]> git.proxmox.com Git - mirror_lxcfs.git/blobdiff - cgmanager.c
use threads when safe
[mirror_lxcfs.git] / cgmanager.c
index ac6225e4d836c201b54fbc4bc9c0f32da8564c2f..c0059992eaca235603b7e8341662839de0d4b9f4 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/param.h>
 #include <sys/inotify.h>
 #include <sys/mount.h>
+#include <sys/wait.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <stdbool.h>
@@ -51,8 +52,8 @@
 
 #include "cgmanager.h"
 
-static NihDBusProxy *cgroup_manager = NULL;
-static int32_t api_version;
+static __thread NihDBusProxy *cgroup_manager = NULL;
+static __thread int32_t api_version;
 
 static void cgm_dbus_disconnect(void)
 {
@@ -74,7 +75,7 @@ static bool cgm_dbus_connect(void)
 
        connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error);
        if (!connection) {
-               fprintf(stderr, "Failed opening dbus connection: %s: %s",
+               fprintf(stderr, "Failed opening dbus connection: %s: %s\n",
                                dbus_error.name, dbus_error.message);
                dbus_error_free(&dbus_error);
                return false;
@@ -88,7 +89,7 @@ static bool cgm_dbus_connect(void)
        if (!cgroup_manager) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "Error opening cgmanager proxy: %s", nerr->message);
+               fprintf(stderr, "Error opening cgmanager proxy: %s\n", nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return false;
@@ -98,7 +99,7 @@ static bool cgm_dbus_connect(void)
        if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "Error cgroup manager api version: %s", nerr->message);
+               fprintf(stderr, "Error cgroup manager api version: %s\n", nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return false;
@@ -115,7 +116,7 @@ bool cgm_get_controllers(char ***contrls)
        if ( cgmanager_list_controllers_sync(NULL, cgroup_manager, contrls) != 0 ) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "call to list_controllers failed: %s", nerr->message);
+               fprintf(stderr, "call to list_controllers failed: %s\n", nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return false;
@@ -135,7 +136,7 @@ bool cgm_list_keys(const char *controller, const char *cgroup, struct cgm_keys *
                                (CgmanagerListKeysOutputElement ***)keys) != 0 ) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "call to list_keys failed: %s", nerr->message);
+               fprintf(stderr, "call to list_keys (%s:%s) failed: %s\n", controller, cgroup, nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return false;
@@ -154,7 +155,7 @@ bool cgm_list_children(const char *controller, const char *cgroup, char ***list)
        if ( cgmanager_list_children_sync(NULL, cgroup_manager, controller, cgroup, list) != 0 ) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "call to list_children failed: %s", nerr->message);
+               fprintf(stderr, "call to list_children (%s:%s) failed: %s\n", controller, cgroup, nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return false;
@@ -175,7 +176,7 @@ char *cgm_get_pid_cgroup(pid_t pid, const char *controller)
        if ( cgmanager_get_pid_cgroup_sync(NULL, cgroup_manager, controller, pid, &output) != 0 ) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "call to get_pid_cgroup failed: %s", nerr->message);
+               fprintf(stderr, "call to get_pid_cgroup (%s) failed: %s\n", controller, nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return NULL;
@@ -194,7 +195,185 @@ bool cgm_escape_cgroup(void)
        if ( cgmanager_move_pid_abs_sync(NULL, cgroup_manager, "all", "/", (int32_t) getpid()) != 0 ) {
                NihError *nerr;
                nerr = nih_error_get();
-               fprintf(stderr, "call to move_pid_abs failed: %s", nerr->message);
+               fprintf(stderr, "call to move_pid_abs (all:/) failed: %s\n", nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               return false;
+       }
+
+       cgm_dbus_disconnect();
+       return true;
+}
+
+bool cgm_move_pid(const char *controller, const char *cgroup, pid_t pid)
+{
+       if (!cgm_dbus_connect()) {
+               return false;
+       }
+
+       if ( cgmanager_move_pid_sync(NULL, cgroup_manager, controller, cgroup,
+                               (int32_t) pid) != 0 ) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to move_pid (%s:%s, %d) failed: %s\n", controller, cgroup, pid, nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               return false;
+       }
+
+       cgm_dbus_disconnect();
+       return true;
+}
+
+bool cgm_get_value(const char *controller, const char *cgroup, const char *file,
+               char **value)
+{
+       if (!cgm_dbus_connect()) {
+               return false;
+       }
+
+       if ( cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup,
+                       file, value) != 0 ) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to get_value (%s:%s, %s) failed: %s\n", controller, cgroup, file, nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               return false;
+       }
+
+       cgm_dbus_disconnect();
+       return true;
+}
+
+bool cgm_set_value(const char *controller, const char *cgroup, const char *file,
+               const char *value)
+{
+       if (!cgm_dbus_connect()) {
+               return false;
+       }
+
+       if ( cgmanager_set_value_sync(NULL, cgroup_manager, controller, cgroup,
+                       file, value) != 0 ) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to set_value (%s:%s, %s, %s) failed: %s\n", controller, cgroup, file, value, nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               return false;
+       }
+
+       cgm_dbus_disconnect();
+       return true;
+}
+
+static int wait_for_pid(pid_t pid)
+{
+       int status, ret;
+
+again:
+       ret = waitpid(pid, &status, 0);
+       if (ret == -1) {
+               if (errno == EINTR)
+                       goto again;
+               return -1;
+       }
+       if (ret != pid)
+               goto again;
+       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+               return -1;
+       return 0;
+}
+
+bool cgm_create(const char *controller, const char *cg, uid_t uid, gid_t gid)
+{
+       int32_t e;
+       pid_t pid = fork();
+
+       if (pid) {
+               if (wait_for_pid(pid) != 0)
+                       return false;
+               return true;
+       }
+
+       if (setgroups(0, NULL))
+               exit(1);
+       if (setresgid(gid, gid, gid))
+               exit(1);
+       if (setresuid(uid, uid, uid))
+               exit(1);
+
+       if (!cgm_dbus_connect()) {
+               exit(1);
+       }
+
+       if ( cgmanager_create_sync(NULL, cgroup_manager, controller, cg, &e) != 0) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to create failed (%s:%s): %s\n", controller, cg, nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               exit(1);
+       }
+
+       cgm_dbus_disconnect();
+       exit(0);
+}
+
+bool cgm_chown_file(const char *controller, const char *cg, uid_t uid, gid_t gid)
+{
+       if (!cgm_dbus_connect()) {
+               return false;
+       }
+
+       if ( cgmanager_chown_sync(NULL, cgroup_manager, controller, cg, uid, gid) != 0) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to chown (%s:%s, %d, %d) failed: %s\n", controller, cg, uid, gid, nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               return false;
+       }
+
+       cgm_dbus_disconnect();
+       return true;
+}
+
+bool cgm_chmod_file(const char *controller, const char *file, mode_t mode)
+{
+       if (!cgm_dbus_connect()) {
+               return false;
+       }
+
+       if ( cgmanager_chmod_sync(NULL, cgroup_manager, controller, file, "", mode) != 0) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to chmod (%s:%s, %d) failed: %s\n", controller, file, mode, nerr->message);
+               nih_free(nerr);
+               cgm_dbus_disconnect();
+               return false;
+       }
+
+       cgm_dbus_disconnect();
+       return true;
+}
+
+bool cgm_remove(const char *controller, const char *cg)
+{
+       /*
+        * tempting to make remove be recursive, but this is a filesystem,
+        * so best to opt for least surprise
+        */
+       int32_t r = 0, e;
+
+       if (!cgm_dbus_connect()) {
+               return false;
+       }
+
+       if ( cgmanager_remove_sync(NULL, cgroup_manager, controller, cg, r, &e) != 0) {
+               NihError *nerr;
+               nerr = nih_error_get();
+               fprintf(stderr, "call to remove (%s:%s) failed: %s\n", controller, cg, nerr->message);
                nih_free(nerr);
                cgm_dbus_disconnect();
                return false;