From: Daniel Wagner <[email protected]>
---
src/cgroup.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/connman.h | 3 +
2 files changed, 201 insertions(+)
diff --git a/src/cgroup.c b/src/cgroup.c
index febb895..cd4128b 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -28,12 +28,204 @@
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <connman/inet.h>
#include "connman.h"
#define CGROUP_PATH "/sys/fs/cgroup/connman"
static connman_bool_t enabled;
+static GHashTable *if_hash = NULL;
+
+struct cgroup_info {
+ char *path;
+};
+
+static int write_line(const char *path, const char *line)
+{
+ ssize_t len;
+ int fd;
+ int err;
+
+ fd = open(path, O_WRONLY | O_CLOEXEC);
+ if (fd < 0) {
+ err = -errno;
+ connman_error("Failed to open %s: %s", path, strerror(errno));
+ return err;
+ }
+
+ len = write(fd, line, strlen(line));
+ if (len < 0) {
+ err = -errno;
+ connman_error("Failed to write line '%s' to %s: %s",
+ line, path, strerror(errno));
+ goto out;
+ }
+
+ close(fd);
+
+out:
+ return err;
+}
+
+static int cgroup_attach(const char *path, pid_t pid)
+{
+ char *line, *tasks;
+ int err;
+
+ DBG("path %p pid %d", path, pid);
+
+ line = g_strdup_printf("%lu\n", (unsigned long) pid);
+ tasks = g_strdup_printf("%s/tasks", path);
+
+ err = write_line(tasks, line);
+
+ g_free(line);
+ g_free(tasks);
+
+ return err;
+}
+
+static int read_one_pid(const char *path, pid_t *pid)
+{
+ unsigned long ul;
+ char *tasks;
+ FILE *file;
+ int err;
+
+ tasks = g_strdup_printf("%s/tasks", path);
+ file = fopen(tasks, "r");
+ if (file == NULL) {
+ g_free(tasks);
+ return -errno;
+ }
+
+ err = fscanf(file, "%lu", &ul);
+ fclose(file);
+ g_free(tasks);
+
+ if (err < 0) {
+ if (errno == 0)
+ return -ENOENT;
+ return -errno;
+ }
+
+ if (err != 1)
+ return -EIO;
+
+ *pid = ul;
+
+ return 0;
+}
+
+static void cleanup_cgroup(gpointer user_data)
+{
+ struct cgroup_info *info = user_data;
+ pid_t pid;
+
+ DBG("remove %s", info->path);
+
+ while (read_one_pid(info->path, &pid) == 0)
+ cgroup_attach(CGROUP_PATH, pid);
+
+ rmdir(info->path);
+ g_free(info->path);
+ g_free(info);
+}
+
+int __connman_cgroup_add_interface(int index)
+{
+ struct cgroup_info *info;
+ char *interface = NULL;
+ int err;
+
+ DBG("index %d", index);
+
+ info = g_try_new0(struct cgroup_info, 1);
+ if (info == NULL)
+ return -ENOMEM;
+
+ if (g_hash_table_lookup(if_hash, GINT_TO_POINTER(index)) != NULL) {
+ connman_error("Trying to add an already registered interface");
+ err = -EALREADY;
+ goto err;
+ }
+
+ interface = connman_inet_ifname(index);
+ if (interface == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ info->path = g_strdup_printf("%s/%s", CGROUP_PATH, interface);
+ g_free(interface);
+ if (info->path == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ err = mkdir(info->path, S_IRWXU | S_IRGRP | S_IXGRP |
+ S_IROTH | S_IXOTH);
+ if (err < 0) {
+ err = -errno;
+ connman_error("Could not create %s: %s", info->path,
+ strerror(errno));
+ goto err;
+ }
+
+ g_hash_table_replace(if_hash, GINT_TO_POINTER(index), info);
+
+ return 0;
+
+err:
+ g_free(info->path);
+ g_free(info);
+
+ return err;
+}
+
+int __connman_cgroup_rem_interface(int index)
+{
+ DBG("index %d", index);
+
+ if (g_hash_table_lookup(if_hash, GINT_TO_POINTER(index)) == NULL) {
+ connman_error("Trying to remove an unkonwn interface");
+ return -EINVAL;
+ }
+
+ g_hash_table_remove(if_hash, GINT_TO_POINTER(index));
+
+ return 0;
+}
+
+int __connman_cgroup_set_route(int index, int pid)
+{
+ struct cgroup_info *info;
+ int err;
+
+ DBG("index %d pid %d", index, pid);
+
+ if (index < 0)
+ return cgroup_attach(CGROUP_PATH, pid);
+
+ info = g_hash_table_lookup(if_hash, GINT_TO_POINTER(index));
+ if (info == NULL) {
+ connman_error("Inconsitent state. No cgroup for index %d",
+ index);
+ return -EINVAL;
+ }
+
+ err = cgroup_attach(info->path, pid);
+ if (err < 0) {
+ DBG("Could not attach pid %s to %d", info->path, pid);
+ return err;
+ }
+
+ return 0;
+}
static int check_mount_point(const char *path)
{
@@ -114,6 +306,9 @@ int __connman_cgroup_init(void)
return err;
}
+ if_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, cleanup_cgroup);
+
enabled = TRUE;
return 0;
@@ -126,5 +321,8 @@ void __connman_cgroup_cleanup(void)
if (enabled == FALSE)
return;
+ g_hash_table_destroy(if_hash);
+ if_hash = NULL;
+
cgroup_cleanup();
}
diff --git a/src/connman.h b/src/connman.h
index 7eba662..90c85ac 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -845,3 +845,6 @@ void __connman_nat_disable(const char *name);
int __connman_cgroup_init(void);
void __connman_cgroup_cleanup(void);
+int __connman_cgroup_add_interface(int index);
+int __connman_cgroup_rem_interface(int index);
+int __connman_cgroup_set_route(int index, int pid);
--
1.7.12.rc1.16.g05a20c8
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman