X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl.c;h=0de2444d43edb62bd420e7435fc364610fb0fadf;hp=620b91ff639460e06a8cabfd53007bca3e1bde4f;hb=798e258d301ac237cb1d72b5fc4b19ee900d6f7d;hpb=729e3769c32242bbba26ea96900be005d52ce438 diff --git a/src/systemctl.c b/src/systemctl.c index 620b91ff6..0de2444d4 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -66,6 +66,7 @@ static const char *arg_job_mode = "replace"; static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; static bool arg_immediate = false; static bool arg_no_block = false; +static bool arg_no_legend = false; static bool arg_no_pager = false; static bool arg_no_wtmp = false; static bool arg_no_sync = false; @@ -137,6 +138,8 @@ static bool on_tty(void) { } static void pager_open_if_enabled(void) { + + /* Cache result before we open the pager */ on_tty(); if (arg_no_pager) @@ -312,35 +315,60 @@ static bool output_show_unit(const struct unit_info *u) { } static void output_units_list(const struct unit_info *unit_infos, unsigned c) { - unsigned active_len, sub_len, job_len, n_shown = 0; + unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0; const struct unit_info *u; + max_id_len = sizeof("UNIT")-1; active_len = sizeof("ACTIVE")-1; sub_len = sizeof("SUB")-1; job_len = sizeof("JOB")-1; + desc_len = 0; for (u = unit_infos; u < unit_infos + c; u++) { if (!output_show_unit(u)) continue; + max_id_len = MAX(max_id_len, strlen(u->id)); active_len = MAX(active_len, strlen(u->active_state)); sub_len = MAX(sub_len, strlen(u->sub_state)); if (u->job_id != 0) job_len = MAX(job_len, strlen(u->job_type)); } - if (on_tty()) { - printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD", + if (!arg_full) { + unsigned basic_len; + id_len = MIN(max_id_len, 25); + basic_len = 5 + id_len + 6 + active_len + sub_len + job_len; + if (basic_len < (unsigned) columns()) { + unsigned extra_len, incr; + 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); + desc_len += incr; + extra_len -= incr; + /* split the remaining space between UNIT and DESC, + * but do not give UNIT more than it needs. */ + if (extra_len > 0) { + incr = MIN(extra_len / 2, max_id_len - id_len); + id_len += incr; + desc_len += extra_len - incr; + } + } + } else + id_len = max_id_len; + + if (!arg_no_legend) { + printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD", active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB"); - if (columns() >= 80+12 || arg_full || !arg_no_pager) - printf(" %s\n", "DESCRIPTION"); + if (!arg_full && arg_no_pager) + printf("%.*s\n", desc_len, "DESCRIPTION"); else - printf("\n"); + printf("%s\n", "DESCRIPTION"); } for (u = unit_infos; u < unit_infos + c; u++) { char *e; - int a = 0, b = 0; const char *on_loaded, *off_loaded; const char *on_active, *off_active; @@ -362,39 +390,23 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { } else on_active = off_active = ""; - e = arg_full ? NULL : ellipsize(u->id, 25, 33); + e = arg_full ? NULL : ellipsize(u->id, id_len, 33); - printf("%-25s %s%-6s%s %s%-*s %-*s%s%n", - e ? e : u->id, + printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ", + id_len, e ? e : u->id, on_loaded, u->load_state, off_loaded, on_active, active_len, u->active_state, sub_len, u->sub_state, off_active, - &a); - - free(e); - - a -= strlen(on_loaded) + strlen(off_loaded); - a -= strlen(on_active) + strlen(off_active); - - if (u->job_id != 0) - printf(" %-*s", job_len, u->job_type); + job_len, u->job_id ? u->job_type : ""); + if (!arg_full && arg_no_pager) + printf("%.*s\n", desc_len, u->description); else - b = 1 + job_len; - - if (a + b + 1 < columns()) { - if (u->job_id == 0) - printf(" %-*s", job_len, ""); - - if (arg_full || !arg_no_pager) - printf(" %s", u->description); - else - printf(" %.*s", columns() - a - b - 1, u->description); - } + printf("%s\n", u->description); - fputs("\n", stdout); + free(e); } - if (on_tty()) { + if (!arg_no_legend) { printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n" "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n" "SUB = The low-level unit activation state, values depend on unit type.\n" @@ -608,6 +620,7 @@ static int list_unit_files(DBusConnection *bus, char **args) { r = unit_file_get_list(arg_scope, arg_root, h); if (r < 0) { + unit_file_list_free(h); log_error("Failed to get unit file list: %s", strerror(-r)); return r; } @@ -1054,7 +1067,7 @@ finish: } static int load_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; DBusError error; int r; char **name; @@ -1065,6 +1078,7 @@ static int load_unit(DBusConnection *bus, char **args) { assert(args); STRV_FOREACH(name, args+1) { + DBusMessage *reply; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -1102,9 +1116,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; @@ -1794,7 +1805,7 @@ finish: } static int kill_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int r = 0; DBusError error; char **name; @@ -1811,6 +1822,7 @@ static int kill_unit(DBusConnection *bus, char **args) { arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process"; STRV_FOREACH(name, args+1) { + DBusMessage *reply; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -1850,9 +1862,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; @@ -1962,6 +1971,7 @@ typedef struct UnitStatusInfo { const char *load_state; const char *active_state; const char *sub_state; + const char *unit_file_state; const char *description; const char *following; @@ -1969,6 +1979,8 @@ typedef struct UnitStatusInfo { const char *path; const char *default_control_group; + const char *load_error; + usec_t inactive_exit_timestamp; usec_t active_enter_timestamp; usec_t active_exit_timestamp; @@ -2039,7 +2051,11 @@ static void print_status_info(UnitStatusInfo *i) { } else on = off = ""; - if (i->path) + if (i->load_error) + printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error); + else if (i->path && i->unit_file_state) + printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state); + else if (i->path) printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path); else printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off); @@ -2148,8 +2164,6 @@ static void print_status_info(UnitStatusInfo *i) { printf(")%s\n", off); - on = off = NULL; - if (i->main_pid == p->pid && i->start_timestamp == p->start_timestamp && i->exit_timestamp == p->start_timestamp) @@ -2281,6 +2295,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn i->what = s; else if (streq(name, "Following")) i->following = s; + else if (streq(name, "UnitFileState")) + i->unit_file_state = s; } break; @@ -2392,6 +2408,30 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn break; } + + case DBUS_TYPE_STRUCT: { + + if (streq(name, "LoadError")) { + DBusMessageIter sub; + const char *n, *message; + int r; + + dbus_message_iter_recurse(iter, &sub); + + r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true); + if (r < 0) + return r; + + r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false); + if (r < 0) + return r; + + if (!isempty(message)) + i->load_error = message; + } + + break; + } } return 0; @@ -2432,6 +2472,16 @@ static int print_property(const char *name, DBusMessageIter *iter) { if (arg_all || s[0]) printf("%s=%s\n", name, s); + return 0; + } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) { + const char *a = NULL, *b = NULL; + + if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0) + bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false); + + if (arg_all || !isempty(a) || !isempty(b)) + printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b)); + return 0; } @@ -2452,7 +2502,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 && bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0) - printf("EnvironmentFile=%s (ignore=%s)\n", path, yes_no(ignore)); + printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore)); dbus_message_iter_next(&sub); } @@ -2503,6 +2553,30 @@ 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, "ControlGroupAttributes")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *controller, *attr, *value; + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 && + 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", + controller, + attr, + value); + } + + dbus_message_iter_next(&sub); + } + + return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) { DBusMessageIter sub; @@ -2517,7 +2591,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { t = strv_join(info.argv, " "); - printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", + printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", name, strna(info.path), strna(t), @@ -3163,7 +3237,7 @@ finish: } static int reset_failed(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int r; DBusError error; char **name; @@ -3175,6 +3249,7 @@ static int reset_failed(DBusConnection *bus, char **args) { return daemon_reload(bus, args); STRV_FOREACH(name, args+1) { + DBusMessage *reply; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -3211,9 +3286,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; @@ -3862,6 +3934,7 @@ static int systemctl_help(void) { " --no-wall Don't send wall message before halt/power-off/reboot\n" " --no-reload When enabling/disabling unit files, don't reload daemon\n" " configuration\n" + " --no-legend Do not print a legend (column headers and hints)\n" " --no-pager Do not pipe output into a pager\n" " --no-ask-password\n" " Do not ask for system passwords\n" @@ -4012,6 +4085,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_SYSTEM, ARG_GLOBAL, ARG_NO_BLOCK, + ARG_NO_LEGEND, ARG_NO_PAGER, ARG_NO_WALL, ARG_ORDER, @@ -4040,6 +4114,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, { "no-block", no_argument, NULL, ARG_NO_BLOCK }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-wall", no_argument, NULL, ARG_NO_WALL }, { "quiet", no_argument, NULL, 'q' }, @@ -4128,6 +4203,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_no_block = true; break; + case ARG_NO_LEGEND: + arg_no_legend = true; + break; + case ARG_NO_PAGER: arg_no_pager = true; break; @@ -4360,18 +4439,6 @@ static int parse_time_spec(const char *t, usec_t *_u) { return 0; } -static bool kexec_loaded(void) { - bool loaded = false; - char *s; - - if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { - if (s[0] == '1') - loaded = true; - free(s); - } - return loaded; -} - static int shutdown_parse_argv(int argc, char *argv[]) { enum { @@ -4926,8 +4993,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError return 0; } + if (!bus) { + log_error("Failed to get D-Bus connection: %s", + dbus_error_is_set(error) ? error->message : "No connection to service manager."); + return -EIO; + } + + } else { + if (!bus && !avoid_bus()) { - log_error("Failed to get D-Bus connection: %s", error->message); + log_error("Failed to get D-Bus connection: %s", + dbus_error_is_set(error) ? error->message : "No connection to service manager."); return -EIO; } } @@ -4983,7 +5059,7 @@ static int reload_with_fallback(DBusConnection *bus) { if (bus) { /* First, try systemd via D-Bus. */ - if (daemon_reload(bus, NULL) > 0) + if (daemon_reload(bus, NULL) >= 0) return 0; }