X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=0887bc397727f35cac2eccf4b61d947c89b32e3f;hb=dedabea4b3d61a87cedb5c8d7ccce5b86ea84afe;hp=45833da16c59b09b2240b3061837827e24fd9e69;hpb=1238ee09b7babb175b9bf7ad1d0e8eb2a414ee6e;p=elogind.git diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 45833da16..0887bc397 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -341,7 +341,7 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) { } static int output_units_list(const UnitInfo *unit_infos, unsigned c) { - unsigned id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len; + unsigned circle_len = 0, id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len; const UnitInfo *u; unsigned n_shown = 0; int job_count = 0; @@ -363,13 +363,18 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { job_len = MAX(job_len, strlen(u->job_type)); job_count++; } + + if (!arg_no_legend && + (streq(u->active_state, "failed") || + STR_IN_SET(u->load_state, "error", "not-found", "masked"))) + circle_len = 2; } if (!arg_full && original_stdout_is_tty) { unsigned basic_len; id_len = MIN(max_id_len, 25u); - basic_len = 5 + id_len + 5 + active_len + sub_len; + basic_len = circle_len + 5 + id_len + 5 + active_len + sub_len; if (job_count) basic_len += job_len + 1; @@ -397,11 +402,17 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { for (u = unit_infos; u < unit_infos + c; u++) { _cleanup_free_ char *e = NULL, *j = NULL; - const char *on_loaded, *off_loaded, *on = ""; - const char *on_active, *off_active, *off = ""; + const char *on_loaded = "", *off_loaded = ""; + const char *on_active = "", *off_active = ""; + const char *on_circle = "", *off_circle = ""; const char *id; + bool circle = false; if (!n_shown && !arg_no_legend) { + + if (circle_len > 0) + fputs(" ", stdout); + printf("%-*s %-*s %-*s %-*s ", id_len, "UNIT", load_len, "LOAD", @@ -419,18 +430,18 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { n_shown++; - if (streq(u->load_state, "error") || - streq(u->load_state, "not-found")) { - on_loaded = on = ansi_highlight_red(); - off_loaded = off = ansi_highlight_off(); - } else - on_loaded = off_loaded = ""; + if (STR_IN_SET(u->load_state, "error", "not-found", "masked")) { + on_loaded = ansi_highlight_red(); + on_circle = ansi_highlight_yellow(); + off_loaded = off_circle = ansi_highlight_off(); + circle = true; + } if (streq(u->active_state, "failed")) { - on_active = on = ansi_highlight_red(); - off_active = off = ansi_highlight_off(); - } else - on_active = off_active = ""; + on_circle = on_active = ansi_highlight_red(); + off_circle = off_active = ansi_highlight_off(); + circle = true; + } if (u->machine) { j = strjoin(u->machine, ":", u->id, NULL); @@ -449,8 +460,11 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { id = e; } + if (circle_len > 0) + printf("%s%s%s", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle); + printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s", - on, id_len, id, off, + on_active, id_len, id, off_active, on_loaded, load_len, u->load_state, off_loaded, on_active, active_len, u->active_state, sub_len, u->sub_state, off_active, @@ -466,7 +480,8 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { const char *on, *off; if (n_shown) { - puts("\nLOAD = Reflects whether the unit definition was properly loaded.\n" + puts("\n" + "LOAD = 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."); puts(job_count ? "JOB = Pending job for the unit.\n" : ""); @@ -932,9 +947,39 @@ static int get_next_elapse( return 0; } +static int get_last_trigger( + sd_bus *bus, + const char *path, + usec_t *last) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(path); + assert(last); + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Timer", + "LastTriggerUSec", + &error, + 't', + last); + if (r < 0) { + log_error("Failed to get last trigger time: %s", bus_error_message(&error, r)); + return r; + } + + return 0; +} + struct timer_info { const char* id; usec_t next_elapse; + usec_t last_trigger; char** triggered; }; @@ -955,6 +1000,8 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) { unsigned nextlen = strlen("NEXT"), leftlen = strlen("LEFT"), + lastlen = strlen("LAST"), + passedlen = strlen("PASSED"), unitlen = strlen("UNIT"), activatelen = strlen("ACTIVATES"); @@ -976,30 +1023,47 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) { leftlen = MAX(leftlen, strlen(trel)); } + if (t->last_trigger > 0) { + char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = ""; + + format_timestamp(tstamp, sizeof(tstamp), t->last_trigger); + lastlen = MAX(lastlen, strlen(tstamp) + 1); + + format_timestamp_relative(trel, sizeof(trel), t->last_trigger); + passedlen = MAX(passedlen, strlen(trel)); + } + unitlen = MAX(unitlen, strlen(t->id)); STRV_FOREACH(a, t->triggered) ul += strlen(*a) + 2*(a != t->triggered); + activatelen = MAX(activatelen, ul); } if (n > 0) { if (!arg_no_legend) - printf("%-*s %-*s %-*s %s\n", - nextlen, "NEXT", - leftlen, "LEFT", - unitlen, "UNIT", - "ACTIVATES"); + printf("%-*s %-*s %-*s %-*s %-*s %s\n", + nextlen, "NEXT", + leftlen, "LEFT", + lastlen, "LAST", + passedlen, "PASSED", + unitlen, "UNIT", + "ACTIVATES"); for (t = timer_infos; t < timer_infos + n; t++) { - char tstamp[FORMAT_TIMESTAMP_MAX] = "n/a", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a"; + char tstamp1[FORMAT_TIMESTAMP_MAX] = "n/a", trel1[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a"; + char tstamp2[FORMAT_TIMESTAMP_MAX] = "n/a", trel2[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a"; char **a; - format_timestamp(tstamp, sizeof(tstamp), t->next_elapse); - format_timestamp_relative(trel, sizeof(trel), t->next_elapse); + format_timestamp(tstamp1, sizeof(tstamp1), t->next_elapse); + format_timestamp_relative(trel1, sizeof(trel1), t->next_elapse); + + format_timestamp(tstamp2, sizeof(tstamp2), t->last_trigger); + format_timestamp_relative(trel2, sizeof(trel2), t->last_trigger); - printf("%-*s %-*s %-*s", - nextlen, tstamp, leftlen, trel, unitlen, t->id); + printf("%-*s %-*s %-*s %-*s %-*s", + nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, t->id); STRV_FOREACH(a, t->triggered) printf("%s %s", @@ -1073,7 +1137,7 @@ static int list_timers(sd_bus *bus, char **args) { for (u = unit_infos; u < unit_infos + n; u++) { _cleanup_strv_free_ char **triggered = NULL; dual_timestamp next = {}; - usec_t m; + usec_t m, last = 0; if (!endswith(u->id, ".timer")) continue; @@ -1086,6 +1150,8 @@ static int list_timers(sd_bus *bus, char **args) { if (r < 0) goto cleanup; + get_last_trigger(bus, u->unit_path, &last); + if (!GREEDY_REALLOC(timer_infos, size, c+1)) { r = log_oom(); goto cleanup; @@ -1096,6 +1162,7 @@ static int list_timers(sd_bus *bus, char **args) { timer_infos[c++] = (struct timer_info) { .id = u->id, .next_elapse = m, + .last_trigger = last, .triggered = triggered, }; @@ -1567,7 +1634,7 @@ static int compare_machine_info(const void *a, const void *b) { const struct machine_info *u = a, *v = b; if (u->is_host != v->is_host) - return u->is_host > v->is_host ? 1 : -1; + return u->is_host > v->is_host ? -1 : 1; return strcasecmp(u->name, v->name); } @@ -1670,6 +1737,7 @@ static int get_machine_list( static void output_machines_list(struct machine_info *machine_infos, unsigned n) { struct machine_info *m; unsigned + circle_len = 0, namelen = sizeof("NAME") - 1, statelen = sizeof("STATE") - 1, failedlen = sizeof("FAILED") - 1, @@ -1682,26 +1750,36 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n) statelen = MAX(statelen, m->state ? strlen(m->state) : 0); failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units)); jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs)); + + if (!arg_no_legend && !streq_ptr(m->state, "running")) + circle_len = 2; } - if (!arg_no_legend) + if (!arg_no_legend) { + if (circle_len > 0) + fputs(" ", stdout); + printf("%-*s %-*s %-*s %-*s\n", namelen, "NAME", statelen, "STATE", failedlen, "FAILED", jobslen, "JOBS"); + } for (m = machine_infos; m < machine_infos + n; m++) { - const char *on_state, *off_state, *on_failed, *off_failed; + const char *on_state = "", *off_state = ""; + const char *on_failed = "", *off_failed = ""; + bool circle = false; if (streq_ptr(m->state, "degraded")) { on_state = ansi_highlight_red(); off_state = ansi_highlight_off(); + circle = true; } else if (!streq_ptr(m->state, "running")) { on_state = ansi_highlight_yellow(); off_state = ansi_highlight_off(); - } else - on_state = off_state = ""; + circle = true; + } if (m->n_failed_units > 0) { on_failed = ansi_highlight_red(); @@ -1709,6 +1787,9 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n) } else on_failed = off_failed = ""; + if (circle_len > 0) + printf("%s%s%s", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state); + if (m->is_host) printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n", (int) (namelen - (sizeof(" (host)")-1)), strna(m->name),