X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fdbus-unit.c;h=b7391b5506d2945eed08e3ae1315d63311e15271;hp=d1de46afd4e2069e358fe79853932ed58684d37a;hb=4ec9a8a48d61266638524a7cbc2c4763a9c92e2c;hpb=71645acac27da55d510f2e4d61cc61b4e5b93035 diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index d1de46afd..b7391b550 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -30,6 +30,7 @@ #include "cgroup-util.h" #include "strv.h" #include "path-util.h" +#include "fileio.h" const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; @@ -80,6 +81,25 @@ static int bus_unit_append_following(DBusMessageIter *i, const char *property, v return 0; } +static int bus_unit_append_slice(DBusMessageIter *i, const char *property, void *data) { + Unit *u = data; + const char *d; + + assert(i); + assert(property); + assert(u); + + if (UNIT_DEREF(u->slice)) + d = UNIT_DEREF(u->slice)->id; + else + d = ""; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) + return -ENOMEM; + + return 0; +} + static int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data) { Unit *u; Iterator j; @@ -313,7 +333,7 @@ static int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, voi return -ENOMEM; LIST_FOREACH(by_unit, cgb, u->cgroup_bondings) { - char _cleanup_free_ *t = NULL; + _cleanup_free_ char *t = NULL; bool success; t = cgroup_bonding_to_string(cgb); @@ -340,11 +360,11 @@ static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property return -ENOMEM; LIST_FOREACH(by_unit, a, u->cgroup_attributes) { - char _cleanup_free_ *v = NULL; + _cleanup_free_ char *v = NULL; bool success; - if (a->map_callback) - a->map_callback(a->controller, a->name, a->value, &v); + if (a->semantics && a->semantics->map_write) + a->semantics->map_write(a->semantics, a->value, &v); success = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) && @@ -471,7 +491,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (!reply) goto oom; - } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroups")) { + } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroup")) { DBusMessageIter iter; SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); @@ -487,7 +507,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (!reply) goto oom; - } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroups")) { + } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroup")) { DBusMessageIter iter; SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); @@ -495,14 +515,14 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (!dbus_message_iter_init(message, &iter)) goto oom; - r = bus_unit_cgroup_set(u, &iter); + r = bus_unit_cgroup_unset(u, &iter); if (r < 0) return bus_send_error_reply(connection, message, NULL, r); reply = dbus_message_new_method_return(message); if (!reply) goto oom; - } else if (streq_ptr(dbus_message_get_member(message), "GetControlGroupAttributes")) { + } else if (streq_ptr(dbus_message_get_member(message), "GetControlGroupAttribute")) { DBusMessageIter iter; _cleanup_strv_free_ char **list = NULL; @@ -523,7 +543,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (bus_append_strv_iter(&iter, list) < 0) goto oom; - } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroupAttributes")) { + } else if (streq_ptr(dbus_message_get_member(message), "SetControlGroupAttribute")) { DBusMessageIter iter; SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); @@ -539,7 +559,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if (!reply) goto oom; - } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroupAttributes")) { + } else if (streq_ptr(dbus_message_get_member(message), "UnsetControlGroupAttribute")) { DBusMessageIter iter; SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); @@ -581,7 +601,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn } if (reply) - if (!dbus_connection_send(connection, reply, NULL)) + if (!bus_maybe_send_reply(connection, message, reply)) goto oom; return DBUS_HANDLER_RESULT_HANDLED; @@ -672,7 +692,7 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB free(introspection); - if (!dbus_connection_send(connection, reply, NULL)) + if (!bus_maybe_send_reply(connection, message, reply)) goto oom; return DBUS_HANDLER_RESULT_HANDLED; @@ -885,7 +905,7 @@ DBusHandlerResult bus_unit_queue_job( DBUS_TYPE_INVALID)) goto oom; - if (!dbus_connection_send(connection, reply, NULL)) + if (!bus_maybe_send_reply(connection, message, reply)) goto oom; return DBUS_HANDLER_RESULT_HANDLED; @@ -896,17 +916,17 @@ oom: return DBUS_HANDLER_RESULT_NEED_MEMORY; } -static int next_and_parse_mode(DBusMessageIter *iter, bool *runtime) { +static int parse_mode(DBusMessageIter *iter, bool *runtime, bool next) { const char *mode; + int r; assert(iter); assert(runtime); - dbus_message_iter_next(iter); - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) - return -EINVAL; + r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &mode, next); + if (r < 0) + return r; - dbus_message_iter_get_basic(iter, &mode); if (streq(mode, "runtime")) *runtime = true; else if (streq(mode, "persistent")) @@ -918,10 +938,11 @@ static int next_and_parse_mode(DBusMessageIter *iter, bool *runtime) { } int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) { - int r; - _cleanup_strv_free_ char **a = NULL; - char **name; + _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL, *contents = NULL; + const char *name; + CGroupBonding *b; bool runtime; + int r; assert(u); assert(iter); @@ -929,60 +950,74 @@ int bus_unit_cgroup_set(Unit *u, DBusMessageIter *iter) { if (!unit_get_exec_context(u)) return -EINVAL; - r = bus_parse_strv_iter(iter, &a); + r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true); if (r < 0) return r; - r = next_and_parse_mode(iter, &runtime); + r = parse_mode(iter, &runtime, false); if (r < 0) return r; - STRV_FOREACH(name, a) { - _cleanup_free_ char *controller = NULL, *old_path = NULL, *new_path = NULL, *contents = NULL; - CGroupBonding *b; - - r = cg_split_spec(*name, &controller, &new_path); - if (r < 0) - return r; + r = cg_split_spec(name, &controller, &new_path); + if (r < 0) + return r; - b = cgroup_bonding_find_list(u->cgroup_bondings, controller); - if (b) { - old_path = strdup(b->path); - if (!old_path) - return -ENOMEM; - } + if (!new_path) { + new_path = unit_default_cgroup_path(u); + if (!new_path) + return -ENOMEM; + } - r = unit_add_cgroup_from_text(u, *name, true, &b); - if (r < 0) - return r; + if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + return -EINVAL; - if (r > 0) { - /* Try to move things to the new place, and clean up the old place */ - cgroup_bonding_realize(b); - cgroup_bonding_migrate(b, u->cgroup_bondings); + b = cgroup_bonding_find_list(u->cgroup_bondings, controller); + if (b) { + if (streq(b->path, new_path)) + return 0; - if (old_path) - cg_trim(controller, old_path, true); - } + if (b->essential) + return -EINVAL; - contents = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n" - "ControlGroup=", *name, "\n", NULL); - if (!contents) + old_path = strdup(b->path); + if (!old_path) return -ENOMEM; + } - r = unit_write_drop_in(u, runtime, *name, contents); - if (r < 0) - return r; + r = unit_add_cgroup_from_text(u, name, true, &b); + if (r < 0) + return r; + if (r > 0) { + CGroupAttribute *a; + + /* Try to move things to the new place, and clean up the old place */ + cgroup_bonding_realize(b); + cgroup_bonding_migrate(b, u->cgroup_bondings); + + if (old_path) + cg_trim(controller, old_path, true); + + /* Apply the attributes to the new group */ + LIST_FOREACH(by_unit, a, u->cgroup_attributes) + if (streq(a->controller, controller)) + cgroup_attribute_apply(a, b); } - return 0; + contents = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n" + "ControlGroup=", name, "\n", NULL); + if (!contents) + return -ENOMEM; + + return unit_write_drop_in(u, runtime, controller, contents); } int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) { - _cleanup_strv_free_ char **a = NULL; - char **name; - int r; + _cleanup_free_ char *controller = NULL, *path = NULL, *target = NULL; + const char *name; + CGroupAttribute *a, *n; + CGroupBonding *b; bool runtime; + int r; assert(u); assert(iter); @@ -990,50 +1025,57 @@ int bus_unit_cgroup_unset(Unit *u, DBusMessageIter *iter) { if (!unit_get_exec_context(u)) return -EINVAL; - r = bus_parse_strv_iter(iter, &a); + r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true); if (r < 0) return r; - r = next_and_parse_mode(iter, &runtime); + r = parse_mode(iter, &runtime, false); if (r < 0) return r; - STRV_FOREACH(name, a) { - _cleanup_free_ char *controller = NULL, *path = NULL, *target = NULL; - CGroupBonding *b; + r = cg_split_spec(name, &controller, &path); + if (r < 0) + return r; - r = cg_split_spec(*name, &controller, &path); - if (r < 0) - return r; + if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + return -EINVAL; - if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER)) - return -EINVAL; + b = cgroup_bonding_find_list(u->cgroup_bondings, controller); + if (!b) + return -ENOENT; - unit_remove_drop_in(u, runtime, *name); + if (path && !path_equal(path, b->path)) + return -ENOENT; - b = cgroup_bonding_find_list(u->cgroup_bondings, controller); - if (!b) - continue; + if (b->essential) + return -EINVAL; - if (path && !path_equal(path, b->path)) - continue; + unit_remove_drop_in(u, runtime, controller); - if (b->essential) - return -EINVAL; + /* Try to migrate the old group away */ + if (cg_pid_get_path(controller, 0, &target) >= 0) + cgroup_bonding_migrate_to(u->cgroup_bondings, target, false); + + cgroup_bonding_free(b, true); - /* Try to migrate the old group away */ - if (cg_get_by_pid(controller, 0, &target) >= 0) - cgroup_bonding_migrate_to(u->cgroup_bondings, target, false); + /* Drop all attributes of this controller */ + LIST_FOREACH_SAFE(by_unit, a, n, u->cgroup_attributes) { + if (!streq(a->controller, controller)) + continue; - cgroup_bonding_free(b, true); + unit_remove_drop_in(u, runtime, a->name); + cgroup_attribute_free(a); } return 0; } int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_result) { - _cleanup_strv_free_ char **l = NULL, **result = NULL; - char **name; + _cleanup_free_ char *controller = NULL; + CGroupAttribute *a; + CGroupBonding *b; + const char *name; + char **l = NULL; int r; assert(u); @@ -1043,63 +1085,99 @@ int bus_unit_cgroup_attribute_get(Unit *u, DBusMessageIter *iter, char ***_resul if (!unit_get_exec_context(u)) return -EINVAL; - r = bus_parse_strv_iter(iter, &l); + r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, false); if (r < 0) return r; - STRV_FOREACH(name, l) { - _cleanup_free_ char *controller = NULL; - CGroupAttribute *a; - CGroupBonding *b; + r = cg_controller_from_attr(name, &controller); + if (r < 0) + return r; - r = cg_controller_from_attr(*name, &controller); + /* 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; - /* 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) { + /* Split on new lines */ + l = strv_split_newlines(v); + if (!l) + return -ENOMEM; - r = read_full_file(p, &v, NULL); - if (r >= 0) { - r = strv_extend(&result, v); - if (r < 0) - return r; + *_result = l; + return 0; - 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; + /* If that didn't work, read our cached value */ + LIST_FOREACH(by_unit, a, u->cgroup_attributes) { + if (!cgroup_attribute_matches(a, controller, name)) continue; - } - return -ENOENT; + r = strv_extend(&l, a->value); + if (r < 0) { + strv_free(l); + return r; + } } - *_result = result; - result = NULL; + if (!l) + return -ENOENT; + *_result = l; return 0; } +static int update_attribute_drop_in(Unit *u, bool runtime, const char *name) { + _cleanup_free_ char *buf = NULL; + CGroupAttribute *a; + + assert(u); + assert(name); + + LIST_FOREACH(by_unit, a, u->cgroup_attributes) { + if (!cgroup_attribute_matches(a, NULL, name)) + continue; + + if (!buf) { + buf = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n" + "ControlGroupAttribute=", a->name, " ", a->value, "\n", NULL); + + if (!buf) + return -ENOMEM; + } else { + char *b; + + b = strjoin(buf, + "ControlGroupAttribute=", a->name, " ", a->value, "\n", NULL); + + if (!b) + return -ENOMEM; + + free(buf); + buf = b; + } + } + + if (buf) + return unit_write_drop_in(u, runtime, name, buf); + else + return unit_remove_drop_in(u, runtime, name); +} + int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) { _cleanup_strv_free_ char **l = NULL; int r; bool runtime = false; - char **name, **value; + char **value; + const char *name; assert(u); assert(iter); @@ -1107,19 +1185,34 @@ int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) { if (!unit_get_exec_context(u)) return -EINVAL; - r = bus_parse_strv_pairs_iter(iter, &l); + r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true); + if (r < 0) + return r; + + r = bus_parse_strv_iter(iter, &l); if (r < 0) return r; - r = next_and_parse_mode(iter, &runtime); + if (!dbus_message_iter_next(iter)) + return -EINVAL; + + r = parse_mode(iter, &runtime, false); if (r < 0) return r; - STRV_FOREACH_PAIR(name, value, l) { - _cleanup_free_ char *contents = NULL; + STRV_FOREACH(value, l) { + _cleanup_free_ char *v = NULL; CGroupAttribute *a; + const CGroupSemantics *s; - r = unit_add_cgroup_attribute(u, NULL, *name, *value, NULL, &a); + r = cgroup_semantics_find(NULL, name, *value, &v, &s); + if (r < 0) + return r; + + if (s && !s->multiple && l[1]) + return -EINVAL; + + r = unit_add_cgroup_attribute(u, s, NULL, name, v ? v : *value, &a); if (r < 0) return r; @@ -1143,22 +1236,17 @@ int bus_unit_cgroup_attribute_set(Unit *u, DBusMessageIter *iter) { cgroup_attribute_apply(a, u->cgroup_bondings); } - contents = strjoin("[", UNIT_VTABLE(u)->exec_section, "]\n" - "ControlGroupAttribute=", *name, " ", *value, "\n", NULL); - if (!contents) - return -ENOMEM; - - r = unit_write_drop_in(u, runtime, *name, contents); - if (r < 0) - return r; } + r = update_attribute_drop_in(u, runtime, name); + if (r < 0) + return r; + return 0; } int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) { - _cleanup_strv_free_ char **l = NULL; - char **name; + const char *name; bool runtime; int r; @@ -1168,23 +1256,16 @@ int bus_unit_cgroup_attribute_unset(Unit *u, DBusMessageIter *iter) { if (!unit_get_exec_context(u)) return -EINVAL; - r = bus_parse_strv_iter(iter, &l); + r = bus_iter_get_basic_and_next(iter, DBUS_TYPE_STRING, &name, true); if (r < 0) return r; - r = next_and_parse_mode(iter, &runtime); + r = parse_mode(iter, &runtime, false); if (r < 0) return r; - STRV_FOREACH(name, l) { - CGroupAttribute *a; - - a = cgroup_attribute_find_list(u->cgroup_attributes, NULL, *name); - if (a) - cgroup_attribute_free(a); - - unit_remove_drop_in(u, runtime, *name); - } + cgroup_attribute_free_some(u->cgroup_attributes, NULL, name); + update_attribute_drop_in(u, runtime, name); return 0; } @@ -1193,6 +1274,7 @@ const BusProperty bus_unit_properties[] = { { "Id", bus_property_append_string, "s", offsetof(Unit, id), true }, { "Names", bus_unit_append_names, "as", 0 }, { "Following", bus_unit_append_following, "s", 0 }, + { "Slice", bus_unit_append_slice, "s", 0 }, { "Requires", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES]), true }, { "RequiresOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), true }, { "Requisite", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE]), true }, @@ -1222,6 +1304,7 @@ const BusProperty bus_unit_properties[] = { { "SubState", bus_unit_append_sub_state, "s", 0 }, { "FragmentPath", bus_property_append_string, "s", offsetof(Unit, fragment_path), true }, { "SourcePath", bus_property_append_string, "s", offsetof(Unit, source_path), true }, + { "DropInPaths", bus_property_append_strv, "as", offsetof(Unit, dropin_paths), true }, { "UnitFileState", bus_unit_append_file_state, "s", 0 }, { "InactiveExitTimestamp",bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.realtime) }, { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic) },