From 965c5d1d5a4d3a29d34d262f1528a318b9f295ac Mon Sep 17 00:00:00 2001 From: Kevin Kuehler Date: Mon, 4 Nov 2019 14:48:06 -0800 Subject: [PATCH 1/3] systemctl: Add TriggeredBy and Triggers to status For all units that aren't timers, if it is activated by another unit, add the triggering unit under the "TriggeredBy:" header. If a unit can trigger other units, print the units it triggers other the "Triggers:" header. --- TODO | 1 - src/systemctl/systemctl.c | 70 ++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/TODO b/TODO index 03d38da9a0..64068a8803 100644 --- a/TODO +++ b/TODO @@ -1107,7 +1107,6 @@ External: - - should complete options, but currently does not - systemctl add-wants,add-requires -* systemctl status foo.service should say that it is trigger by foo.timer * systemctl status should know about 'systemd-analyze calendar ... --iterations=' * If timer has just OnInactiveSec=..., it should fire after a specified time after being started. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 3fabbb665c..c8c22b2591 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4054,6 +4054,9 @@ typedef struct UnitStatusInfo { char **dropin_paths; + char **triggered_by; + char **triggers; + const char *load_error; const char *result; @@ -4138,6 +4141,8 @@ static void unit_status_info_free(UnitStatusInfo *info) { strv_free(info->documentation); strv_free(info->dropin_paths); + strv_free(info->triggered_by); + strv_free(info->triggers); strv_free(info->listen); while ((c = info->conditions)) { @@ -4151,6 +4156,17 @@ static void unit_status_info_free(UnitStatusInfo *info) { } } +static void format_active_state(const char *active_state, const char **active_on, const char **active_off) { + if (streq_ptr(active_state, "failed")) { + *active_on = ansi_highlight_red(); + *active_off = ansi_normal(); + } else if (STRPTR_IN_SET(active_state, "active", "reloading")) { + *active_on = ansi_highlight_green(); + *active_off = ansi_normal(); + } else + *active_on = *active_off = ""; +} + static void print_status_info( sd_bus *bus, UnitStatusInfo *i, @@ -4164,20 +4180,14 @@ static void print_status_info( const char *path; char **t, **t2; int r; + bool is_timer; assert(i); /* This shows pretty information about a unit. See * print_property() for a low-level property printer */ - if (streq_ptr(i->active_state, "failed")) { - active_on = ansi_highlight_red(); - active_off = ansi_normal(); - } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) { - active_on = ansi_highlight_green(); - active_off = ansi_normal(); - } else - active_on = active_off = ""; + format_active_state(i->active_state, &active_on, &active_off); printf("%s%s%s %s", active_on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), active_off, strna(i->id)); @@ -4282,7 +4292,28 @@ static void print_status_info( else printf("\n"); - if (endswith(i->id, ".timer")) { + is_timer = endswith(i->id, ".timer"); + + if (!is_timer && !strv_isempty(i->triggered_by)) { + char **trigger; + bool first = true; + + printf(" TriggeredBy:"); + STRV_FOREACH(trigger, i->triggered_by) { + UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; + + (void) get_state_one_unit(bus, *trigger, &state); + format_active_state(unit_active_state_to_string(state), &on, &off); + if (first) { + printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); + first = false; + } else { + printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); + } + } + } + + if (is_timer) { char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX], tstamp2[FORMAT_TIMESTAMP_MAX]; const char *next_rel_time, *next_time; @@ -4303,6 +4334,25 @@ static void print_status_info( printf("n/a\n"); } + if (!strv_isempty(i->triggers)) { + char **trigger; + bool first = true; + + printf(" Triggers:"); + STRV_FOREACH(trigger, i->triggers) { + UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; + + (void) get_state_one_unit(bus, *trigger, &state); + format_active_state(unit_active_state_to_string(state), &on, &off); + if (first) { + printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); + first = false; + } else { + printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); + } + } + } + if (!i->condition_result && i->condition_timestamp > 0) { UnitCondition *c; int n = 0; @@ -5514,6 +5564,8 @@ static int show_one( { "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) }, { "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) }, { "Result", "s", NULL, offsetof(UnitStatusInfo, result) }, + { "TriggeredBy", "as", NULL, offsetof(UnitStatusInfo, triggered_by) }, + { "Triggers", "as", NULL, offsetof(UnitStatusInfo, triggers) }, { "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) }, { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) }, { "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) }, From 0d588deae21234c9a9d64d9eddbcbe7da5c9a39d Mon Sep 17 00:00:00 2001 From: Kevin Kuehler Date: Mon, 4 Nov 2019 14:52:13 -0800 Subject: [PATCH 2/3] systemctl: Align all status outputs to TriggeredBy --- src/systemctl/systemctl.c | 76 +++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c8c22b2591..fe5da8422c 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4210,24 +4210,24 @@ static void print_status_info( path = formatted_path; if (!isempty(i->load_error)) - printf(" Loaded: %s%s%s (Reason: %s)\n", + printf(" Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error); else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) && !STR_IN_SET(i->unit_file_state, "generated", "transient")) - printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n", + printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n", on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset); else if (path && !isempty(i->unit_file_state)) - printf(" Loaded: %s%s%s (%s; %s)\n", + printf(" Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state); else if (path) - printf(" Loaded: %s%s%s (%s)\n", + printf(" Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path); else - printf(" Loaded: %s%s%s\n", + printf(" Loaded: %s%s%s\n", on, strna(i->load_state), off); if (i->transient) - printf("Transient: yes\n"); + printf(" Transient: yes\n"); if (!strv_isempty(i->dropin_paths)) { _cleanup_free_ char *dir = NULL; @@ -4239,8 +4239,8 @@ static void print_status_info( const char *df; if (!dir || last) { - printf(dir ? " " : - " Drop-In: "); + printf(dir ? " " : + " Drop-In: "); dir = mfree(dir); @@ -4251,7 +4251,7 @@ static void print_status_info( } printf("%s\n" - " %s", dir, + " %s", dir, special_glyph(SPECIAL_GLYPH_TREE_RIGHT)); } @@ -4268,10 +4268,10 @@ static void print_status_info( ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state; if (ss) - printf(" Active: %s%s (%s)%s", + printf(" Active: %s%s (%s)%s", active_on, strna(i->active_state), ss, active_off); else - printf(" Active: %s%s%s", + printf(" Active: %s%s%s", active_on, strna(i->active_state), active_off); if (!isempty(i->result) && !streq(i->result, "success")) @@ -4298,7 +4298,7 @@ static void print_status_info( char **trigger; bool first = true; - printf(" TriggeredBy:"); + printf("TriggeredBy:"); STRV_FOREACH(trigger, i->triggered_by) { UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; @@ -4308,7 +4308,7 @@ static void print_status_info( printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); first = false; } else { - printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); + printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); } } } @@ -4321,7 +4321,7 @@ static void print_status_info( i->next_elapse_monotonic}; usec_t next_elapse; - printf(" Trigger: "); + printf(" Trigger: "); dual_timestamp_get(&nw); next_elapse = calc_next_elapse(&nw, &next); @@ -4338,7 +4338,7 @@ static void print_status_info( char **trigger; bool first = true; - printf(" Triggers:"); + printf(" Triggers:"); STRV_FOREACH(trigger, i->triggers) { UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; @@ -4348,7 +4348,7 @@ static void print_status_info( printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); first = false; } else { - printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); + printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); } } } @@ -4360,7 +4360,7 @@ static void print_status_info( s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp); s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); - printf("Condition: start %scondition failed%s at %s%s%s\n", + printf(" Condition: start %scondition failed%s at %s%s%s\n", ansi_highlight_yellow(), ansi_normal(), s2, s1 ? "; " : "", strempty(s1)); @@ -4370,7 +4370,7 @@ static void print_status_info( LIST_FOREACH(conditions, c, i->conditions) if (c->tristate < 0) - printf(" %s %s=%s%s%s was not met\n", + printf(" %s %s=%s%s%s was not met\n", --n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT), c->name, c->trigger ? "|" : "", @@ -4382,24 +4382,24 @@ static void print_status_info( s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp); s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp); - printf(" Assert: start %sassertion failed%s at %s%s%s\n", + printf(" Assert: start %sassertion failed%s at %s%s%s\n", ansi_highlight_red(), ansi_normal(), s2, s1 ? "; " : "", strempty(s1)); if (i->failed_assert_trigger) - printf(" none of the trigger assertions were met\n"); + printf(" none of the trigger assertions were met\n"); else if (i->failed_assert) - printf(" %s=%s%s was not met\n", + printf(" %s=%s%s was not met\n", i->failed_assert, i->failed_assert_negate ? "!" : "", i->failed_assert_parameter); } if (i->sysfs_path) - printf(" Device: %s\n", i->sysfs_path); + printf(" Device: %s\n", i->sysfs_path); if (i->where) - printf(" Where: %s\n", i->where); + printf(" Where: %s\n", i->where); if (i->what) - printf(" What: %s\n", i->what); + printf(" What: %s\n", i->what); STRV_FOREACH(t, i->documentation) { _cleanup_free_ char *formatted = NULL; @@ -4410,16 +4410,16 @@ static void print_status_info( else q = *t; - printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q); + printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q); } STRV_FOREACH_PAIR(t, t2, i->listen) - printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t); + printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t); if (i->accept) { - printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections); + printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections); if (i->n_refused) - printf(" Refused: %u", i->n_refused); + printf(" Refused: %u", i->n_refused); printf("\n"); } @@ -4437,7 +4437,7 @@ static void print_status_info( continue; argv = strv_join(p->argv, " "); - printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv)); + printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv)); good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL); if (!good) { @@ -4474,7 +4474,7 @@ static void print_status_info( if (i->main_pid > 0 || i->control_pid > 0) { if (i->main_pid > 0) { - printf(" Main PID: "PID_FMT, i->main_pid); + printf(" Main PID: "PID_FMT, i->main_pid); if (i->running) { @@ -4526,14 +4526,14 @@ static void print_status_info( } if (i->status_text) - printf(" Status: \"%s\"\n", i->status_text); + printf(" Status: \"%s\"\n", i->status_text); if (i->status_errno > 0) - printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno)); + printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno)); if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) { char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX]; - printf(" IP: %s in, %s out\n", + printf(" IP: %s in, %s out\n", format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes), format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes)); } @@ -4541,13 +4541,13 @@ static void print_status_info( if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) { char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX]; - printf(" IO: %s read, %s written\n", + printf(" IO: %s read, %s written\n", format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes), format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes)); } if (i->tasks_current != (uint64_t) -1) { - printf(" Tasks: %" PRIu64, i->tasks_current); + printf(" Tasks: %" PRIu64, i->tasks_current); if (i->tasks_max != (uint64_t) -1) printf(" (limit: %" PRIu64 ")\n", i->tasks_max); @@ -4558,7 +4558,7 @@ static void print_status_info( if (i->memory_current != (uint64_t) -1) { char buf[FORMAT_BYTES_MAX]; - printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current)); + printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current)); if (i->memory_min > 0 || i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX || @@ -4598,7 +4598,7 @@ static void print_status_info( if (i->cpu_usage_nsec != (uint64_t) -1) { char buf[FORMAT_TIMESPAN_MAX]; - printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC)); + printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC)); } if (i->control_group) { @@ -4606,7 +4606,7 @@ static void print_status_info( static const char prefix[] = " "; unsigned c; - printf(" CGroup: %s\n", i->control_group); + printf(" CGroup: %s\n", i->control_group); c = columns(); if (c > sizeof(prefix) - 1) From bc9aa96bbddb82c776844626c189bec2bfb7e928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 5 Nov 2019 22:01:46 +0100 Subject: [PATCH 3/3] systemctl: simplify printing of Triggers/TriggeredBy --- src/systemctl/systemctl.c | 51 +++++++++++++-------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index fe5da8422c..50d1a2545f 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4180,7 +4180,6 @@ static void print_status_info( const char *path; char **t, **t2; int r; - bool is_timer; assert(i); @@ -4292,28 +4291,19 @@ static void print_status_info( else printf("\n"); - is_timer = endswith(i->id, ".timer"); + STRV_FOREACH(t, i->triggered_by) { + UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; - if (!is_timer && !strv_isempty(i->triggered_by)) { - char **trigger; - bool first = true; + (void) get_state_one_unit(bus, *t, &state); + format_active_state(unit_active_state_to_string(state), &on, &off); - printf("TriggeredBy:"); - STRV_FOREACH(trigger, i->triggered_by) { - UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; - - (void) get_state_one_unit(bus, *trigger, &state); - format_active_state(unit_active_state_to_string(state), &on, &off); - if (first) { - printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); - first = false; - } else { - printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); - } - } + printf("%s %s%s%s %s\n", + t == i->triggered_by ? "TriggeredBy:" : " ", + on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, + *t); } - if (is_timer) { + if (endswith(i->id, ".timer")) { char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX], tstamp2[FORMAT_TIMESTAMP_MAX]; const char *next_rel_time, *next_time; @@ -4334,23 +4324,16 @@ static void print_status_info( printf("n/a\n"); } - if (!strv_isempty(i->triggers)) { - char **trigger; - bool first = true; + STRV_FOREACH(t, i->triggers) { + UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; - printf(" Triggers:"); - STRV_FOREACH(trigger, i->triggers) { - UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID; + (void) get_state_one_unit(bus, *t, &state); + format_active_state(unit_active_state_to_string(state), &on, &off); - (void) get_state_one_unit(bus, *trigger, &state); - format_active_state(unit_active_state_to_string(state), &on, &off); - if (first) { - printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); - first = false; - } else { - printf(" %s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, *trigger); - } - } + printf("%s %s%s%s %s\n", + t == i->triggers ? " Triggers:" : " ", + on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, + *t); } if (!i->condition_result && i->condition_timestamp > 0) {