chiark / gitweb /
systemctl: add new "get-cgroup-attr" to query current cgroup attribute value
authorLennart Poettering <lennart@poettering.net>
Fri, 18 Jan 2013 00:44:41 +0000 (01:44 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 18 Jan 2013 00:44:41 +0000 (01:44 +0100)
Also adds a pair of bus calls for this to the daemon.

src/core/cgroup-attr.c
src/core/dbus-manager.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/shared/util.c
src/systemctl/systemctl.c

index cedf37d..aed4e99 100644 (file)
@@ -25,8 +25,7 @@
 
 int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) {
         int r;
-        char *path = NULL;
-        char *v = NULL;
+        _cleanup_free_ char *path = NULL, *v = NULL;
 
         assert(a);
 
@@ -41,18 +40,13 @@ int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) {
         }
 
         r = cg_get_path(a->controller, b->path, a->name, &path);
-        if (r < 0) {
-                free(v);
+        if (r < 0)
                 return r;
-        }
 
         r = write_one_line_file(path, v ? v : a->value);
         if (r < 0)
                 log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r));
 
-        free(path);
-        free(v);
-
         return r;
 }
 
index 1d785a2..b782957 100644 (file)
         "  <method name=\"ResetFailedUnit\">\n"                         \
         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
         "  </method>\n"                                                 \
-        "  <method name=\"SetUnitControlGroups\">\n"                    \
-        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnsetUnitControlGroups\">\n"                  \
+        "  <method name=\"GetUnitControlGroupAttributes\">\n"           \
         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
-        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>"         \
+        "   <arg name=\"attributes\" type=\"as\" direction=\"in\"/>\n"  \
+        "   <arg name=\"values\" type=\"as\" direction=\"out\"/>\n"      \
         "  </method>\n"                                                 \
         "  <method name=\"SetUnitControlGroupAttributes\">\n"           \
         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
         "   <arg name=\"attributes\" type=\"a(ss)\" direction=\"in\"/>\n" \
         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
         "  </method>\n"                                                 \
+        "  <method name=\"SetUnitControlGroups\">\n"                    \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"UnsetUnitControlGroups\">\n"                  \
+        "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
+        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>"         \
+        "  </method>\n"                                                 \
         "  <method name=\"GetJob\">\n"                                  \
         "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
@@ -979,6 +984,38 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                 if (!reply)
                         goto oom;
 
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitControlGroupAttributes")) {
+                const char *name;
+                Unit *u;
+                DBusMessageIter iter;
+                _cleanup_strv_free_ char **list = NULL;
+
+                if (!dbus_message_iter_init(message, &iter))
+                        goto oom;
+
+                r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, NULL, r);
+
+                u = manager_get_unit(m, name);
+                if (!u) {
+                        dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
+                        return bus_send_error_reply(connection, message, &error, -ENOENT);
+                }
+
+                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
+                r = bus_unit_cgroup_attribute_get(u, &iter, &list);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, NULL, r);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+                if (bus_append_strv_iter(&iter, list) < 0)
+                        goto oom;
+
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
                 DBusMessageIter iter, sub;
                 Iterator i;
index c7bf043..d2f8ebf 100644 (file)
@@ -502,6 +502,27 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
                 reply = dbus_message_new_method_return(message);
                 if (!reply)
                         goto oom;
+        } else if (streq_ptr(dbus_message_get_member(message), "GetControlGroupAttributes")) {
+                DBusMessageIter iter;
+                _cleanup_strv_free_ char **list = NULL;
+
+                SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
+
+                if (!dbus_message_iter_init(message, &iter))
+                        goto oom;
+
+                r = bus_unit_cgroup_attribute_get(u, &iter, &list);
+                if (r < 0)
+                        return bus_send_error_reply(connection, message, NULL, r);
+
+                reply = dbus_message_new_method_return(message);
+                if (!reply)
+                        goto oom;
+
+                dbus_message_iter_init_append(reply, &iter);
+                if (bus_append_strv_iter(&iter, list) < 0)
+                        goto oom;
+
         } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroupAttributes")) {
                 DBusMessageIter iter;
 
@@ -965,6 +986,74 @@ int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) {
         return 0;
 }
 
+int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_result) {
+        _cleanup_strv_free_ char **l = NULL, **result = NULL;
+        char **name;
+        int r;
+
+        assert(u);
+        assert(iter);
+        assert(_result);
+
+        if (!unit_get_exec_context(u))
+                return -EINVAL;
+
+        r = bus_parse_strv_iter(iter, &l);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(name, l) {
+                _cleanup_free_ char *controller = NULL;
+                const char *dot;
+                CGroupAttribute *a;
+                CGroupBonding *b;
+
+                dot = strchr(*name, '.');
+                if (dot) {
+                        controller = strndup(*name, dot - *name);
+                        if (!controller)
+                                return -ENOMEM;
+                }
+
+                /* First attempt, read the value from the kernel */
+                b = cgroup_bonding_find_list(u->cgroup_bondings, controller);
+                if (b) {
+                        _cleanup_free_ char *p = NULL, *v = NULL;
+
+                        r = cg_get_path(b->controller, b->path, *name, &p);
+                        if (r < 0)
+                                return r;
+
+                        r = read_full_file(p, &v, NULL);
+                        if (r >= 0) {
+                                r = strv_extend(&result, v);
+                                if (r < 0)
+                                        return r;
+
+                                continue;
+                        } else if (r != -ENOENT)
+                                return r;
+                }
+
+                /* If that didn't work, read our cached value */
+                a = cgroup_attribute_find_list(u->cgroup_attributes, NULL, *name);
+                if (a) {
+                        r = strv_extend(&result, a->value);
+                        if (r < 0)
+                                return r;
+
+                        continue;
+                }
+
+                return -ENOENT;
+        }
+
+        *_result = result;
+        result = NULL;
+
+        return 0;
+}
+
 int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) {
         DBusMessageIter sub, sub2;
         int r;
index c7d5863..c8903f8 100644 (file)
         "  <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"ControlGroupAttributes\" type=\"a(sss)\" access=\"read\"/>\n" \
-        "  <method name=\"SetControlGroups\">\n"                        \
-        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
-        "  </method>\n"                                                 \
-        "  <method name=\"UnsetControlGroups\">\n"                      \
-        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
-        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "  <method name=\"GetControlGroupAttributes\">\n"               \
+        "   <arg name=\"attributes\" type=\"as\" direction=\"in\"/>\n"  \
+        "   <arg name=\"values\" type=\"as\" direction=\"out\"/>\n"     \
         "  </method>\n"                                                 \
         "  <method name=\"SetControlGroupAttributes\">\n"               \
         "   <arg name=\"attributes\" type=\"a(ss)\" direction=\"in\"/>\n" \
         "  <method name=\"UnsetControlGroupAttributes\">\n"             \
         "   <arg name=\"attributes\" type=\"as\" direction=\"in\"/>\n"  \
         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"SetControlGroups\">\n"                        \
+        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
+        "  </method>\n"                                                 \
+        "  <method name=\"UnsetControlGroups\">\n"                      \
+        "   <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n"      \
+        "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
         "  </method>\n"
 
 #define BUS_UNIT_INTERFACES_LIST                \
@@ -164,6 +168,7 @@ DBusHandlerResult bus_unit_queue_job(
 
 int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter);
 int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter);
+int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_result);
 int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter);
 int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter);
 
index d5de59f..f75a81c 100644 (file)
@@ -641,6 +641,9 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
         _cleanup_free_ char *buf = NULL;
         struct stat st;
 
+        assert(fn);
+        assert(contents);
+
         f = fopen(fn, "re");
         if (!f)
                 return -errno;
index cac7067..f3d661d 100644 (file)
@@ -2273,6 +2273,64 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
         return 0;
 }
 
+static int get_cgroup_attr(DBusConnection *bus, char **args) {
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        DBusMessageIter iter;
+        int r;
+        _cleanup_free_ char *n = NULL;
+        _cleanup_strv_free_ char **list = NULL;
+        char **a;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        n = unit_name_mangle(args[1]);
+        if (!n)
+                return log_oom();
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "GetUnitControlGroupAttributes");
+        if (!m)
+                return log_oom();
+
+        dbus_message_iter_init_append(m, &iter);
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
+                return log_oom();
+
+        r = bus_append_strv_iter(&iter, args + 2);
+        if (r < 0)
+                return log_oom();
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                dbus_error_free(&error);
+                return -EIO;
+        }
+
+        dbus_message_iter_init(reply, &iter);
+        r = bus_parse_strv_iter(&iter, &list);
+        if (r < 0) {
+                log_error("Failed to parse value list.");
+                return r;
+        }
+
+        STRV_FOREACH(a, list) {
+                if (endswith(*a, "\n"))
+                        fputs(*a, stdout);
+                else
+                        puts(*a);
+        }
+
+        return 0;
+}
+
 typedef struct ExecStatusInfo {
         char *name;
 
@@ -4276,12 +4334,14 @@ static int systemctl_help(void) {
                "  help [NAME...|PID...]           Show manual for one or more units\n"
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
                "                                  units\n"
-               "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
-               "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
+               "  get-cgroup-attr [NAME] [ATTR] ...\n"
+               "                                  Get control group attrubute\n"
                "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
                "                                  Set control group attribute\n"
                "  unset-cgroup-attr [NAME] [ATTR...]\n"
                "                                  Unset control group attribute\n"
+               "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
+               "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-dependencies [NAME]        Recursively show units which are required\n"
                "                                  or wanted by this unit\n\n"
@@ -5261,6 +5321,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "isolate",               EQUAL, 2, start_unit        },
                 { "set-cgroup",            MORE,  2, set_cgroup        },
                 { "unset-cgroup",          MORE,  2, set_cgroup        },
+                { "get-cgroup-attr",       MORE,  2, get_cgroup_attr   },
                 { "set-cgroup-attr",       MORE,  2, set_cgroup_attr   },
                 { "unset-cgroup-attr",     MORE,  2, set_cgroup        },
                 { "kill",                  MORE,  2, kill_unit         },