From: Lennart Poettering Date: Fri, 18 Jan 2013 00:44:41 +0000 (+0100) Subject: systemctl: add new "get-cgroup-attr" to query current cgroup attribute value X-Git-Tag: v198~486 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=d2a30975827b3447ca0fd5a2c06ec1ff15ce7f0f systemctl: add new "get-cgroup-attr" to query current cgroup attribute value Also adds a pair of bus calls for this to the daemon. --- diff --git a/src/core/cgroup-attr.c b/src/core/cgroup-attr.c index cedf37de5..aed4e99d8 100644 --- a/src/core/cgroup-attr.c +++ b/src/core/cgroup-attr.c @@ -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; } diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 1d785a234..b7829572f 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -102,15 +102,10 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ + " \n" \ " \n" \ - " \n" \ - " " \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -122,6 +117,16 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " " \ + " \n" \ " \n" \ " \n" \ " \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; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index c7bf04376..d2f8ebf76 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -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; diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index c7d5863a9..c8903f8e5 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -127,13 +127,9 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -142,6 +138,14 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \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); diff --git a/src/shared/util.c b/src/shared/util.c index d5de59fce..f75a81c60 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index cac70673c..f3d661d2b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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 },