From 551d0afe2e471e67e7a23353c8ffc1b0bacaf97f Mon Sep 17 00:00:00 2001 From: David Tardon Date: Sat, 23 Jul 2022 17:07:52 +0200 Subject: [PATCH 1/7] systemctl: reduce var. scope and shorten the code a bit --- src/systemctl/systemctl-list-units.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index 5b0ce3854d..a6596ddd0e 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -350,7 +350,6 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { _cleanup_(table_unrefp) Table *table = NULL; - const char *on, *off; int r; table = table_new("listen", "type", "unit", "activates"); @@ -401,14 +400,7 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { r = table_add_cell(table, NULL, TABLE_STRV, s->triggered); if (r < 0) return table_log_add_error(r); - } - - on = ansi_highlight(); - off = ansi_normal(); - } else { - on = ansi_highlight_red(); - off = ansi_normal(); } r = output_table(table); @@ -416,6 +408,11 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { return r; if (arg_legend != 0) { + const char *on, *off; + + on = cs > 0 ? ansi_highlight() : ansi_highlight_red(); + off = ansi_normal(); + printf("\n%s%zu sockets listed.%s\n", on, cs, off); if (!arg_all) printf("Pass --all to see loaded but inactive sockets, too.\n"); @@ -599,7 +596,6 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf static int output_timers_list(struct timer_info *timer_infos, size_t n) { _cleanup_(table_unrefp) Table *table = NULL; - const char *on, *off; int r; assert(timer_infos || n == 0); @@ -641,19 +637,16 @@ static int output_timers_list(struct timer_info *timer_infos, size_t n) { return table_log_add_error(r); } - if (n > 0) { - on = ansi_highlight(); - off = ansi_normal(); - } else { - on = ansi_highlight_red(); - off = ansi_normal(); - } - r = output_table(table); if (r < 0) return r; if (arg_legend != 0) { + const char *on, *off; + + on = n > 0 ? ansi_highlight() : ansi_highlight_red(); + off = ansi_normal(); + printf("\n%s%zu timers listed.%s\n", on, n, off); if (!arg_all) printf("Pass --all to see loaded but inactive timers, too.\n"); From 25facd0384bc6aefe7accabb50796c765a26c160 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Mon, 25 Jul 2022 09:28:31 +0200 Subject: [PATCH 2/7] systemctl: drop unneeded condition --- src/systemctl/systemctl-list-units.c | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index a6596ddd0e..96bc4d47ea 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -352,6 +352,8 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { _cleanup_(table_unrefp) Table *table = NULL; int r; + assert(socket_infos || cs == 0); + table = table_new("listen", "type", "unit", "activates"); if (!table) return log_oom(); @@ -369,38 +371,36 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { (void) table_set_empty_string(table, "-"); - if (cs > 0) { - for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) { - _cleanup_free_ char *j = NULL; - const char *path; + for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) { + _cleanup_free_ char *j = NULL; + const char *path; - if (s->machine) { - j = strjoin(s->machine, ":", s->path); - if (!j) - return log_oom(); - path = j; - } else - path = s->path; + if (s->machine) { + j = strjoin(s->machine, ":", s->path); + if (!j) + return log_oom(); + path = j; + } else + path = s->path; - r = table_add_many(table, - TABLE_STRING, path, - TABLE_STRING, s->type, - TABLE_STRING, s->id); - if (r < 0) - return table_log_add_error(r); + r = table_add_many(table, + TABLE_STRING, path, + TABLE_STRING, s->type, + TABLE_STRING, s->id); + if (r < 0) + return table_log_add_error(r); - if (strv_isempty(s->triggered)) - r = table_add_cell(table, NULL, TABLE_EMPTY, NULL); - else if (strv_length(s->triggered) == 1) - r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]); - else - /* This should never happen, currently our socket units can only trigger a - * single unit. But let's handle this anyway, who knows what the future - * brings? */ - r = table_add_cell(table, NULL, TABLE_STRV, s->triggered); - if (r < 0) - return table_log_add_error(r); - } + if (strv_isempty(s->triggered)) + r = table_add_cell(table, NULL, TABLE_EMPTY, NULL); + else if (strv_length(s->triggered) == 1) + r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]); + else + /* This should never happen, currently our socket units can only trigger a + * single unit. But let's handle this anyway, who knows what the future + * brings? */ + r = table_add_cell(table, NULL, TABLE_STRV, s->triggered); + if (r < 0) + return table_log_add_error(r); } r = output_table(table); From 11d6270b42511168efa38e57b496c123503ed00d Mon Sep 17 00:00:00 2001 From: David Tardon Date: Mon, 25 Jul 2022 09:23:49 +0200 Subject: [PATCH 3/7] systemctl: extract output of legend to a function --- src/systemctl/systemctl-list-units.c | 37 +++++++++++++--------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index 96bc4d47ea..fe1bf2f0a5 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -87,6 +87,19 @@ static int get_unit_list_recursive( return c; } +static void output_legend(const char *type, size_t n_items) { + const char *on, *off; + + assert(type); + + on = n_items > 0 ? ansi_highlight() : ansi_highlight_red(); + off = ansi_normal(); + + printf("\n%s%zu %ss listed.%s\n", on, n_items, type, off); + if (!arg_all) + printf("Pass --all to see loaded but inactive %ss, too.\n", type); +} + static int output_units_list(const UnitInfo *unit_infos, size_t c) { _cleanup_(table_unrefp) Table *table = NULL; size_t job_count = 0; @@ -407,16 +420,8 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { if (r < 0) return r; - if (arg_legend != 0) { - const char *on, *off; - - on = cs > 0 ? ansi_highlight() : ansi_highlight_red(); - off = ansi_normal(); - - printf("\n%s%zu sockets listed.%s\n", on, cs, off); - if (!arg_all) - printf("Pass --all to see loaded but inactive sockets, too.\n"); - } + if (arg_legend != 0) + output_legend("socket", cs); return 0; } @@ -641,16 +646,8 @@ static int output_timers_list(struct timer_info *timer_infos, size_t n) { if (r < 0) return r; - if (arg_legend != 0) { - const char *on, *off; - - on = n > 0 ? ansi_highlight() : ansi_highlight_red(); - off = ansi_normal(); - - printf("\n%s%zu timers listed.%s\n", on, n, off); - if (!arg_all) - printf("Pass --all to see loaded but inactive timers, too.\n"); - } + if (arg_legend != 0) + output_legend("timer", n); return 0; } From 0f787940b7d60429a1127d9898075d398c4f0384 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Mon, 25 Jul 2022 09:32:16 +0200 Subject: [PATCH 4/7] systemctl: simplify var. definition a bit --- src/systemctl/systemctl-list-units.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index fe1bf2f0a5..80defede91 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -200,13 +200,11 @@ static int output_units_list(const UnitInfo *unit_infos, size_t c) { "SUB = The low-level unit activation state, values depend on unit type."); if (job_count > 0) puts("JOB = Pending job for the unit.\n"); - on = ansi_highlight(); - off = ansi_normal(); - } else { - on = ansi_highlight_red(); - off = ansi_normal(); } + on = records > 0 ? ansi_highlight() : ansi_highlight_red(); + off = ansi_normal(); + if (arg_all || strv_contains(arg_states, "inactive")) printf("%s%zu loaded units listed.%s\n" "To show all installed unit files use 'systemctl list-unit-files'.\n", From ed462ea3fa3b85b15ca6f672eb0aa87236d3d67b Mon Sep 17 00:00:00 2001 From: David Tardon Date: Fri, 15 Jul 2022 15:58:06 +0200 Subject: [PATCH 5/7] systemctl: add list-automounts verb Fixes: #6056 --- src/systemctl/systemctl-list-units.c | 184 +++++++++++++++++++++++++++ src/systemctl/systemctl-list-units.h | 1 + src/systemctl/systemctl.c | 3 + 3 files changed, 188 insertions(+) diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index 80defede91..5a1311f5ea 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -3,6 +3,7 @@ #include "sd-login.h" #include "bus-error.h" +#include "bus-locator.h" #include "format-table.h" #include "locale-util.h" #include "set.h" @@ -748,3 +749,186 @@ int verb_list_timers(int argc, char *argv[], void *userdata) { return r; } + +struct automount_info { + const char *machine; + const char *id; + char *what; + char *where; + usec_t timeout_idle_usec; + bool mounted; +}; + +static int automount_info_compare(const struct automount_info *a, const struct automount_info *b) { + int r; + + assert(a); + assert(b); + + r = strcasecmp_ptr(a->machine, b->machine); + if (r != 0) + return r; + + return strcmp(a->where, b->where); +} + +static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct automount_info *ret_info) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *mount = NULL, *mount_path = NULL, *where = NULL, *what = NULL, *state = NULL; + usec_t timeout_idle_usec; + BusLocator locator; + int r; + + assert(bus); + assert(info); + assert(ret_info); + + locator = (BusLocator) { + .destination = "org.freedesktop.systemd1", + .path = info->unit_path, + .interface = "org.freedesktop.systemd1.Automount", + }; + + r = bus_get_property_string(bus, &locator, "Where", &error, &where); + if (r < 0) + return log_error_errno(r, "Failed to get automount target: %s", bus_error_message(&error, r)); + + r = bus_get_property_trivial(bus, &locator, "TimeoutIdleUSec", &error, 't', &timeout_idle_usec); + if (r < 0) + return log_error_errno(r, "Failed to get idle timeout: %s", bus_error_message(&error, r)); + + r = unit_name_from_path(where, ".mount", &mount); + if (r < 0) + return log_error_errno(r, "Failed to generate unit name from path: %m"); + + mount_path = unit_dbus_path_from_name(mount); + if (!mount_path) + return log_oom(); + + locator.path = mount_path; + locator.interface = "org.freedesktop.systemd1.Mount"; + + r = bus_get_property_string(bus, &locator, "What", &error, &what); + if (r < 0) + return log_error_errno(r, "Failed to get mount source: %s", bus_error_message(&error, r)); + + locator.interface = "org.freedesktop.systemd1.Unit"; + + r = bus_get_property_string(bus, &locator, "ActiveState", &error, &state); + if (r < 0) + return log_error_errno(r, "Failed to get mount state: %s", bus_error_message(&error, r)); + + *ret_info = (struct automount_info) { + .machine = info->machine, + .id = info->id, + .what = TAKE_PTR(what), + .where = TAKE_PTR(where), + .timeout_idle_usec = timeout_idle_usec, + .mounted = streq_ptr(state, "active"), + }; + + return 0; +} + +static int output_automounts_list(struct automount_info *infos, size_t n_infos) { + _cleanup_(table_unrefp) Table *table = NULL; + int r; + + assert(infos || n_infos == 0); + + table = table_new("what", "where", "mounted", "idle timeout", "unit"); + if (!table) + return log_oom(); + + table_set_header(table, arg_legend != 0); + if (arg_full) + table_set_width(table, 0); + + (void) table_set_empty_string(table, "-"); + + for (struct automount_info *info = infos; info < infos + n_infos; info++) { + _cleanup_free_ char *j = NULL; + const char *unit; + + if (info->machine) { + j = strjoin(info->machine, ":", info->id); + if (!j) + return log_oom(); + unit = j; + } else + unit = info->id; + + r = table_add_many(table, + TABLE_STRING, info->what, + TABLE_STRING, info->where, + TABLE_BOOLEAN, info->mounted, + TABLE_TIMESPAN_MSEC, info->timeout_idle_usec, + TABLE_STRING, unit); + if (r < 0) + return table_log_add_error(r); + } + + r = output_table(table); + if (r < 0) + return r; + + if (arg_legend != 0) + output_legend("automount", n_infos); + + return 0; +} + +int verb_list_automounts(int argc, char *argv[], void *userdata) { + _cleanup_(message_set_freep) Set *replies = NULL; + _cleanup_strv_free_ char **machines = NULL, **automounts = NULL; + _cleanup_free_ UnitInfo *unit_infos = NULL; + _cleanup_free_ struct automount_info *automount_infos = NULL; + size_t c = 0; + int r, n; + sd_bus *bus; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + pager_open(arg_pager_flags); + + r = expand_unit_names(bus, strv_skip(argv, 1), ".automount", &automounts, NULL); + if (r < 0) + return r; + + if (argc == 1 || automounts) { + n = get_unit_list_recursive(bus, automounts, &unit_infos, &replies, &machines); + if (n < 0) + return n; + + for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { + if (!endswith(u->id, ".automount")) + continue; + + if (!GREEDY_REALLOC(automount_infos, c + 1)) { + r = log_oom(); + goto cleanup; + } + + r = collect_automount_info(bus, u, &automount_infos[c]); + if (r < 0) + goto cleanup; + + c++; + } + + typesafe_qsort(automount_infos, c, automount_info_compare); + } + + output_automounts_list(automount_infos, c); + + cleanup: + assert(c == 0 || automount_infos); + for (struct automount_info *info = automount_infos; info < automount_infos + c; info++) { + free(info->what); + free(info->where); + } + + return r; +} diff --git a/src/systemctl/systemctl-list-units.h b/src/systemctl/systemctl-list-units.h index 7f4cee0d10..117b7e378a 100644 --- a/src/systemctl/systemctl-list-units.h +++ b/src/systemctl/systemctl-list-units.h @@ -4,5 +4,6 @@ int verb_list_units(int argc, char *argv[], void *userdata); int verb_list_sockets(int argc, char *argv[], void *userdata); int verb_list_timers(int argc, char *argv[], void *userdata); +int verb_list_automounts(int argc, char *argv[], void *userdata); usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index fa32c67a08..fb40c478c2 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -138,6 +138,8 @@ static int systemctl_help(void) { "%5$sQuery or send control commands to the system manager.%6$s\n" "\n%3$sUnit Commands:%4$s\n" " list-units [PATTERN...] List units currently in memory\n" + " list-automounts [PATTERN...] List automount units currently in memory,\n" + " ordered by path\n" " list-sockets [PATTERN...] List socket units currently in memory,\n" " ordered by address\n" " list-timers [PATTERN...] List timer units currently in memory,\n" @@ -1022,6 +1024,7 @@ static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, verb_list_units }, { "list-unit-files", VERB_ANY, VERB_ANY, 0, verb_list_unit_files }, + { "list-automounts", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_automounts }, { "list-sockets", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_sockets }, { "list-timers", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_timers }, { "list-jobs", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_jobs }, From 2d5cdc622484e07986f03c51eea75e3db6d8e550 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Fri, 15 Jul 2022 16:07:31 +0200 Subject: [PATCH 6/7] man: document systemctl list-automounts --- man/systemctl.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/man/systemctl.xml b/man/systemctl.xml index 42dd667aa9..483db5179c 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -108,6 +108,25 @@ To show all installed unit files use 'systemctl list-unit-files'. + + list-automounts PATTERN… + + + List automount units currently in memory, ordered by mount path. If one or more + PATTERNs are specified, only automount units matching one of them are shown. + Produces output similar to + +WHAT WHERE MOUNTED IDLE TIMEOUT UNIT +/dev/sdb1 /mnt/test no 120s mnt-test.automount +binfmt_misc /proc/sys/fs/binfmt_misc yes 0 proc-sys-fs-binfmt_misc.automount + +2 automounts listed. + + + Also see , , and . + + + list-sockets PATTERN… From 5edea3b77ededc32d05f93f049be014abb41477a Mon Sep 17 00:00:00 2001 From: David Tardon Date: Fri, 22 Jul 2022 17:07:56 +0200 Subject: [PATCH 7/7] shell-completion: add systemctl list-automounts --- shell-completion/bash/systemctl.in | 2 +- shell-completion/zsh/_systemctl.in | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index b61f88b012..c8ca2882c0 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -215,7 +215,7 @@ _systemctl () { suspend-then-hibernate kexec list-jobs list-sockets list-timers list-units list-unit-files poweroff reboot rescue show-environment suspend get-default - is-system-running preset-all' + is-system-running preset-all list-automounts' [FILE]='link switch-root bind mount-image' [TARGETS]='set-default' [MACHINES]='list-machines' diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 6fbe8737c2..8b8c59e0d7 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -7,6 +7,7 @@ local -a unit_commands=( # Unit Commands + "list-automounts:List automounts" "list-sockets:List sockets" "list-timers:List timers" "list-units:List units"