summaryrefslogtreecommitdiff
path: root/src/systemctl/systemctl-list-units.c
diff options
context:
space:
mode:
authorDavid Tardon <dtardon@redhat.com>2022-07-15 15:58:06 +0200
committerDavid Tardon <dtardon@redhat.com>2022-07-25 13:37:19 +0200
commited462ea3fa3b85b15ca6f672eb0aa87236d3d67b (patch)
treed3eba2e73a5b82fe2adf56c71848252eb4850a7f /src/systemctl/systemctl-list-units.c
parent0f787940b7d60429a1127d9898075d398c4f0384 (diff)
downloadsystemd-ed462ea3fa3b85b15ca6f672eb0aa87236d3d67b.tar.gz
systemctl: add list-automounts verb
Fixes: #6056
Diffstat (limited to 'src/systemctl/systemctl-list-units.c')
-rw-r--r--src/systemctl/systemctl-list-units.c184
1 files changed, 184 insertions, 0 deletions
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;
+}