X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=a7b541dc3f0bf9da029001d04b14c499e4e2496c;hp=c67c6c972a1285567be791132dcf67414296209c;hb=76d14b876a1c286ea62c4e0e4fc5ba3c695e169f;hpb=37d3ab1b7e114f0fb6dfb2e7273569b42794b76a diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c67c6c972..a7b541dc3 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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) { @@ -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, @@ -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(); @@ -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; @@ -2053,7 +2053,7 @@ 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; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; _cleanup_free_ char *n = NULL; char **argument; int r; @@ -2084,7 +2084,11 @@ static int get_cgroup_attr(DBusConnection *bus, char **args) { if (r < 0) return r; - dbus_message_iter_init(reply, &iter); + if (!dbus_message_iter_init(reply, &iter)) { + log_error("Failed to initialize iterator."); + return -EIO; + } + r = bus_parse_strv_iter(&iter, &list); if (r < 0) { log_error("Failed to parse value list."); @@ -2221,6 +2225,8 @@ typedef struct UnitStatusInfo { const char *source_path; const char *default_control_group; + char **dropin_paths; + const char *load_error; const char *result; @@ -2251,6 +2257,9 @@ typedef struct UnitStatusInfo { unsigned n_connections; bool accept; + /* Pairs of type, path */ + char **listen; + /* Device */ const char *sysfs_path; @@ -2276,9 +2285,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 */ @@ -2290,7 +2310,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); @@ -2301,13 +2321,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; @@ -2321,16 +2373,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); @@ -2357,44 +2404,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 - (int)strlen(*t), "Listen", *t, *t2); 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) { @@ -2430,16 +2470,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)); @@ -2456,40 +2494,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; @@ -2499,29 +2540,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) @@ -2740,6 +2774,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")) { @@ -2748,16 +2814,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); } @@ -2870,6 +2933,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; @@ -2884,6 +2948,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; @@ -2901,8 +2983,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); @@ -2984,7 +3066,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) { - _cleanup_free_ DBusMessage *reply = NULL; + DBusMessage _cleanup_free_ *reply = NULL; const char *interface = ""; int r; DBusMessageIter iter, sub, sub2, sub3; @@ -3059,6 +3141,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") && @@ -3978,6 +4062,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); @@ -3992,7 +4077,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; @@ -4009,6 +4101,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", @@ -4017,8 +4113,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; @@ -4232,16 +4331,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; } @@ -4618,11 +4722,11 @@ static int parse_time_spec(const char *t, usec_t *_u) { 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); @@ -4907,7 +5011,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; @@ -5030,21 +5134,22 @@ finish: } static int talk_initctl(void) { - struct init_request request; - int r, fd; + struct init_request request = {0}; + 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; @@ -5054,9 +5159,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; }