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

Reply via email to