Merge pull request #26535 from yuwata/systemctl-list-cleanups
systemctl-list: several cleanups
This commit is contained in:
@@ -22,18 +22,16 @@ static int get_unit_list_recursive(
|
||||
sd_bus *bus,
|
||||
char **patterns,
|
||||
UnitInfo **ret_unit_infos,
|
||||
Set **ret_replies,
|
||||
char ***ret_machines) {
|
||||
Set **ret_replies) {
|
||||
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
_cleanup_(message_set_freep) Set *replies = NULL;
|
||||
sd_bus_message *reply;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
int c, r;
|
||||
|
||||
assert(bus);
|
||||
assert(ret_replies);
|
||||
assert(ret_unit_infos);
|
||||
assert(ret_machines);
|
||||
|
||||
replies = set_new(NULL);
|
||||
if (!replies)
|
||||
@@ -44,10 +42,9 @@ static int get_unit_list_recursive(
|
||||
return c;
|
||||
|
||||
r = set_put(replies, reply);
|
||||
if (r < 0) {
|
||||
sd_bus_message_unref(reply);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
TAKE_PTR(reply);
|
||||
|
||||
if (arg_recursive) {
|
||||
_cleanup_strv_free_ char **machines = NULL;
|
||||
@@ -73,15 +70,11 @@ static int get_unit_list_recursive(
|
||||
c = k;
|
||||
|
||||
r = set_put(replies, reply);
|
||||
if (r < 0) {
|
||||
sd_bus_message_unref(reply);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
TAKE_PTR(reply);
|
||||
}
|
||||
|
||||
*ret_machines = TAKE_PTR(machines);
|
||||
} else
|
||||
*ret_machines = NULL;
|
||||
}
|
||||
|
||||
*ret_unit_infos = TAKE_PTR(unit_infos);
|
||||
*ret_replies = TAKE_PTR(replies);
|
||||
@@ -239,7 +232,6 @@ static int output_units_list(const UnitInfo *unit_infos, size_t c) {
|
||||
int verb_list_units(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
_cleanup_(message_set_freep) Set *replies = NULL;
|
||||
_cleanup_strv_free_ char **machines = NULL;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
@@ -256,11 +248,11 @@ int verb_list_units(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = get_unit_list_recursive(bus, names, &unit_infos, &replies, &machines);
|
||||
r = get_unit_list_recursive(bus, names, &unit_infos, &replies);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
|
||||
r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -295,20 +287,79 @@ static int get_triggered_units(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_listening(
|
||||
typedef struct SocketInfo {
|
||||
const char *machine;
|
||||
const char* id;
|
||||
|
||||
char* type;
|
||||
char* path; /* absolute path or socket address */
|
||||
|
||||
/* Note: triggered is a list here, although it almost certainly will always be one
|
||||
* unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */
|
||||
char** triggered;
|
||||
} SocketInfo;
|
||||
|
||||
static void socket_info_array_free(SocketInfo *sockets, size_t n_sockets) {
|
||||
assert(sockets || n_sockets == 0);
|
||||
|
||||
for (SocketInfo *s = sockets; s < sockets + n_sockets; s++) {
|
||||
free(s->type);
|
||||
free(s->path);
|
||||
strv_free(s->triggered);
|
||||
}
|
||||
|
||||
free(sockets);
|
||||
}
|
||||
|
||||
static int socket_info_compare(const SocketInfo *a, const SocketInfo *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = strcasecmp_ptr(a->machine, b->machine);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CMP(path_is_absolute(a->path), path_is_absolute(b->path));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = path_is_absolute(a->path) ? path_compare(a->path, b->path) : strcmp(a->path, b->path);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return strcmp(a->type, b->type);
|
||||
}
|
||||
|
||||
static int socket_info_add(
|
||||
sd_bus *bus,
|
||||
const char* unit_path,
|
||||
char*** listening) {
|
||||
const UnitInfo *u,
|
||||
SocketInfo **sockets,
|
||||
size_t *n_sockets) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_strv_free_ char **triggered = NULL;
|
||||
const char *type, *path;
|
||||
int r, n = 0;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(u);
|
||||
assert(sockets);
|
||||
assert(n_sockets);
|
||||
|
||||
if (!endswith(u->id, ".socket"))
|
||||
return 0;
|
||||
|
||||
r = get_triggered_units(bus, u->unit_path, &triggered);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_get_property(
|
||||
bus,
|
||||
"org.freedesktop.systemd1",
|
||||
unit_path,
|
||||
u->unit_path,
|
||||
"org.freedesktop.systemd1.Socket",
|
||||
"Listen",
|
||||
&error,
|
||||
@@ -322,16 +373,31 @@ static int get_listening(
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
|
||||
_cleanup_free_ char *type_dup = NULL, *path_dup = NULL;
|
||||
_cleanup_strv_free_ char **triggered_dup = NULL;
|
||||
|
||||
r = strv_extend(listening, type);
|
||||
if (r < 0)
|
||||
type_dup = strdup(type);
|
||||
if (!type_dup)
|
||||
return log_oom();
|
||||
|
||||
r = strv_extend(listening, path);
|
||||
if (r < 0)
|
||||
path_dup = strdup(path);
|
||||
if (!path_dup)
|
||||
return log_oom();
|
||||
|
||||
n++;
|
||||
triggered_dup = strv_copy(triggered);
|
||||
if (!triggered_dup)
|
||||
return log_oom();
|
||||
|
||||
if (!GREEDY_REALLOC(*sockets, *n_sockets + 1))
|
||||
return log_oom();
|
||||
|
||||
(*sockets)[(*n_sockets)++] = (SocketInfo) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
.type = TAKE_PTR(type_dup),
|
||||
.path = TAKE_PTR(path_dup),
|
||||
.triggered = TAKE_PTR(triggered_dup),
|
||||
};
|
||||
}
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
@@ -340,46 +406,14 @@ static int get_listening(
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct socket_info {
|
||||
const char *machine;
|
||||
const char* id;
|
||||
|
||||
char* type;
|
||||
char* path;
|
||||
|
||||
/* Note: triggered is a list here, although it almost certainly will always be one
|
||||
* unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */
|
||||
char** triggered;
|
||||
|
||||
/* The strv above is shared. free is set only in the first one. */
|
||||
bool own_triggered;
|
||||
};
|
||||
|
||||
static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = strcasecmp_ptr(a->machine, b->machine);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = strcmp(a->path, b->path);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return strcmp(a->type, b->type);
|
||||
}
|
||||
|
||||
static int output_sockets_list(struct socket_info *socket_infos, size_t cs) {
|
||||
static int output_sockets_list(const SocketInfo *sockets, size_t n_sockets) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
int r;
|
||||
|
||||
assert(socket_infos || cs == 0);
|
||||
assert(sockets || n_sockets == 0);
|
||||
|
||||
table = table_new("listen", "type", "unit", "activates");
|
||||
if (!table)
|
||||
@@ -398,7 +432,7 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) {
|
||||
|
||||
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
|
||||
|
||||
for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) {
|
||||
for (const SocketInfo *s = sockets; s < sockets + n_sockets; s++) {
|
||||
_cleanup_free_ char *unit = NULL;
|
||||
|
||||
unit = format_unit_id(s->id, s->machine);
|
||||
@@ -406,9 +440,9 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) {
|
||||
return log_oom();
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, s->path,
|
||||
TABLE_STRING, s->type,
|
||||
TABLE_STRING, unit);
|
||||
TABLE_STRING, s->path,
|
||||
TABLE_STRING, s->type,
|
||||
TABLE_STRING, unit);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
@@ -422,20 +456,21 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) {
|
||||
return r;
|
||||
|
||||
if (arg_legend != 0)
|
||||
output_legend("socket", cs);
|
||||
output_legend("socket", n_sockets);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verb_list_sockets(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(message_set_freep) Set *replies = NULL;
|
||||
_cleanup_strv_free_ char **machines = NULL;
|
||||
_cleanup_strv_free_ char **sockets_with_suffix = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
_cleanup_free_ struct socket_info *socket_infos = NULL;
|
||||
size_t cs = 0;
|
||||
int r, n;
|
||||
SocketInfo *sockets = NULL;
|
||||
size_t n_sockets = 0;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
CLEANUP_ARRAY(sockets, n_sockets, socket_info_array_free);
|
||||
|
||||
r = acquire_bus(BUS_MANAGER, &bus);
|
||||
if (r < 0)
|
||||
@@ -448,63 +483,23 @@ int verb_list_sockets(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
|
||||
if (argc == 1 || sockets_with_suffix) {
|
||||
n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies, &machines);
|
||||
int n;
|
||||
|
||||
n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
|
||||
_cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
|
||||
int c;
|
||||
|
||||
if (!endswith(u->id, ".socket"))
|
||||
continue;
|
||||
|
||||
r = get_triggered_units(bus, u->unit_path, &triggered);
|
||||
r = socket_info_add(bus, u, &sockets, &n_sockets);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
c = get_listening(bus, u->unit_path, &listening);
|
||||
if (c < 0) {
|
||||
r = c;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(socket_infos, cs + c)) {
|
||||
r = log_oom();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (int i = 0; i < c; i++)
|
||||
socket_infos[cs + i] = (struct socket_info) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
.type = listening[i*2],
|
||||
.path = listening[i*2 + 1],
|
||||
.triggered = triggered,
|
||||
.own_triggered = i==0,
|
||||
};
|
||||
|
||||
/* from this point on we will cleanup those socket_infos */
|
||||
cs += c;
|
||||
free(listening);
|
||||
listening = triggered = NULL; /* avoid cleanup */
|
||||
return r;
|
||||
}
|
||||
|
||||
typesafe_qsort(socket_infos, cs, socket_info_compare);
|
||||
}
|
||||
|
||||
output_sockets_list(socket_infos, cs);
|
||||
typesafe_qsort(sockets, n_sockets, socket_info_compare);
|
||||
output_sockets_list(sockets, n_sockets);
|
||||
|
||||
cleanup:
|
||||
assert(cs == 0 || socket_infos);
|
||||
for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) {
|
||||
free(s->type);
|
||||
free(s->path);
|
||||
if (s->own_triggered)
|
||||
strv_free(s->triggered);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_next_elapse(
|
||||
@@ -575,15 +570,24 @@ static int get_last_trigger(
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct timer_info {
|
||||
typedef struct TimerInfo {
|
||||
const char* machine;
|
||||
const char* id;
|
||||
usec_t next_elapse;
|
||||
usec_t last_trigger;
|
||||
char** triggered;
|
||||
};
|
||||
char **triggered;
|
||||
} TimerInfo;
|
||||
|
||||
static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
|
||||
static void timer_info_array_free(TimerInfo *timers, size_t n_timers) {
|
||||
assert(timers || n_timers == 0);
|
||||
|
||||
for (TimerInfo *t = timers; t < timers + n_timers; t++)
|
||||
strv_free(t->triggered);
|
||||
|
||||
free(timers);
|
||||
}
|
||||
|
||||
static int timer_info_compare(const TimerInfo *a, const TimerInfo *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
@@ -600,11 +604,11 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf
|
||||
return strcmp(a->id, b->id);
|
||||
}
|
||||
|
||||
static int output_timers_list(struct timer_info *timer_infos, size_t n) {
|
||||
static int output_timers_list(const TimerInfo *timers, size_t n_timers) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
int r;
|
||||
|
||||
assert(timer_infos || n == 0);
|
||||
assert(timers || n_timers == 0);
|
||||
|
||||
table = table_new("next", "left", "last", "passed", "unit", "activates");
|
||||
if (!table)
|
||||
@@ -619,7 +623,7 @@ static int output_timers_list(struct timer_info *timer_infos, size_t n) {
|
||||
(void) table_set_align_percent(table, table_get_cell(table, 0, 1), 100);
|
||||
(void) table_set_align_percent(table, table_get_cell(table, 0, 3), 100);
|
||||
|
||||
for (struct timer_info *t = timer_infos; t < timer_infos + n; t++) {
|
||||
for (const TimerInfo *t = timers; t < timers + n_timers; t++) {
|
||||
_cleanup_free_ char *unit = NULL;
|
||||
|
||||
unit = format_unit_id(t->id, t->machine);
|
||||
@@ -645,12 +649,12 @@ static int output_timers_list(struct timer_info *timer_infos, size_t n) {
|
||||
return r;
|
||||
|
||||
if (arg_legend != 0)
|
||||
output_legend("timer", n);
|
||||
output_legend("timer", n_timers);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
|
||||
usec_t calc_next_elapse(const dual_timestamp *nw, const dual_timestamp *next) {
|
||||
usec_t next_elapse;
|
||||
|
||||
assert(nw);
|
||||
@@ -675,16 +679,65 @@ usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
|
||||
return next_elapse;
|
||||
}
|
||||
|
||||
static int add_timer_info(
|
||||
sd_bus *bus,
|
||||
const UnitInfo *u,
|
||||
const dual_timestamp *nw,
|
||||
TimerInfo **timers,
|
||||
size_t *n_timers) {
|
||||
|
||||
_cleanup_strv_free_ char **triggered = NULL;
|
||||
dual_timestamp next = DUAL_TIMESTAMP_NULL;
|
||||
usec_t m, last = 0;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(u);
|
||||
assert(nw);
|
||||
assert(timers);
|
||||
assert(n_timers);
|
||||
|
||||
if (!endswith(u->id, ".timer"))
|
||||
return 0;
|
||||
|
||||
r = get_triggered_units(bus, u->unit_path, &triggered);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = get_next_elapse(bus, u->unit_path, &next);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = get_last_trigger(bus, u->unit_path, &last);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
m = calc_next_elapse(nw, &next);
|
||||
|
||||
if (!GREEDY_REALLOC(*timers, *n_timers + 1))
|
||||
return log_oom();
|
||||
|
||||
(*timers)[(*n_timers)++] = (TimerInfo) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
.next_elapse = m,
|
||||
.last_trigger = last,
|
||||
.triggered = TAKE_PTR(triggered),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verb_list_timers(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(message_set_freep) Set *replies = NULL;
|
||||
_cleanup_strv_free_ char **machines = NULL;
|
||||
_cleanup_strv_free_ char **timers_with_suffix = NULL;
|
||||
_cleanup_free_ struct timer_info *timer_infos = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
dual_timestamp nw;
|
||||
size_t c = 0;
|
||||
TimerInfo *timers = NULL;
|
||||
size_t n_timers = 0;
|
||||
sd_bus *bus;
|
||||
int n, r;
|
||||
int r;
|
||||
|
||||
CLEANUP_ARRAY(timers, n_timers, timer_info_array_free);
|
||||
|
||||
r = acquire_bus(BUS_MANAGER, &bus);
|
||||
if (r < 0)
|
||||
@@ -697,68 +750,49 @@ int verb_list_timers(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
|
||||
if (argc == 1 || timers_with_suffix) {
|
||||
n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies, &machines);
|
||||
dual_timestamp nw;
|
||||
int n;
|
||||
|
||||
n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
dual_timestamp_get(&nw);
|
||||
|
||||
for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
|
||||
_cleanup_strv_free_ char **triggered = NULL;
|
||||
dual_timestamp next = DUAL_TIMESTAMP_NULL;
|
||||
usec_t m, last = 0;
|
||||
|
||||
if (!endswith(u->id, ".timer"))
|
||||
continue;
|
||||
|
||||
r = get_triggered_units(bus, u->unit_path, &triggered);
|
||||
r = add_timer_info(bus, u, &nw, &timers, &n_timers);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
r = get_next_elapse(bus, u->unit_path, &next);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
get_last_trigger(bus, u->unit_path, &last);
|
||||
|
||||
if (!GREEDY_REALLOC(timer_infos, c+1)) {
|
||||
r = log_oom();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
m = calc_next_elapse(&nw, &next);
|
||||
|
||||
timer_infos[c++] = (struct timer_info) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
.next_elapse = m,
|
||||
.last_trigger = last,
|
||||
.triggered = TAKE_PTR(triggered),
|
||||
};
|
||||
return r;
|
||||
}
|
||||
|
||||
typesafe_qsort(timer_infos, c, timer_info_compare);
|
||||
}
|
||||
|
||||
output_timers_list(timer_infos, c);
|
||||
typesafe_qsort(timers, n_timers, timer_info_compare);
|
||||
output_timers_list(timers, n_timers);
|
||||
|
||||
cleanup:
|
||||
for (struct timer_info *t = timer_infos; t < timer_infos + c; t++)
|
||||
strv_free(t->triggered);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct automount_info {
|
||||
typedef struct AutomountInfo {
|
||||
const char *machine;
|
||||
const char *id;
|
||||
char *what;
|
||||
char *where;
|
||||
usec_t timeout_idle_usec;
|
||||
bool mounted;
|
||||
};
|
||||
} AutomountInfo;
|
||||
|
||||
static int automount_info_compare(const struct automount_info *a, const struct automount_info *b) {
|
||||
static void automount_info_array_free(AutomountInfo *automounts, size_t n_automounts) {
|
||||
assert(automounts || n_automounts == 0);
|
||||
|
||||
for (AutomountInfo *i = automounts; i < automounts + n_automounts; i++) {
|
||||
free(i->what);
|
||||
free(i->where);
|
||||
}
|
||||
|
||||
free(automounts);
|
||||
}
|
||||
|
||||
static int automount_info_compare(const AutomountInfo *a, const AutomountInfo *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
@@ -768,10 +802,15 @@ static int automount_info_compare(const struct automount_info *a, const struct a
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return strcmp(a->where, b->where);
|
||||
return path_compare(a->where, b->where);
|
||||
}
|
||||
|
||||
static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct automount_info *ret_info) {
|
||||
static int automount_info_add(
|
||||
sd_bus* bus,
|
||||
const UnitInfo *info,
|
||||
AutomountInfo **automounts,
|
||||
size_t *n_automounts) {
|
||||
|
||||
_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;
|
||||
uint64_t timeout_idle_usec;
|
||||
@@ -780,7 +819,11 @@ static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct auto
|
||||
|
||||
assert(bus);
|
||||
assert(info);
|
||||
assert(ret_info);
|
||||
assert(automounts);
|
||||
assert(n_automounts);
|
||||
|
||||
if (!endswith(info->id, ".automount"))
|
||||
return 0;
|
||||
|
||||
locator = (BusLocator) {
|
||||
.destination = "org.freedesktop.systemd1",
|
||||
@@ -817,7 +860,10 @@ static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct auto
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get mount state: %s", bus_error_message(&error, r));
|
||||
|
||||
*ret_info = (struct automount_info) {
|
||||
if (!GREEDY_REALLOC(*automounts, *n_automounts + 1))
|
||||
return log_oom();
|
||||
|
||||
(*automounts)[(*n_automounts)++] = (AutomountInfo) {
|
||||
.machine = info->machine,
|
||||
.id = info->id,
|
||||
.what = TAKE_PTR(what),
|
||||
@@ -829,7 +875,7 @@ static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct auto
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_automounts_list(struct automount_info *infos, size_t n_infos) {
|
||||
static int output_automounts_list(const AutomountInfo *infos, size_t n_infos) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
int r;
|
||||
|
||||
@@ -845,7 +891,7 @@ static int output_automounts_list(struct automount_info *infos, size_t n_infos)
|
||||
|
||||
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
|
||||
|
||||
for (struct automount_info *info = infos; info < infos + n_infos; info++) {
|
||||
for (const AutomountInfo *info = infos; info < infos + n_infos; info++) {
|
||||
_cleanup_free_ char *unit = NULL;
|
||||
|
||||
unit = format_unit_id(info->id, info->machine);
|
||||
@@ -883,12 +929,14 @@ static int output_automounts_list(struct automount_info *infos, size_t n_infos)
|
||||
|
||||
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_strv_free_ char **names = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
_cleanup_free_ struct automount_info *automount_infos = NULL;
|
||||
size_t c = 0;
|
||||
int r, n;
|
||||
AutomountInfo *automounts = NULL;
|
||||
size_t n_automounts = 0;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
CLEANUP_ARRAY(automounts, n_automounts, automount_info_array_free);
|
||||
|
||||
r = acquire_bus(BUS_MANAGER, &bus);
|
||||
if (r < 0)
|
||||
@@ -896,47 +944,32 @@ int verb_list_automounts(int argc, char *argv[], void *userdata) {
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
r = expand_unit_names(bus, strv_skip(argv, 1), ".automount", &automounts, NULL);
|
||||
r = expand_unit_names(bus, strv_skip(argv, 1), ".automount", &names, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (argc == 1 || automounts) {
|
||||
n = get_unit_list_recursive(bus, automounts, &unit_infos, &replies, &machines);
|
||||
int n;
|
||||
|
||||
n = get_unit_list_recursive(bus, names, &unit_infos, &replies);
|
||||
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]);
|
||||
r = automount_info_add(bus, u, &automounts, &n_automounts);
|
||||
if (r < 0)
|
||||
goto cleanup;
|
||||
|
||||
c++;
|
||||
return r;
|
||||
}
|
||||
|
||||
typesafe_qsort(automount_infos, c, automount_info_compare);
|
||||
}
|
||||
|
||||
output_automounts_list(automount_infos, c);
|
||||
typesafe_qsort(automounts, n_automounts, automount_info_compare);
|
||||
output_automounts_list(automounts, n_automounts);
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct path_info {
|
||||
typedef struct PathInfo {
|
||||
const char *machine;
|
||||
const char *id;
|
||||
|
||||
@@ -946,14 +979,9 @@ struct path_info {
|
||||
/* Note: triggered is a list here, although it almost certainly will always be one
|
||||
* unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */
|
||||
char** triggered;
|
||||
};
|
||||
} PathInfo;
|
||||
|
||||
struct path_infos {
|
||||
size_t count;
|
||||
struct path_info *items;
|
||||
};
|
||||
|
||||
static int path_info_compare(const struct path_info *a, const struct path_info *b) {
|
||||
static int path_info_compare(const PathInfo *a, const PathInfo *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
@@ -974,34 +1002,45 @@ static int path_info_compare(const struct path_info *a, const struct path_info *
|
||||
return strcasecmp_ptr(a->id, b->id);
|
||||
}
|
||||
|
||||
static void path_infos_done(struct path_infos *ps) {
|
||||
assert(ps);
|
||||
assert(ps->items || ps->count == 0);
|
||||
static void path_info_array_free(PathInfo *paths, size_t n_paths) {
|
||||
assert(paths || n_paths == 0);
|
||||
|
||||
for (struct path_info *p = ps->items; p < ps->items + ps->count; p++) {
|
||||
for (PathInfo *p = paths; p < paths + n_paths; p++) {
|
||||
free(p->condition);
|
||||
free(p->path);
|
||||
strv_free(p->triggered);
|
||||
}
|
||||
|
||||
free(ps->items);
|
||||
free(paths);
|
||||
}
|
||||
|
||||
static int get_paths(sd_bus *bus, const char *unit_path, char ***ret_conditions, char ***ret_paths) {
|
||||
static int path_info_add(
|
||||
sd_bus *bus,
|
||||
const struct UnitInfo *u,
|
||||
PathInfo **paths,
|
||||
size_t *n_paths) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_strv_free_ char **conditions = NULL, **paths = NULL;
|
||||
_cleanup_strv_free_ char **triggered = NULL;
|
||||
const char *condition, *path;
|
||||
int r, n = 0;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(unit_path);
|
||||
assert(ret_conditions);
|
||||
assert(ret_paths);
|
||||
assert(u);
|
||||
assert(paths);
|
||||
assert(n_paths);
|
||||
|
||||
if (!endswith(u->id, ".path"))
|
||||
return 0;
|
||||
|
||||
r = get_triggered_units(bus, u->unit_path, &triggered);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_get_property(bus,
|
||||
"org.freedesktop.systemd1",
|
||||
unit_path,
|
||||
u->unit_path,
|
||||
"org.freedesktop.systemd1.Path",
|
||||
"Paths",
|
||||
&error,
|
||||
@@ -1015,13 +1054,31 @@ static int get_paths(sd_bus *bus, const char *unit_path, char ***ret_conditions,
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_read(reply, "(ss)", &condition, &path)) > 0) {
|
||||
if (strv_extend(&conditions, condition) < 0)
|
||||
_cleanup_free_ char *condition_dup = NULL, *path_dup = NULL;
|
||||
_cleanup_strv_free_ char **triggered_dup = NULL;
|
||||
|
||||
condition_dup = strdup(condition);
|
||||
if (!condition_dup)
|
||||
return log_oom();
|
||||
|
||||
if (strv_extend(&paths, path) < 0)
|
||||
path_dup = strdup(path);
|
||||
if (!path_dup)
|
||||
return log_oom();
|
||||
|
||||
n++;
|
||||
triggered_dup = strv_copy(triggered);
|
||||
if (!triggered_dup)
|
||||
return log_oom();
|
||||
|
||||
if (!GREEDY_REALLOC(*paths, *n_paths + 1))
|
||||
return log_oom();
|
||||
|
||||
(*paths)[(*n_paths)++] = (PathInfo) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
.condition = TAKE_PTR(condition_dup),
|
||||
.path = TAKE_PTR(path_dup),
|
||||
.triggered = TAKE_PTR(triggered_dup),
|
||||
};
|
||||
}
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
@@ -1030,18 +1087,14 @@ static int get_paths(sd_bus *bus, const char *unit_path, char ***ret_conditions,
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
*ret_conditions = TAKE_PTR(conditions);
|
||||
*ret_paths = TAKE_PTR(paths);
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_paths_list(struct path_infos *ps) {
|
||||
static int output_paths_list(const PathInfo *paths, size_t n_paths) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
int r;
|
||||
|
||||
assert(ps);
|
||||
assert(ps->items || ps->count == 0);
|
||||
assert(paths || n_paths == 0);
|
||||
|
||||
table = table_new("path", "condition", "unit", "activates");
|
||||
if (!table)
|
||||
@@ -1053,7 +1106,7 @@ static int output_paths_list(struct path_infos *ps) {
|
||||
|
||||
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
|
||||
|
||||
for (struct path_info *p = ps->items; p < ps->items + ps->count; p++) {
|
||||
for (const PathInfo *p = paths; p < paths + n_paths; p++) {
|
||||
_cleanup_free_ char *unit = NULL;
|
||||
|
||||
unit = format_unit_id(p->id, p->machine);
|
||||
@@ -1077,18 +1130,21 @@ static int output_paths_list(struct path_infos *ps) {
|
||||
return r;
|
||||
|
||||
if (arg_legend != 0)
|
||||
output_legend("path", ps->count);
|
||||
output_legend("path", n_paths);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verb_list_paths(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(message_set_freep) Set *replies = NULL;
|
||||
_cleanup_strv_free_ char **machines = NULL, **units = NULL;
|
||||
_cleanup_strv_free_ char **units = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
_cleanup_(path_infos_done) struct path_infos path_infos = {};
|
||||
int r, n;
|
||||
PathInfo *paths = NULL;
|
||||
size_t n_paths = 0;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
CLEANUP_ARRAY(paths, n_paths, path_info_array_free);
|
||||
|
||||
r = acquire_bus(BUS_MANAGER, &bus);
|
||||
if (r < 0)
|
||||
@@ -1101,49 +1157,21 @@ int verb_list_paths(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
|
||||
if (argc == 1 || units) {
|
||||
n = get_unit_list_recursive(bus, units, &unit_infos, &replies, &machines);
|
||||
int n;
|
||||
|
||||
n = get_unit_list_recursive(bus, units, &unit_infos, &replies);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
|
||||
_cleanup_strv_free_ char **conditions = NULL, **paths = NULL, **triggered = NULL;
|
||||
int c;
|
||||
|
||||
if (!endswith(u->id, ".path"))
|
||||
continue;
|
||||
|
||||
r = get_triggered_units(bus, u->unit_path, &triggered);
|
||||
r = path_info_add(bus, u, &paths, &n_paths);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c = get_paths(bus, u->unit_path, &conditions, &paths);
|
||||
if (c < 0)
|
||||
return c;
|
||||
|
||||
if (!GREEDY_REALLOC(path_infos.items, path_infos.count + c))
|
||||
return log_oom();
|
||||
|
||||
for (int i = c - 1; i >= 0; i--) {
|
||||
char **t;
|
||||
|
||||
t = strv_copy(triggered);
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
path_infos.items[path_infos.count++] = (struct path_info) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
.condition = TAKE_PTR(conditions[i]),
|
||||
.path = TAKE_PTR(paths[i]),
|
||||
.triggered = t,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
typesafe_qsort(path_infos.items, path_infos.count, path_info_compare);
|
||||
}
|
||||
|
||||
output_paths_list(&path_infos);
|
||||
typesafe_qsort(paths, n_paths, path_info_compare);
|
||||
output_paths_list(paths, n_paths);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@ int verb_list_timers(int argc, char *argv[], void *userdata);
|
||||
int verb_list_automounts(int argc, char *argv[], void *userdata);
|
||||
int verb_list_paths(int argc, char *argv[], void *userdata);
|
||||
|
||||
usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next);
|
||||
usec_t calc_next_elapse(const dual_timestamp *nw, const dual_timestamp *next);
|
||||
|
||||
Reference in New Issue
Block a user