X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=0d1be198629e75dc46b68fe21049ae22e92f3ca7;hp=075ee4b752781e580e33d3ae58e698e6e9c76d65;hb=cdf3f17bfb20eac2929c8b6a582b988b790f071d;hpb=246aa6dd9dcea84bb945d16ec86e69f869dbb9b4 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 075ee4b75..0d1be1986 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -38,6 +38,7 @@ #include #include +#include #include "log.h" #include "util.h" @@ -237,21 +238,18 @@ static void warn_wall(enum action a) { return; if (arg_wall) { - char *p; + _cleanup_free_ char *p; p = strv_join(arg_wall, " "); if (!p) { - log_error("Failed to join strings."); + log_oom(); return; } if (*p) { utmp_wall(p, NULL); - free(p); return; } - - free(p); } if (!table[a]) @@ -277,19 +275,6 @@ static bool avoid_bus(void) { return false; } -struct unit_info { - const char *id; - const char *description; - const char *load_state; - const char *active_state; - const char *sub_state; - const char *following; - const char *unit_path; - uint32_t job_id; - const char *job_type; - const char *job_path; -}; - static int compare_unit_info(const void *a, const void *b) { const char *d1, *d2; const struct unit_info *u = a, *v = b; @@ -300,7 +285,8 @@ static int compare_unit_info(const void *a, const void *b) { if (d1 && d2) { int r; - if ((r = strcasecmp(d1, d2)) != 0) + r = strcasecmp(d1, d2); + if (r != 0) return r; } @@ -447,15 +433,15 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { } static int list_units(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; - int r; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_free_ struct unit_info *unit_infos = NULL; DBusMessageIter iter, sub, sub2; unsigned c = 0, n_units = 0; - struct unit_info *unit_infos = NULL; + int r; pager_open_if_enabled(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -464,15 +450,14 @@ static int list_units(DBusConnection *bus, char **args) { &reply, NULL, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -480,28 +465,20 @@ static int list_units(DBusConnection *bus, char **args) { while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { struct unit_info *u; - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT); if (c >= n_units) { struct unit_info *w; n_units = MAX(2*c, 16); w = realloc(unit_infos, sizeof(struct unit_info) * n_units); - - if (!w) { - log_error("Failed to allocate unit array."); - r = -ENOMEM; - goto finish; - } + if (!w) + return log_oom(); unit_infos = w; } - u = unit_infos+c; + u = unit_infos + c; dbus_message_iter_recurse(&sub, &sub2); @@ -516,8 +493,7 @@ static int list_units(DBusConnection *bus, char **args) { bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_next(&sub); @@ -529,13 +505,7 @@ static int list_units(DBusConnection *bus, char **args) { output_units_list(unit_infos, c); } -finish: - if (reply) - dbus_message_unref(reply); - - free(unit_infos); - - return r; + return 0; } static int compare_unit_file_list(const void *a, const void *b) { @@ -626,11 +596,11 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { } static int list_unit_files(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; - int r; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_free_ UnitFileList *units = NULL; DBusMessageIter iter, sub, sub2; unsigned c = 0, n_units = 0; - UnitFileList *units = NULL; + int r; pager_open_if_enabled(); @@ -664,7 +634,7 @@ static int list_unit_files(DBusConnection *bus, char **args) { hashmap_free(h); } else { - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -673,15 +643,14 @@ static int list_unit_files(DBusConnection *bus, char **args) { &reply, NULL, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -690,36 +659,27 @@ static int list_unit_files(DBusConnection *bus, char **args) { UnitFileList *u; const char *state; - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT); if (c >= n_units) { UnitFileList *w; n_units = MAX(2*c, 16); w = realloc(units, sizeof(struct UnitFileList) * n_units); - - if (!w) { - log_error("Failed to allocate unit array."); - r = -ENOMEM; - goto finish; - } + if (!w) + return log_oom(); units = w; } - u = units+c; + u = units + c; dbus_message_iter_recurse(&sub, &sub2); if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } u->state = unit_file_state_from_string(state); @@ -734,18 +694,221 @@ static int list_unit_files(DBusConnection *bus, char **args) { output_unit_file_list(units, c); } - r = 0; + return 0; +} +static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) { + int i; + _cleanup_free_ char *n = NULL; + size_t len = 0; + size_t max_len = MAX(columns(),20); + + for (i = level - 1; i >= 0; i--) { + len += 2; + if(len > max_len - 3 && !arg_full) { + printf("%s...\n",max_len % 2 ? "" : " "); + return 0; + } + printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE)); + } + len += 2; + if(len > max_len - 3 && !arg_full) { + printf("%s...\n",max_len % 2 ? "" : " "); + return 0; + } + printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); + + if(arg_full){ + printf("%s\n", name); + return 0; + } + + n = ellipsize(name, max_len-len, 100); + if(!n) + return log_oom(); + + printf("%s\n", n); + return 0; +} + +static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) { + static const char dependencies[] = + "Requires\0" + "RequiresOverridable\0" + "Requisite\0" + "RequisiteOverridable\0" + "Wants\0"; + + _cleanup_free_ char *path; + const char *interface = "org.freedesktop.systemd1.Unit"; + + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + DBusMessageIter iter, sub, sub2, sub3; + + int r = 0; + char **ret = NULL; + + assert(bus); + assert(name); + assert(deps); + + path = unit_dbus_path_from_name(name); + if (path == NULL) { + r = -EINVAL; + goto finish; + } + + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &reply, + NULL, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_INVALID); + if (r < 0) + goto finish; + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&iter, &sub); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char *prop; + + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY); + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&sub2, &sub3); + dbus_message_iter_next(&sub); + + if (!nulstr_contains(dependencies, prop)) + continue; + + if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) { + if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) { + DBusMessageIter sub4; + dbus_message_iter_recurse(&sub3, &sub4); + + while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) { + const char *s; + + assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING); + dbus_message_iter_get_basic(&sub4, &s); + + r = strv_extend(&ret, s); + if (r < 0) { + log_oom(); + goto finish; + } + + dbus_message_iter_next(&sub4); + } + } + } + } finish: - if (reply) - dbus_message_unref(reply); + if (r < 0) + strv_free(ret); + else + *deps = ret; + return r; +} + +static int list_dependencies_compare(const void *_a, const void *_b) { + const char **a = (const char**) _a, **b = (const char**) _b; + if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET) + return 1; + if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET) + return -1; + return strcasecmp(*a, *b); +} - free(units); +static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char **units, unsigned int branches) { + char **deps = NULL; + char **c; + char **u = NULL; + int r = 0; + + u = strv_append(units, name); + if(!u) + return log_oom(); + + r = list_dependencies_get_dependencies(bus, name, &deps); + if (r < 0) + goto finish; + + qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare); + + STRV_FOREACH(c, deps) { + if (strv_contains(u, *c)) { + r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1); + if(r < 0) + goto finish; + continue; + } + + r = list_dependencies_print(*c, level, branches, c[1] == NULL); + if(r < 0) + goto finish; + + if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) { + r = list_dependencies_one(bus, *c, level + 1, u, (branches << 1) | (c[1] == NULL ? 0 : 1)); + if(r < 0) + goto finish; + } + } + r = 0; +finish: + strv_free(deps); + strv_free(u); return r; } +static int list_dependencies(DBusConnection *bus, char **args) { + _cleanup_free_ char *unit = NULL; + const char *u; + + assert(bus); + + if (args[1]) { + unit = unit_name_mangle(args[1]); + if (!unit) + return log_oom(); + u = unit; + } else + u = SPECIAL_DEFAULT_TARGET; + + pager_open_if_enabled(); + + puts(u); + + return list_dependencies_one(bus, u, 0, NULL, 0); +} + static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) { + static const char * const colors[] = { "Requires", "[color=\"black\"]", "RequiresOverridable", "[color=\"black\"]", @@ -804,14 +967,15 @@ static int dot_one_property(const char *name, const char *prop, DBusMessageIter } static int dot_one(DBusConnection *bus, const char *name, const char *path) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; const char *interface = "org.freedesktop.systemd1.Unit"; int r; DBusMessageIter iter, sub, sub2, sub3; + assert(bus); assert(path); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", path, @@ -821,15 +985,14 @@ static int dot_one(DBusConnection *bus, const char *name, const char *path) { NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -837,50 +1000,32 @@ static int dot_one(DBusConnection *bus, const char *name, const char *path) { while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { const char *prop; - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY); dbus_message_iter_recurse(&sub, &sub2); - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) { + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0 || + dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub2, &sub3); - - if (dot_one_property(name, prop, &sub3)) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } + r = dot_one_property(name, prop, &sub3); + if (r < 0) + return r; dbus_message_iter_next(&sub); } -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return 0; } static int dot(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; - int r; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub, sub2; + int r; - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -889,15 +1034,14 @@ static int dot(DBusConnection *bus, char **args) { &reply, NULL, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } printf("digraph systemd {\n"); @@ -908,8 +1052,7 @@ static int dot(DBusConnection *bus, char **args) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub, &sub2); @@ -922,12 +1065,12 @@ static int dot(DBusConnection *bus, char **args) { bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } - if ((r = dot_one(bus, id, unit_path)) < 0) - goto finish; + r = dot_one(bus, id, unit_path); + if (r < 0) + return r; /* printf("\t\"%s\";\n", id); */ dbus_message_iter_next(&sub); @@ -945,24 +1088,18 @@ static int dot(DBusConnection *bus, char **args) { log_notice("-- You probably want to process this output with graphviz' dot tool.\n" "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n"); - r = 0; - -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return 0; } static int list_jobs(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; - int r; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub, sub2; unsigned k = 0; + int r; pager_open_if_enabled(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -971,15 +1108,14 @@ static int list_jobs(DBusConnection *bus, char **args) { &reply, NULL, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -994,8 +1130,7 @@ static int list_jobs(DBusConnection *bus, char **args) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub, &sub2); @@ -1007,8 +1142,7 @@ static int list_jobs(DBusConnection *bus, char **args) { bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } e = arg_full ? NULL : ellipsize(name, 25, 33); @@ -1023,13 +1157,7 @@ static int list_jobs(DBusConnection *bus, char **args) { if (on_tty()) printf("\n%u jobs listed.\n", k); - r = 0; - -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return 0; } static int load_unit(DBusConnection *bus, char **args) { @@ -1042,7 +1170,10 @@ static int load_unit(DBusConnection *bus, char **args) { int r; n = unit_name_mangle(*name); - r = bus_method_call_with_reply ( + if (!n) + return log_oom(); + + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -1050,7 +1181,7 @@ static int load_unit(DBusConnection *bus, char **args) { "LoadUnit", NULL, NULL, - DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); if (r < 0) return r; @@ -1095,19 +1226,22 @@ static int cancel_job(DBusConnection *bus, char **args) { } static bool need_daemon_reload(DBusConnection *bus, const char *unit) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; dbus_bool_t b = FALSE; DBusMessageIter iter, sub; const char *interface = "org.freedesktop.systemd1.Unit", *property = "NeedDaemonReload", *path; - char *n; + _cleanup_free_ char *n = NULL; int r; /* We ignore all errors here, since this is used to show a warning only */ n = unit_name_mangle(unit); + if (!n) + return log_oom(); + r = bus_method_call_with_reply ( bus, "org.freedesktop.systemd1", @@ -1116,19 +1250,20 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { "GetUnit", &reply, NULL, - DBUS_TYPE_STRING, n ? (const char**) &n : &unit, + DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); - free(n); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) - goto finish; + return -EIO; dbus_message_unref(reply); - r = bus_method_call_with_reply ( + reply = NULL; + + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", path, @@ -1139,24 +1274,18 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - goto finish; + return -EIO; dbus_message_iter_recurse(&iter, &sub); - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) - goto finish; + return -EIO; dbus_message_iter_get_basic(&sub, &b); - -finish: - if (reply) - dbus_message_unref(reply); - return b; } @@ -1189,7 +1318,6 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { uint32_t id; const char *path, *result, *unit; - dbus_bool_t success = true; if (dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &id, @@ -1197,10 +1325,8 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me DBUS_TYPE_STRING, &unit, DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID)) { - char *p; - p = set_remove(d->set, (char*) path); - free(p); + free(set_remove(d->set, (char*) path)); if (!isempty(result)) d->result = strdup(result); @@ -1217,40 +1343,16 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID)) { - char *p; - /* Compatibility with older systemd versions < * 183 during upgrades. This should be dropped * one day. */ - p = set_remove(d->set, (char*) path); - free(p); + free(set_remove(d->set, (char*) path)); if (*result) d->result = strdup(result); goto finish; } - - dbus_error_free(&error); - if (dbus_message_get_args(message, &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_BOOLEAN, &success, - DBUS_TYPE_INVALID)) { - char *p; - - /* Compatibility with older systemd versions < - * 19 during upgrades. This should be dropped - * one day */ - - p = set_remove(d->set, (char*) path); - free(p); - - if (!success) - d->result = strdup("failed"); - - goto finish; - } #endif log_error("Failed to parse message: %s", bus_error_message(&error)); @@ -1343,12 +1445,12 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) { static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_free_ char *n = NULL; DBusMessageIter iter, sub; const char *interface = "org.freedesktop.systemd1.Unit", *property = "ActiveState"; const char *state, *path; - _cleanup_free_ char *n = NULL; DBusError error; int r; @@ -1434,7 +1536,6 @@ static void check_triggering_units( DBusMessageIter iter, sub; const char *interface = "org.freedesktop.systemd1.Unit", *triggered_by_property = "TriggeredBy"; - char _cleanup_free_ *unit_path = NULL, *n = NULL; bool print_warning_label = true; int r; @@ -1515,9 +1616,9 @@ static int start_unit_one( Set *s) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + _cleanup_free_ char *n; const char *path; int r; - _cleanup_free_ char *n, *p = NULL; assert(method); assert(name); @@ -1562,17 +1663,18 @@ static int start_unit_one( n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user"); if (s) { + char *p; + p = strdup(path); if (!p) return log_oom(); r = set_put(s, p); if (r < 0) { + free(p); log_error("Failed to add path to set."); return r; } - - p = NULL; } return 0; @@ -1769,7 +1871,7 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) { return -EINVAL; } - return bus_method_call_with_reply ( + return bus_method_call_with_reply( bus, "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1790,6 +1892,8 @@ static int check_inhibitors(DBusConnection *bus, enum action a) { DBusMessageIter iter, sub, sub2; int r; unsigned c = 0; + _cleanup_strv_free_ char **sessions = NULL; + char **s; if (!bus) return 0; @@ -1831,7 +1935,7 @@ static int check_inhibitors(DBusConnection *bus, enum action a) { const char *what, *who, *why, *mode; uint32_t uid, pid; _cleanup_strv_free_ char **sv = NULL; - _cleanup_free_ char *comm = NULL; + _cleanup_free_ char *comm = NULL, *user = NULL; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); @@ -1865,7 +1969,9 @@ static int check_inhibitors(DBusConnection *bus, enum action a) { goto next; get_process_comm(pid, &comm); - log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", UID %lu), reason is \"%s\".", who, (unsigned long) pid, strna(comm), (unsigned long) uid, why); + user = uid_to_name(uid); + log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".", + who, (unsigned long) pid, strna(comm), strna(user), why); c++; next: @@ -1874,10 +1980,34 @@ static int check_inhibitors(DBusConnection *bus, enum action a) { dbus_message_iter_recurse(&iter, &sub); + /* Check for current sessions */ + sd_get_sessions(&sessions); + STRV_FOREACH(s, sessions) { + uid_t uid; + _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL; + + if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid()) + continue; + + if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user")) + continue; + + if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty"))) + continue; + + sd_session_get_tty(*s, &tty); + sd_session_get_seat(*s, &seat); + sd_session_get_service(*s, &service); + user = uid_to_name(uid); + + log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty); + c++; + } + if (c <= 0) return 0; - log_error("Please try again after closing inhibitors or ignore them with 'systemctl %s -i'.", + log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.", a == ACTION_HALT ? "halt" : a == ACTION_POWEROFF ? "poweroff" : a == ACTION_REBOOT ? "reboot" : @@ -2006,6 +2136,8 @@ static int kill_unit(DBusConnection *bus, char **args) { _cleanup_free_ char *n = NULL; n = unit_name_mangle(*name); + if (!n) + return log_oom(); r = bus_method_call_with_reply( bus, @@ -2015,7 +2147,7 @@ static int kill_unit(DBusConnection *bus, char **args) { "KillUnit", NULL, NULL, - DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_STRING, &arg_kill_who, DBUS_TYPE_INT32, &arg_signal, DBUS_TYPE_INVALID); @@ -2032,6 +2164,7 @@ static int set_cgroup(DBusConnection *bus, char **args) { DBusMessageIter iter; int r; _cleanup_free_ char *n = NULL; + const char *runtime; assert(bus); assert(args); @@ -2063,6 +2196,10 @@ static int set_cgroup(DBusConnection *bus, char **args) { if (r < 0) return log_oom(); + runtime = arg_runtime ? "runtime" : "persistent"; + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime)) + 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)); @@ -2077,9 +2214,9 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; DBusError error; DBusMessageIter iter, sub, sub2; - int r; char **x, **y; _cleanup_free_ char *n = NULL; + const char *runtime; assert(bus); assert(args); @@ -2116,8 +2253,54 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { return log_oom(); } - if (!dbus_message_iter_close_container(&iter, &sub)) - return -ENOMEM; + runtime = arg_runtime ? "runtime" : "persistent"; + if (!dbus_message_iter_close_container(&iter, &sub) || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime)) + 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; + } + + 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) { @@ -2126,6 +2309,20 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { 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; } @@ -2175,7 +2372,8 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0) return -EIO; - if (!(i->path = strdup(path))) + i->path = strdup(path); + if (!i->path) return -ENOMEM; if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY || @@ -2190,8 +2388,8 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) n++; } - - if (!(i->argv = new0(char*, n+1))) + i->argv = new0(char*, n+1); + if (!i->argv) return -ENOMEM; n = 0; @@ -2203,8 +2401,11 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) dbus_message_iter_get_basic(&sub3, &s); dbus_message_iter_next(&sub3); - if (!(i->argv[n++] = strdup(s))) + i->argv[n] = strdup(s); + if (!i->argv[n]) return -ENOMEM; + + n++; } if (!dbus_message_iter_next(&sub2) || @@ -2293,6 +2494,12 @@ static void print_status_info(UnitStatusInfo *i) { char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; char since2[FORMAT_TIMESTAMP_MAX], *s2; const char *path; + int flags = + arg_all * OUTPUT_SHOW_ALL | + (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | + on_tty() * OUTPUT_COLOR | + !arg_quiet * OUTPUT_WARN_CUTOFF | + arg_full * OUTPUT_FULL_WIDTH; assert(i); @@ -2403,7 +2610,7 @@ static void print_status_info(UnitStatusInfo *i) { printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections); LIST_FOREACH(exec, p, i->exec) { - char *t; + _cleanup_free_ char *t = NULL; bool good; /* Only show exited processes here */ @@ -2412,7 +2619,6 @@ static void print_status_info(UnitStatusInfo *i) { t = strv_join(p->argv, " "); printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t)); - free(t); good = is_clean_exit_lsb(p->code, p->status, NULL); if (!good) { @@ -2454,12 +2660,10 @@ static void print_status_info(UnitStatusInfo *i) { printf("Main PID: %u", (unsigned) i->main_pid); if (i->running) { - char *t = NULL; + _cleanup_free_ char *t = NULL; get_process_comm(i->main_pid, &t); - if (t) { + if (t) printf(" (%s)", t); - free(t); - } } else if (i->exit_code > 0) { printf(" (code=%s, ", sigchld_code_to_string(i->exit_code)); @@ -2482,15 +2686,13 @@ static void print_status_info(UnitStatusInfo *i) { printf(";"); if (i->control_pid > 0) { - char *t = NULL; + _cleanup_free_ char *t = NULL; printf(" Control: %u", (unsigned) i->control_pid); get_process_comm(i->control_pid, &t); - if (t) { + if (t) printf(" (%s)", t); - free(t); - } } printf("\n"); @@ -2521,25 +2723,29 @@ static void print_status_info(UnitStatusInfo *i) { if (i->control_pid > 0) extra[k++] = i->control_pid; - show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, extra, k); + show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, extra, k, flags); } } if (i->id && arg_transport != TRANSPORT_SSH) { - int flags = - arg_all * OUTPUT_SHOW_ALL | - (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | - on_tty() * OUTPUT_COLOR | - !arg_quiet * OUTPUT_WARN_CUTOFF; - printf("\n"); - show_journal_by_unit(stdout, - i->id, - arg_output, - 0, - i->inactive_exit_timestamp_monotonic, - arg_lines, - flags); + if(arg_scope == UNIT_FILE_SYSTEM) + show_journal_by_unit(stdout, + i->id, + arg_output, + 0, + i->inactive_exit_timestamp_monotonic, + arg_lines, + flags); + else + show_journal_by_user_unit(stdout, + i->id, + arg_output, + 0, + i->inactive_exit_timestamp_monotonic, + arg_lines, + getuid(), + flags); } if (i->need_daemon_reload) @@ -2952,7 +3158,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 && bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) { - printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n", + printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n", controller, attr, value); @@ -3015,7 +3221,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { } static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { - DBusMessage *reply = NULL; + _cleanup_free_ DBusMessage *reply = NULL; const char *interface = ""; int r; DBusMessageIter iter, sub, sub2, sub3; @@ -3027,7 +3233,7 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo zero(info); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", path, @@ -3037,15 +3243,14 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -3058,24 +3263,13 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { const char *name; - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY); dbus_message_iter_recurse(&sub, &sub2); - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 || + dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub2, &sub3); @@ -3084,11 +3278,9 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo r = print_property(name, &sub3); else r = status_property(name, &sub3, &info); - if (r < 0) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_next(&sub); @@ -3116,22 +3308,18 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo exec_status_info_free(p); } -finish: - if (reply) - dbus_message_unref(reply); - return r; } static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; const char *path = NULL; DBusError error; int r; dbus_error_init(&error); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3141,7 +3329,7 @@ static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, NULL, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID); - if (r) + if (r < 0) goto finish; if (!dbus_message_get_args(reply, &error, @@ -3155,9 +3343,6 @@ static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, r = show_one(verb, bus, path, false, new_line); finish: - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; @@ -3176,50 +3361,43 @@ static int show(DBusConnection *bus, char **args) { if (show_properties) pager_open_if_enabled(); - if (show_properties && strv_length(args) <= 1) { - /* If not argument is specified inspect the manager - * itself */ + /* If no argument is specified inspect the manager itself */ + if (show_properties && strv_length(args) <= 1) return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line); - } STRV_FOREACH(name, args+1) { uint32_t id; if (safe_atou32(*name, &id) < 0) { - char *p, *n; + _cleanup_free_ char *p = NULL, *n = NULL; /* Interpret as unit name */ n = unit_name_mangle(*name); - p = unit_dbus_path_from_name(n ? n : *name); - free(n); + if (!n) + return log_oom(); + + p = unit_dbus_path_from_name(n); if (!p) return log_oom(); r = show_one(args[0], bus, p, show_properties, &new_line); - free(p); - if (r != 0) ret = r; } else if (show_properties) { + _cleanup_free_ char *p = NULL; /* Interpret as job id */ - - char *p; if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) return log_oom(); r = show_one(args[0], bus, p, show_properties, &new_line); - free(p); - if (r != 0) ret = r; } else { - /* Interpret as PID */ - r = show_one_by_pid(args[0], bus, id, &new_line); if (r != 0) ret = r; @@ -3230,7 +3408,7 @@ static int show(DBusConnection *bus, char **args) { } static int dump(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; + _cleanup_free_ DBusMessage *reply = NULL; DBusError error; int r; const char *text; @@ -3239,7 +3417,7 @@ static int dump(DBusConnection *bus, char **args) { pager_open_if_enabled(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3248,26 +3426,19 @@ static int dump(DBusConnection *bus, char **args) { &reply, NULL, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_get_args(reply, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; + dbus_error_free(&error); + return -EIO; } fputs(text, stdout); - -finish: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; + return 0; } static int snapshot(DBusConnection *bus, char **args) { @@ -3277,17 +3448,19 @@ static int snapshot(DBusConnection *bus, char **args) { dbus_bool_t cleanup = FALSE; DBusMessageIter iter, sub; const char - *name = "", *path, *id, + *path, *id, *interface = "org.freedesktop.systemd1.Unit", *property = "Id"; _cleanup_free_ char *n = NULL; dbus_error_init(&error); - if (strv_length(args) > 1) { - name = args[1]; - n = unit_name_mangle(name); - } + if (strv_length(args) > 1) + n = snapshot_name_mangle(args[1]); + else + n = strdup(""); + if (!n) + return log_oom(); r = bus_method_call_with_reply ( bus, @@ -3297,18 +3470,18 @@ static int snapshot(DBusConnection *bus, char **args) { "CreateSnapshot", &reply, NULL, - DBUS_TYPE_STRING, n ? (const char**) &n : &name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_BOOLEAN, &cleanup, DBUS_TYPE_INVALID); if (r < 0) - goto finish; + return r; if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; + dbus_error_free(&error); + return -EIO; } dbus_message_unref(reply); @@ -3326,21 +3499,19 @@ static int snapshot(DBusConnection *bus, char **args) { DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); if (r < 0) - goto finish; + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_get_basic(&sub, &id); @@ -3348,10 +3519,7 @@ static int snapshot(DBusConnection *bus, char **args) { if (!arg_quiet) puts(id); -finish: - dbus_error_free(&error); - - return r; + return 0; } static int delete_snapshot(DBusConnection *bus, char **args) { @@ -3363,7 +3531,10 @@ static int delete_snapshot(DBusConnection *bus, char **args) { _cleanup_free_ char *n = NULL; int r; - n = unit_name_mangle(*name); + n = snapshot_name_mangle(*name); + if (!n) + return log_oom(); + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", @@ -3372,7 +3543,7 @@ static int delete_snapshot(DBusConnection *bus, char **args) { "RemoveSnapshot", NULL, NULL, - DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); if (r < 0) return r; @@ -3406,7 +3577,7 @@ static int daemon_reload(DBusConnection *bus, char **args) { /* "daemon-reload" */ "Reload"; } - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3424,23 +3595,28 @@ static int daemon_reload(DBusConnection *bus, char **args) { /* On reexecution, we expect a disconnect, not * a reply */ r = 0; - else if (r) + else if (r < 0) log_error("Failed to issue method call: %s", bus_error_message(&error)); - dbus_error_free(&error); + dbus_error_free(&error); return r; } static int reset_failed(DBusConnection *bus, char **args) { int r = 0; - char **name, *n; + char **name; if (strv_length(args) <= 1) return daemon_reload(bus, args); STRV_FOREACH(name, args+1) { + _cleanup_free_ char *n; + n = unit_name_mangle(*name); - r = bus_method_call_with_reply ( + if (!n) + return log_oom(); + + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3448,19 +3624,17 @@ static int reset_failed(DBusConnection *bus, char **args) { "ResetFailedUnit", NULL, NULL, - DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); - free(n); - if (r) - goto finish; + if (r < 0) + return r; } -finish: - return r; + return 0; } static int show_enviroment(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub, sub2; int r; const char @@ -3469,7 +3643,7 @@ static int show_enviroment(DBusConnection *bus, char **args) { pager_open_if_enabled(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3480,14 +3654,13 @@ static int show_enviroment(DBusConnection *bus, char **args) { DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&iter, &sub); @@ -3495,8 +3668,7 @@ static int show_enviroment(DBusConnection *bus, char **args) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_recurse(&sub, &sub2); @@ -3506,23 +3678,16 @@ static int show_enviroment(DBusConnection *bus, char **args) { if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_iter_get_basic(&sub2, &text); - printf("%s\n", text); + puts(text); dbus_message_iter_next(&sub2); } - r = 0; - -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return 0; } static int switch_root(DBusConnection *bus, char **args) { @@ -3547,15 +3712,13 @@ static int switch_root(DBusConnection *bus, char **args) { if (!init) init = strdup(""); - - if (!init) - return log_oom(); - } + if (!init) + return log_oom(); log_debug("switching root - root: %s; init: %s", root, init); - return bus_method_call_with_reply ( + return bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3601,15 +3764,11 @@ static int set_environment(DBusConnection *bus, char **args) { 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)); - r = -EIO; - goto finish; + dbus_error_free(&error); + return -EIO; } - r = 0; - -finish: - dbus_error_free(&error); - return r; + return 0; } static int enable_sysv_units(char **args) { @@ -4177,16 +4336,20 @@ static int systemctl_help(void) { " status [NAME...|PID...] Show runtime status of one or more units\n" " show [NAME...|JOB...] Show properties of one or more\n" " units/jobs or the manager\n" - " help [NAME...|PID...] Show manual for one or more units\n" + " 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" - " load [NAME...] Load one or more units\n\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" "Unit File Commands:\n" " list-unit-files List installed unit files\n" " enable [NAME...] Enable one or more unit files\n" @@ -5163,6 +5326,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 }, @@ -5202,6 +5366,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "unmask", MORE, 2, enable_unit }, { "link", MORE, 2, enable_unit }, { "switch-root", MORE, 2, switch_root }, + { "list-dependencies", LESS, 2, list_dependencies }, }; int left;