X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=a95060550359d1f8cdeb67934a7b1bbe8bf6add5;hp=ddf46b66d53a9c7305127bc32266fd3642f0e8a6;hb=0ad4e1a872e789c77828d4c4825a56241103650c;hpb=d0a5cdb280f904eafacb09bbc391afd03c207b62 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ddf46b66d..a95060550 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -68,9 +68,9 @@ #include "socket-util.h" #include "fileio.h" -static const char *arg_type = NULL; -static const char *arg_load_state = NULL; -static char **arg_property = NULL; +static char **arg_types = NULL; +static char **arg_load_states = NULL; +static char **arg_properties = NULL; static bool arg_all = false; static const char *arg_job_mode = "replace"; static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; @@ -136,7 +136,7 @@ static void pager_open_if_enabled(void) { if (arg_no_pager) return; - pager_open(); + pager_open(false); } static void ask_password_agent_open_if_enabled(void) { @@ -295,9 +295,9 @@ static bool output_show_unit(const struct unit_info *u) { if (arg_failed) return streq(u->active_state, "failed"); - return (!arg_type || ((dot = strrchr(u->id, '.')) && - streq(dot+1, arg_type))) && - (!arg_load_state || streq(u->load_state, arg_load_state)) && + return (!arg_types || ((dot = strrchr(u->id, '.')) && + strv_find(arg_types, dot+1))) && + (!arg_load_states || strv_find(arg_load_states, u->load_state)) && (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0); } @@ -328,7 +328,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { if (!arg_full) { unsigned basic_len; - id_len = MIN(max_id_len, 25); + id_len = MIN(max_id_len, 25u); basic_len = 5 + id_len + 5 + active_len + sub_len; if (job_count) basic_len += job_len + 1; @@ -337,7 +337,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { extra_len = columns() - basic_len; /* Either UNIT already got 25, or is fully satisfied. * Grant up to 25 to DESC now. */ - incr = MIN(extra_len, 25); + incr = MIN(extra_len, 25u); desc_len += incr; extra_len -= incr; /* split the remaining space between UNIT and DESC, @@ -353,8 +353,8 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { for (u = unit_infos; u < unit_infos + c; u++) { char _cleanup_free_ *e = NULL; - const char *on_loaded, *off_loaded; - const char *on_active, *off_active; + const char *on_loaded, *off_loaded, *on = ""; + const char *on_active, *off_active, *off = ""; if (!output_show_unit(u)) continue; @@ -373,21 +373,21 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { n_shown++; if (streq(u->load_state, "error")) { - on_loaded = ansi_highlight_red(true); - off_loaded = ansi_highlight_red(false); + on_loaded = on = ansi_highlight_red(true); + off_loaded = off = ansi_highlight_red(false); } else on_loaded = off_loaded = ""; if (streq(u->active_state, "failed")) { - on_active = ansi_highlight_red(true); - off_active = ansi_highlight_red(false); + on_active = on = ansi_highlight_red(true); + off_active = off = ansi_highlight_red(false); } else on_active = off_active = ""; e = arg_full ? NULL : ellipsize(u->id, id_len, 33); - printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s", - id_len, e ? e : u->id, + printf("%s%-*s%s %s%-6s%s %s%-*s %-*s%s %-*s", + on, id_len, e ? e : u->id, off, on_loaded, u->load_state, off_loaded, on_active, active_len, u->active_state, sub_len, u->sub_state, off_active, @@ -463,7 +463,7 @@ static int get_unit_list(DBusConnection *bus, DBusMessage **reply, if (*c >= n_units) { struct unit_info *w; - n_units = MAX(2 * *c, 16); + n_units = MAX(2 * *c, 16u); w = realloc(*unit_infos, sizeof(struct unit_info) * n_units); if (!w) return log_oom(); @@ -524,7 +524,7 @@ static int compare_unit_file_list(const void *a, const void *b) { static bool output_show_unit_file(const UnitFileList *u) { const char *dot; - return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type)); + return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1)); } static void output_unit_file_list(const UnitFileList *units, unsigned c) { @@ -543,7 +543,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { if (!arg_full) { unsigned basic_cols; - id_cols = MIN(max_id_len, 25); + id_cols = MIN(max_id_len, 25u); basic_cols = 1 + id_cols + state_cols; if (basic_cols < (unsigned) columns()) id_cols += MIN(columns() - basic_cols, max_id_len - id_cols); @@ -657,7 +657,7 @@ static int list_unit_files(DBusConnection *bus, char **args) { if (c >= n_units) { UnitFileList *w; - n_units = MAX(2*c, 16); + n_units = MAX(2*c, 16u); w = realloc(units, sizeof(struct UnitFileList) * n_units); if (!w) return log_oom(); @@ -694,7 +694,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra int i; _cleanup_free_ char *n = NULL; size_t len = 0; - size_t max_len = MAX(columns(),20); + size_t max_len = MAX(columns(),20u); for (i = level - 1; i >= 0; i--) { len += 2; @@ -895,13 +895,84 @@ static int list_dependencies(DBusConnection *bus, char **args) { return list_dependencies_one(bus, u, 0, NULL, 0); } +struct job_info { + uint32_t id; + char *name, *type, *state; +}; + +static void list_jobs_print(struct job_info* jobs, size_t n) { + size_t i; + struct job_info *j; + const char *on, *off; + bool shorten = false; + + assert(n == 0 || jobs); + + if (n == 0) { + on = ansi_highlight_green(true); + off = ansi_highlight_green(false); + + printf("%sNo jobs running.%s\n", on, off); + return; + } + + pager_open_if_enabled(); + + { + /* JOB UNIT TYPE STATE */ + unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5; + + for (i = 0, j = jobs; i < n; i++, j++) { + assert(j->name && j->type && j->state); + l0 = MAX(l0, decimal_str_max(j->id)); + l1 = MAX(l1, strlen(j->name)); + l2 = MAX(l2, strlen(j->type)); + l3 = MAX(l3, strlen(j->state)); + } + + if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) { + l1 = MAX(33u, columns() - l0 - l2 - l3 - 3); + shorten = true; + } + + if (on_tty()) + printf("%*s %-*s %-*s %-*s\n", + l0, "JOB", + l1, "UNIT", + l2, "TYPE", + l3, "STATE"); + + for (i = 0, j = jobs; i < n; i++, j++) { + char _cleanup_free_ *e = NULL; + + if (streq(j->state, "running")) { + on = ansi_highlight(true); + off = ansi_highlight(false); + } else + on = off = ""; + + e = shorten ? ellipsize(j->name, l1, 33) : NULL; + printf("%*u %s%-*s%s %-*s %s%-*s%s\n", + l0, j->id, + on, l1, e ? e : j->name, off, + l2, j->type, + on, l3, j->state, off); + } + } + + on = ansi_highlight(true); + off = ansi_highlight(false); + + if (on_tty()) + printf("\n%s%zu jobs listed%s.\n", on, n, off); +} + static int list_jobs(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub, sub2; - unsigned k = 0; int r; - - pager_open_if_enabled(); + struct job_info *jobs = NULL; + size_t size = 0, used = 0; r = bus_method_call_with_reply( bus, @@ -924,13 +995,9 @@ static int list_jobs(DBusConnection *bus, char **args) { dbus_message_iter_recurse(&iter, &sub); - if (on_tty()) - printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE"); - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { const char *name, *type, *state, *job_path, *unit_path; uint32_t id; - char _cleanup_free_ *e = NULL; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { log_error("Failed to parse reply."); @@ -946,19 +1013,37 @@ 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."); - return -EIO; + r = -EIO; + goto finish; } - e = arg_full ? NULL : ellipsize(name, 25, 33); - printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state); + if (!greedy_realloc((void**) &jobs, &size, + sizeof(struct job_info) * (used + 1))) { + r = log_oom(); + goto finish; + } - k++; + jobs[used++] = (struct job_info) { id, + strdup(name), + strdup(type), + strdup(state) }; + if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) { + r = log_oom(); + goto finish; + } dbus_message_iter_next(&sub); } - if (on_tty()) - printf("\n%u jobs listed.\n", k); + list_jobs_print(jobs, used); + + finish: + while (used--) { + free(jobs[used].name); + free(jobs[used].type); + free(jobs[used].state); + } + free(jobs); return 0; } @@ -1045,7 +1130,7 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { if (!n) return log_oom(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -1193,14 +1278,11 @@ static int enable_wait_for_jobs(DBusConnection *bus) { static int wait_for_jobs(DBusConnection *bus, Set *s) { int r = 0; - WaitData d; + WaitData d = { .set = s }; assert(bus); assert(s); - zero(d); - d.set = s; - if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) return log_oom(); @@ -1518,53 +1600,39 @@ static int start_unit_one( return 0; } +static const struct { + const char *target; + const char *verb; + const char *mode; +} action_table[_ACTION_MAX] = { + [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, + [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, + [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" }, + [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" }, + [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" }, + [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" }, + [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" }, + [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" }, + [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" }, + [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" }, + [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" }, + [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" }, +}; + static enum action verb_to_action(const char *verb) { - if (streq(verb, "halt")) - return ACTION_HALT; - else if (streq(verb, "poweroff")) - return ACTION_POWEROFF; - else if (streq(verb, "reboot")) - return ACTION_REBOOT; - else if (streq(verb, "kexec")) - return ACTION_KEXEC; - else if (streq(verb, "rescue")) - return ACTION_RESCUE; - else if (streq(verb, "emergency")) - return ACTION_EMERGENCY; - else if (streq(verb, "default")) - return ACTION_DEFAULT; - else if (streq(verb, "exit")) - return ACTION_EXIT; - else if (streq(verb, "suspend")) - return ACTION_SUSPEND; - else if (streq(verb, "hibernate")) - return ACTION_HIBERNATE; - else if (streq(verb, "hybrid-sleep")) - return ACTION_HYBRID_SLEEP; - else - return ACTION_INVALID; + enum action i; + + for (i = ACTION_INVALID; i < _ACTION_MAX; i++) + if (action_table[i].verb && streq(verb, action_table[i].verb)) + return i; + return ACTION_INVALID; } static int start_unit(DBusConnection *bus, char **args) { - static const char * const table[_ACTION_MAX] = { - [ACTION_HALT] = SPECIAL_HALT_TARGET, - [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET, - [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET, - [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET, - [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET, - [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET, - [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET, - [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET, - [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET, - [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET, - [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET, - [ACTION_EXIT] = SPECIAL_EXIT_TARGET, - [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET, - [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, - [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET - }; - int r, ret = 0; const char *method, *mode, *one_name; Set _cleanup_set_free_free_ *s = NULL; @@ -1578,6 +1646,7 @@ static int start_unit(DBusConnection *bus, char **args) { ask_password_agent_open_if_enabled(); if (arg_action == ACTION_SYSTEMCTL) { + enum action action; method = streq(args[0], "stop") || streq(args[0], "condstop") ? "StopUnit" : @@ -1594,28 +1663,21 @@ static int start_unit(DBusConnection *bus, char **args) { streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" : "StartUnit"; + action = verb_to_action(args[0]); - mode = - (streq(args[0], "isolate") || - streq(args[0], "rescue") || - streq(args[0], "emergency")) ? "isolate" : arg_job_mode; + mode = streq(args[0], "isolate") ? "isolate" : + action_table[action].mode ?: arg_job_mode; - one_name = table[verb_to_action(args[0])]; + one_name = action_table[action].target; } else { - assert(arg_action < ELEMENTSOF(table)); - assert(table[arg_action]); + assert(arg_action < ELEMENTSOF(action_table)); + assert(action_table[arg_action].target); method = "StartUnit"; - mode = (arg_action == ACTION_EMERGENCY || - arg_action == ACTION_RESCUE || - arg_action == ACTION_RUNLEVEL2 || - arg_action == ACTION_RUNLEVEL3 || - arg_action == ACTION_RUNLEVEL4 || - arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace"; - - one_name = table[arg_action]; + mode = action_table[arg_action].mode; + one_name = action_table[arg_action].target; } if (!arg_no_block) { @@ -1838,12 +1900,7 @@ static int check_inhibitors(DBusConnection *bus, enum action a) { return 0; 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" : - a == ACTION_KEXEC ? "kexec" : - a == ACTION_SUSPEND ? "suspend" : - a == ACTION_HIBERNATE ? "hibernate" : "hybrid-sleep"); + action_table[a].verb); return -EPERM; #else @@ -1988,53 +2045,41 @@ static int kill_unit(DBusConnection *bus, char **args) { } static int set_cgroup(DBusConnection *bus, char **args) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - DBusError error; - const char *method; - DBusMessageIter iter; - int r; _cleanup_free_ char *n = NULL; - const char *runtime; + const char *method, *runtime; + char **argument; + int r; assert(bus); assert(args); - dbus_error_init(&error); - method = - streq(args[0], "set-cgroup") ? "SetUnitControlGroups" : - streq(args[0], "unset-group") ? "UnsetUnitControlGroups" - : "UnsetUnitControlGroupAttributes"; + streq(args[0], "set-cgroup") ? "SetUnitControlGroup" : + streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup" + : "UnsetUnitControlGroupAttribute"; + + runtime = arg_runtime ? "runtime" : "persistent"; 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", - method); - if (!m) - return log_oom(); + STRV_FOREACH(argument, args + 2) { - 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(); - - 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)); - dbus_error_free(&error); - return -EIO; + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method, + NULL, + NULL, + DBUS_TYPE_STRING, &n, + DBUS_TYPE_STRING, argument, + DBUS_TYPE_STRING, &runtime, + DBUS_TYPE_INVALID); + if (r < 0) + return r; } return 0; @@ -2043,20 +2088,17 @@ static int set_cgroup(DBusConnection *bus, char **args) { static int set_cgroup_attr(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; DBusError error; - DBusMessageIter iter, sub, sub2; - char **x, **y; + DBusMessageIter iter; _cleanup_free_ char *n = NULL; const char *runtime; + int r; assert(bus); assert(args); dbus_error_init(&error); - if (strv_length(args) % 2 != 0) { - log_error("Expecting an uneven number of arguments!"); - return -EINVAL; - } + runtime = arg_runtime ? "runtime" : "persistent"; n = unit_name_mangle(args[1]); if (!n) @@ -2066,26 +2108,20 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "SetUnitControlGroupAttributes"); + "SetUnitControlGroupAttribute"); if (!m) return log_oom(); dbus_message_iter_init_append(m, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2])) return log_oom(); - STRV_FOREACH_PAIR(x, y, args + 2) { - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) || - !dbus_message_iter_close_container(&sub, &sub2)) - return log_oom(); - } + r = bus_append_strv_iter(&iter, args + 3); + if (r < 0) + return log_oom(); - runtime = arg_runtime ? "runtime" : "persistent"; - if (!dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime)) + 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); @@ -2099,58 +2135,54 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { } 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_dbus_message_unref_ DBusMessage *reply = NULL; _cleanup_free_ char *n = NULL; - _cleanup_strv_free_ char **list = NULL; - char **a; + char **argument; + int r; 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(); + STRV_FOREACH(argument, args + 2) { + _cleanup_strv_free_ char **list = NULL; + DBusMessageIter iter; + char **a; - r = bus_append_strv_iter(&iter, args + 2); - if (r < 0) - return log_oom(); + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitControlGroupAttribute", + &reply, + NULL, + DBUS_TYPE_STRING, &n, + DBUS_TYPE_STRING, argument, + DBUS_TYPE_INVALID); + if (r < 0) + return r; - 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; - } + if (!dbus_message_iter_init(reply, &iter)) { + log_error("Failed to initialize iterator."); + 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; - } + 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); + STRV_FOREACH(a, list) { + if (endswith(*a, "\n")) + fputs(*a, stdout); + else + puts(*a); + } } return 0; @@ -2275,6 +2307,8 @@ typedef struct UnitStatusInfo { const char *source_path; const char *default_control_group; + char **dropin_paths; + const char *load_error; const char *result; @@ -2305,6 +2339,9 @@ typedef struct UnitStatusInfo { unsigned n_connections; bool accept; + /* Pairs of type, path */ + char **listen; + /* Device */ const char *sysfs_path; @@ -2330,9 +2367,20 @@ static void print_status_info(UnitStatusInfo *i) { on_tty() * OUTPUT_COLOR | !arg_quiet * OUTPUT_WARN_CUTOFF | arg_full * OUTPUT_FULL_WIDTH; + int maxlen = 8; /* a value that'll suffice most of the time */ + char **t, **t2; assert(i); + STRV_FOREACH_PAIR(t, t2, i->listen) + maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t))); + if (i->accept) + maxlen = MAX(maxlen, (int)sizeof("Accept") - 1); + if (i->main_pid > 0) + maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1); + else if (i->control_pid > 0) + maxlen = MAX(maxlen, (int)sizeof("Control") - 1); + /* This shows pretty information about a unit. See * print_property() for a low-level property printer */ @@ -2344,7 +2392,7 @@ static void print_status_info(UnitStatusInfo *i) { printf("\n"); if (i->following) - printf("\t Follow: unit currently follows state of %s\n", i->following); + printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following); if (streq_ptr(i->load_state, "error")) { on = ansi_highlight_red(true); @@ -2355,13 +2403,45 @@ static void print_status_info(UnitStatusInfo *i) { path = i->source_path ? i->source_path : i->fragment_path; if (i->load_error) - printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error); + printf(" %*s: %s%s%s (Reason: %s)\n", + maxlen, "Loaded", on, strna(i->load_state), off, i->load_error); else if (path && i->unit_file_state) - printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state); + printf(" %*s: %s%s%s (%s; %s)\n", + maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state); else if (path) - printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path); + printf(" %*s: %s%s%s (%s)\n", + maxlen, "Loaded", on, strna(i->load_state), off, path); else - printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off); + printf(" %*s: %s%s%s\n", + maxlen, "Loaded", on, strna(i->load_state), off); + + if (!strv_isempty(i->dropin_paths)) { + char ** dropin; + char * dir = NULL; + bool last = false; + + STRV_FOREACH(dropin, i->dropin_paths) { + if (! dir || last) { + printf(" %*s ", maxlen, dir ? "" : "Drop-In:"); + + free(dir); + + if (path_get_parent(*dropin, &dir) < 0) { + log_oom(); + return; + } + + printf("%s\n %*s %s", dir, maxlen, "", + draw_special_char(DRAW_TREE_RIGHT)); + } + + last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir)); + + printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", "); + } + + free(dir); + } ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state; @@ -2375,16 +2455,11 @@ static void print_status_info(UnitStatusInfo *i) { on = off = ""; if (ss) - printf("\t Active: %s%s (%s)%s", - on, - strna(i->active_state), - ss, - off); + printf(" %*s: %s%s (%s)%s", + maxlen, "Active", on, strna(i->active_state), ss, off); else - printf("\t Active: %s%s%s", - on, - strna(i->active_state), - off); + printf(" %*s: %s%s%s", + maxlen, "Active", on, strna(i->active_state), off); if (!isempty(i->result) && !streq(i->result, "success")) printf(" (Result: %s)", i->result); @@ -2411,44 +2486,37 @@ static void print_status_info(UnitStatusInfo *i) { s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); if (s1) - printf("\t start condition failed at %s; %s\n", s2, s1); + printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1); else if (s2) - printf("\t start condition failed at %s\n", s2); + printf(" %*s start condition failed at %s\n", maxlen, "", s2); } if (i->sysfs_path) - printf("\t Device: %s\n", i->sysfs_path); + printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path); if (i->where) - printf("\t Where: %s\n", i->where); + printf(" %*s: %s\n", maxlen, "Where", i->where); if (i->what) - printf("\t What: %s\n", i->what); + printf(" %*s: %s\n", maxlen, "What", i->what); - if (!strv_isempty(i->documentation)) { - char **t; - bool first = true; + STRV_FOREACH(t, i->documentation) + printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t); - STRV_FOREACH(t, i->documentation) { - if (first) { - printf("\t Docs: %s\n", *t); - first = false; - } else - printf("\t %s\n", *t); - } - } + STRV_FOREACH_PAIR(t, t2, i->listen) + printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t); if (i->accept) - printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections); + printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections); LIST_FOREACH(exec, p, i->exec) { - _cleanup_free_ char *t = NULL; + _cleanup_free_ char *argv = NULL; bool good; /* Only show exited processes here */ if (p->code == 0) continue; - t = strv_join(p->argv, " "); - printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t)); + argv = strv_join(p->argv, " "); + printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv)); good = is_clean_exit_lsb(p->code, p->status, NULL); if (!good) { @@ -2484,16 +2552,14 @@ static void print_status_info(UnitStatusInfo *i) { } if (i->main_pid > 0 || i->control_pid > 0) { - printf("\t"); - if (i->main_pid > 0) { - printf("Main PID: %u", (unsigned) i->main_pid); + printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid); if (i->running) { - _cleanup_free_ char *t = NULL; - get_process_comm(i->main_pid, &t); - if (t) - printf(" (%s)", t); + _cleanup_free_ char *comm = NULL; + get_process_comm(i->main_pid, &comm); + if (comm) + printf(" (%s)", comm); } else if (i->exit_code > 0) { printf(" (code=%s, ", sigchld_code_to_string(i->exit_code)); @@ -2510,40 +2576,43 @@ static void print_status_info(UnitStatusInfo *i) { printf("signal=%s", signal_to_string(i->exit_status)); printf(")"); } - } - if (i->main_pid > 0 && i->control_pid > 0) - printf(";"); + if (i->control_pid > 0) + printf(";"); + } if (i->control_pid > 0) { - _cleanup_free_ char *t = NULL; + _cleanup_free_ char *c = NULL; - printf(" Control: %u", (unsigned) i->control_pid); + printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid); - get_process_comm(i->control_pid, &t); - if (t) - printf(" (%s)", t); + get_process_comm(i->control_pid, &c); + if (c) + printf(" (%s)", c); } printf("\n"); } if (i->status_text) - printf("\t Status: \"%s\"\n", i->status_text); + printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text); if (i->default_control_group && (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) { unsigned c; - printf("\t CGroup: %s\n", i->default_control_group); + printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group); if (arg_transport != TRANSPORT_SSH) { unsigned k = 0; pid_t extra[2]; + char prefix[maxlen + 4]; + memset(prefix, ' ', sizeof(prefix) - 1); + prefix[sizeof(prefix) - 1] = '\0'; c = columns(); - if (c > 18) - c -= 18; + if (c > sizeof(prefix) - 1) + c -= sizeof(prefix) - 1; else c = 0; @@ -2553,29 +2622,22 @@ 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, extra, k, flags); + show_cgroup_and_extra_by_spec(i->default_control_group, prefix, + c, false, extra, k, flags); } } if (i->id && arg_transport != TRANSPORT_SSH) { printf("\n"); - 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); + show_journal_by_unit(stdout, + i->id, + arg_output, + 0, + i->inactive_exit_timestamp_monotonic, + arg_lines, + getuid(), + flags, + arg_scope == UNIT_FILE_SYSTEM); } if (i->need_daemon_reload) @@ -2794,6 +2856,38 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn dbus_message_iter_next(&sub); } + + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *type, *path; + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) { + int r; + + r = strv_extend(&i->listen, type); + if (r < 0) + return r; + r = strv_extend(&i->listen, path); + if (r < 0) + return r; + } + + dbus_message_iter_next(&sub); + } + + return 0; + + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) { + int r = bus_parse_strv_iter(iter, &i->dropin_paths); + if (r < 0) + return r; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "Documentation")) { @@ -2802,16 +2896,13 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn dbus_message_iter_recurse(iter, &sub); while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { const char *s; - char **l; + int r; dbus_message_iter_get_basic(&sub, &s); - l = strv_append(i->documentation, s); - if (!l) - return -ENOMEM; - - strv_free(i->documentation); - i->documentation = l; + r = strv_extend(&i->documentation, s); + if (r < 0) + return r; dbus_message_iter_next(&sub); } @@ -2855,7 +2946,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { /* This is a low-level property printer, see * print_status_info() for the nicer output */ - if (arg_property && !strv_find(arg_property, name)) + if (arg_properties && !strv_find(arg_properties, name)) return 0; switch (dbus_message_iter_get_arg_type(iter)) { @@ -2924,6 +3015,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { DBusMessageIter sub, sub2; dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { const char *type, *path; @@ -2938,6 +3030,24 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *type, *path; + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) + printf("Listen%s=%s\n", type, path); + + dbus_message_iter_next(&sub); + } + + return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) { DBusMessageIter sub, sub2; @@ -2955,8 +3065,8 @@ static int print_property(const char *name, DBusMessageIter *iter) { printf("%s={ value=%s ; next_elapse=%s }\n", base, - format_timespan(timespan1, sizeof(timespan1), value), - format_timespan(timespan2, sizeof(timespan2), next_elapse)); + format_timespan(timespan1, sizeof(timespan1), value, 0), + format_timespan(timespan2, sizeof(timespan2), next_elapse, 0)); } dbus_message_iter_next(&sub); @@ -2993,9 +3103,8 @@ static int print_property(const char *name, DBusMessageIter *iter) { dbus_message_iter_recurse(iter, &sub); while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - ExecStatusInfo info; + ExecStatusInfo info = {}; - zero(info); if (exec_status_info_deserialize(&sub, &info) >= 0) { char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX]; char _cleanup_free_ *t; @@ -3038,18 +3147,16 @@ 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) { - _cleanup_free_ DBusMessage *reply = NULL; + DBusMessage _cleanup_free_ *reply = NULL; const char *interface = ""; int r; DBusMessageIter iter, sub, sub2, sub3; - UnitStatusInfo info; + UnitStatusInfo info = {}; ExecStatusInfo *p; assert(path); assert(new_line); - zero(info); - r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", @@ -3113,6 +3220,8 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo } strv_free(info.documentation); + strv_free(info.dropin_paths); + strv_free(info.listen); if (!streq_ptr(info.active_state, "active") && !streq_ptr(info.active_state, "reloading") && @@ -3624,7 +3733,7 @@ static int enable_sysv_units(char **args) { #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG) const char *verb = args[0]; unsigned f = 1, t = 1; - LookupPaths paths; + LookupPaths paths = {}; if (arg_scope != UNIT_FILE_SYSTEM) return 0; @@ -3637,7 +3746,6 @@ static int enable_sysv_units(char **args) { /* Processes all SysV units, and reshuffles the array so that * afterwards only the native units remain */ - zero(paths); r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL); if (r < 0) return r; @@ -4010,16 +4118,15 @@ static int enable_unit(DBusConnection *bus, char **args) { } if (carries_install_info == 0) - log_warning( -"The unit files have no [Install] section. They are not meant to be enabled\n" -"using systemctl.\n" -"Possible reasons for having this kind of units are:\n" -"1) A unit may be statically enabled by being symlinked from another unit's\n" -" .wants/ or .requires/ directory.\n" -"2) A unit's purpose may be to act as a helper for some other unit which has\n" -" a requirement dependency on it.\n" -"3) A unit may be started when needed via activation (socket, path, timer,\n" -" D-Bus, udev, scripted systemctl call, ...).\n"); + log_warning("The unit files have no [Install] section. They are not meant to be enabled\n" + "using systemctl.\n" + "Possible reasons for having this kind of units are:\n" + "1) A unit may be statically enabled by being symlinked from another unit's\n" + " .wants/ or .requires/ directory.\n" + "2) A unit's purpose may be to act as a helper for some other unit which has\n" + " a requirement dependency on it.\n" + "3) A unit may be started when needed via activation (socket, path, timer,\n" + " D-Bus, udev, scripted systemctl call, ...).\n"); finish: unit_file_changes_free(changes, n_changes); @@ -4033,6 +4140,7 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { DBusMessage _cleanup_dbus_message_unref_ *reply = NULL; bool enabled; char **name; + char *n; dbus_error_init(&error); @@ -4047,7 +4155,14 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { STRV_FOREACH(name, args+1) { UnitFileState state; - state = unit_file_get_state(arg_scope, arg_root, *name); + n = unit_name_mangle(*name); + if (!n) + return log_oom(); + + state = unit_file_get_state(arg_scope, arg_root, n); + + free(n); + if (state < 0) return state; @@ -4064,6 +4179,10 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { STRV_FOREACH(name, args+1) { const char *s; + n = unit_name_mangle(*name); + if (!n) + return log_oom(); + r = bus_method_call_with_reply ( bus, "org.freedesktop.systemd1", @@ -4072,8 +4191,11 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { "GetUnitFileState", &reply, NULL, - DBUS_TYPE_STRING, name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); + + free(n); + if (r) return r; @@ -4287,16 +4409,21 @@ static int runlevel_help(void) { static int help_types(void) { int i; + const char *t; puts("Available unit types:"); - for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++) - if (unit_type_table[i]) - puts(unit_type_table[i]); + for(i = 0; i < _UNIT_TYPE_MAX; i++) { + t = unit_type_to_string(i); + if (t) + puts(t); + } puts("\nAvailable unit load states: "); - for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++) - if (unit_type_table[i]) - puts(unit_load_state_table[i]); + for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) { + t = unit_load_state_to_string(i); + if (t) + puts(t); + } return 0; } @@ -4305,6 +4432,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { enum { ARG_FAIL = 0x100, + ARG_IRREVERSIBLE, ARG_IGNORE_DEPENDENCIES, ARG_VERSION, ARG_USER, @@ -4333,6 +4461,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "failed", no_argument, NULL, ARG_FAILED }, { "full", no_argument, NULL, ARG_FULL }, { "fail", no_argument, NULL, ARG_FAIL }, + { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, { "ignore-inhibitors", no_argument, NULL, 'i' }, { "user", no_argument, NULL, ARG_USER }, @@ -4375,37 +4504,74 @@ static int systemctl_parse_argv(int argc, char *argv[]) { puts(SYSTEMD_FEATURES); return 0; - case 't': - if (streq(optarg, "help")) { - help_types(); - return 0; - } + case 't': { + char *word, *state; + size_t size; - if (unit_type_from_string(optarg) >= 0) { - arg_type = optarg; - break; - } - if (unit_load_state_from_string(optarg) >= 0) { - arg_load_state = optarg; - break; + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + char _cleanup_free_ *type; + + type = strndup(word, size); + if (!type) + return -ENOMEM; + + if (streq(type, "help")) { + help_types(); + return 0; + } + + if (unit_type_from_string(type) >= 0) { + if (strv_push(&arg_types, type)) + return log_oom(); + type = NULL; + continue; + } + + if (unit_load_state_from_string(optarg) >= 0) { + if (strv_push(&arg_load_states, type)) + return log_oom(); + type = NULL; + continue; + } + + log_error("Unkown unit type or load state '%s'.", type); + log_info("Use -t help to see a list of allowed values."); + return -EINVAL; } - log_error("Unkown unit type or load state '%s'.", - optarg); - log_info("Use -t help to see a list of allowed values."); - return -EINVAL; + + break; + } + case 'p': { - char **l; + /* Make sure that if the empty property list + was specified, we won't show any properties. */ + if (isempty(optarg) && !arg_properties) { + arg_properties = strv_new(NULL, NULL); + if (!arg_properties) + return log_oom(); + } else { + char *word, *state; + size_t size; - if (!(l = strv_append(arg_property, optarg))) - return -ENOMEM; + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + char *prop; - strv_free(arg_property); - arg_property = l; + prop = strndup(word, size); + if (!prop) + return log_oom(); + + if (strv_push(&arg_properties, prop)) { + free(prop); + return log_oom(); + } + } + } /* If the user asked for a particular * property, show it to him, even if it is * empty. */ arg_all = true; + break; } @@ -4417,6 +4583,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_job_mode = "fail"; break; + case ARG_IRREVERSIBLE: + arg_job_mode = "replace-irreversibly"; + break; + case ARG_IGNORE_DEPENDENCIES: arg_job_mode = "ignore-dependencies"; break; @@ -4646,23 +4816,22 @@ static int parse_time_spec(const char *t, usec_t *_u) { } else { char *e = NULL; long hour, minute; - struct tm tm; + struct tm tm = {}; time_t s; usec_t n; errno = 0; hour = strtol(t, &e, 10); - if (errno != 0 || *e != ':' || hour < 0 || hour > 23) + if (errno > 0 || *e != ':' || hour < 0 || hour > 23) return -EINVAL; minute = strtol(e+1, &e, 10); - if (errno != 0 || *e != 0 || minute < 0 || minute > 59) + if (errno > 0 || *e != 0 || minute < 0 || minute > 59) return -EINVAL; n = now(CLOCK_REALTIME); s = (time_t) (n / USEC_PER_SEC); - zero(tm); assert_se(localtime_r(&s, &tm)); tm.tm_hour = (int) hour; @@ -4941,7 +5110,7 @@ static int parse_argv(int argc, char *argv[]) { * request to it. For now we simply * guess that it is Upstart. */ - execv("/lib/upstart/telinit", argv); + execv(TELINIT, argv); log_error("Couldn't find an alternative telinit implementation to spawn."); return -EIO; @@ -5064,21 +5233,22 @@ finish: } static int talk_initctl(void) { - struct init_request request; - int r, fd; + struct init_request request = {}; + int r; + int _cleanup_close_ fd = -1; char rl; - if (!(rl = action_to_runlevel())) + rl = action_to_runlevel(); + if (!rl) return 0; - zero(request); request.magic = INIT_MAGIC; request.sleeptime = 0; request.cmd = INIT_CMD_RUNLVL; request.runlevel = rl; - if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) { - + fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { if (errno == ENOENT) return 0; @@ -5088,9 +5258,7 @@ static int talk_initctl(void) { errno = 0; r = loop_write(fd, &request, sizeof(request), false) != sizeof(request); - close_nointr_nofail(fd); - - if (r < 0) { + if (r) { log_error("Failed to write to "INIT_FIFO": %m"); return errno ? -errno : -EIO; } @@ -5128,11 +5296,11 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */ { "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 }, + { "set-cgroup", MORE, 3, set_cgroup }, + { "unset-cgroup", MORE, 3, set_cgroup }, + { "get-cgroup-attr", MORE, 3, get_cgroup_attr }, + { "set-cgroup-attr", MORE, 4, set_cgroup_attr }, + { "unset-cgroup-attr", MORE, 3, set_cgroup }, { "kill", MORE, 2, kill_unit }, { "is-active", MORE, 2, check_unit_active }, { "check", MORE, 2, check_unit_active }, @@ -5270,41 +5438,38 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) { int _cleanup_close_ fd; - struct msghdr msghdr; - struct iovec iovec[2]; - union sockaddr_union sockaddr; - struct sd_shutdown_command c; + struct sd_shutdown_command c = { + .usec = t, + .mode = mode, + .dry_run = dry_run, + .warn_wall = warn, + }; + union sockaddr_union sockaddr = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/shutdownd", + }; + struct iovec iovec[2] = { + {.iov_base = (char*) &c, + .iov_len = offsetof(struct sd_shutdown_command, wall_message), + } + }; + struct msghdr msghdr = { + .msg_name = &sockaddr, + .msg_namelen = offsetof(struct sockaddr_un, sun_path) + + sizeof("/run/systemd/shutdownd") - 1, + .msg_iov = iovec, + .msg_iovlen = 1, + }; fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); if (fd < 0) return -errno; - zero(c); - c.usec = t; - c.mode = mode; - c.dry_run = dry_run; - c.warn_wall = warn; - - zero(sockaddr); - sockaddr.sa.sa_family = AF_UNIX; - strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path)); - - zero(msghdr); - msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1; - - zero(iovec); - iovec[0].iov_base = (char*) &c; - iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message); - - if (isempty(message)) - msghdr.msg_iovlen = 1; - else { + if (!isempty(message)) { iovec[1].iov_base = (char*) message; iovec[1].iov_len = strlen(message); - msghdr.msg_iovlen = 2; + msghdr.msg_iovlen++; } - msghdr.msg_iov = iovec; if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) return -errno; @@ -5582,7 +5747,9 @@ finish: dbus_shutdown(); - strv_free(arg_property); + strv_free(arg_types); + strv_free(arg_load_states); + strv_free(arg_properties); pager_close(); ask_password_agent_close();