]> git.proxmox.com Git - systemd.git/blame - src/systemctl/systemctl-show.c
New upstream version 249~rc1
[systemd.git] / src / systemctl / systemctl-show.c
CommitLineData
a032b68d
MB
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <sys/mount.h>
4
8b3d4ff0 5#include "af-list.h"
a032b68d
MB
6#include "bus-error.h"
7#include "bus-locator.h"
8#include "bus-map-properties.h"
9#include "bus-print-properties.h"
10#include "bus-unit-procs.h"
11#include "cgroup-show.h"
12#include "cpu-set-util.h"
13#include "errno-util.h"
14#include "exec-util.h"
15#include "exit-status.h"
16#include "format-util.h"
17#include "hexdecoct.h"
18#include "hostname-util.h"
19#include "in-addr-util.h"
1ce460ce 20#include "journal-file.h"
a032b68d
MB
21#include "list.h"
22#include "locale-util.h"
23#include "memory-util.h"
24#include "numa-util.h"
25#include "parse-util.h"
26#include "path-util.h"
27#include "pretty-print.h"
28#include "process-util.h"
29#include "signal-util.h"
30#include "sort-util.h"
31#include "string-table.h"
32#include "systemctl-list-machines.h"
33#include "systemctl-list-units.h"
34#include "systemctl-show.h"
35#include "systemctl-sysv-compat.h"
36#include "systemctl-util.h"
37#include "systemctl.h"
38#include "terminal-util.h"
39#include "utf8.h"
40
41static OutputFlags get_output_flags(void) {
42 return
8b3d4ff0 43 FLAGS_SET(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) * OUTPUT_SHOW_ALL |
a032b68d
MB
44 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
45 colors_enabled() * OUTPUT_COLOR |
46 !arg_quiet * OUTPUT_WARN_CUTOFF;
47}
48
49typedef struct ExecStatusInfo {
50 char *name;
51
52 char *path;
53 char **argv;
54
55 bool ignore;
56
57 usec_t start_timestamp;
58 usec_t exit_timestamp;
59 pid_t pid;
60 int code;
61 int status;
62
63 ExecCommandFlags flags;
64
65 LIST_FIELDS(struct ExecStatusInfo, exec);
66} ExecStatusInfo;
67
68static void exec_status_info_free(ExecStatusInfo *i) {
69 assert(i);
70
71 free(i->name);
72 free(i->path);
73 strv_free(i->argv);
74 free(i);
75}
76
77static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i, bool is_ex_prop) {
78 _cleanup_strv_free_ char **ex_opts = NULL;
79 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
80 const char *path;
81 uint32_t pid;
82 int32_t code, status;
83 int ignore, r;
84
85 assert(m);
86 assert(i);
87
88 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, is_ex_prop ? "sasasttttuii" : "sasbttttuii");
89 if (r < 0)
90 return bus_log_parse_error(r);
91 else if (r == 0)
92 return 0;
93
94 r = sd_bus_message_read(m, "s", &path);
95 if (r < 0)
96 return bus_log_parse_error(r);
97
98 i->path = strdup(path);
99 if (!i->path)
100 return log_oom();
101
102 r = sd_bus_message_read_strv(m, &i->argv);
103 if (r < 0)
104 return bus_log_parse_error(r);
105
106 r = is_ex_prop ? sd_bus_message_read_strv(m, &ex_opts) : sd_bus_message_read(m, "b", &ignore);
107 if (r < 0)
108 return bus_log_parse_error(r);
109
110 r = sd_bus_message_read(m,
111 "ttttuii",
112 &start_timestamp, &start_timestamp_monotonic,
113 &exit_timestamp, &exit_timestamp_monotonic,
114 &pid,
115 &code, &status);
116 if (r < 0)
117 return bus_log_parse_error(r);
118
119 if (is_ex_prop) {
120 r = exec_command_flags_from_strv(ex_opts, &i->flags);
121 if (r < 0)
122 return log_error_errno(r, "Failed to convert strv to ExecCommandFlags: %m");
123
124 i->ignore = FLAGS_SET(i->flags, EXEC_COMMAND_IGNORE_FAILURE);
125 } else
126 i->ignore = ignore;
127
128 i->start_timestamp = (usec_t) start_timestamp;
129 i->exit_timestamp = (usec_t) exit_timestamp;
130 i->pid = (pid_t) pid;
131 i->code = code;
132 i->status = status;
133
134 r = sd_bus_message_exit_container(m);
135 if (r < 0)
136 return bus_log_parse_error(r);
137
138 return 1;
139}
140
141typedef struct UnitCondition {
142 char *name;
143 char *param;
144 bool trigger;
145 bool negate;
146 int tristate;
147
148 LIST_FIELDS(struct UnitCondition, conditions);
149} UnitCondition;
150
3a6ce677 151static UnitCondition* unit_condition_free(UnitCondition *c) {
a032b68d 152 if (!c)
3a6ce677 153 return NULL;
a032b68d
MB
154
155 free(c->name);
156 free(c->param);
3a6ce677 157 return mfree(c);
a032b68d 158}
a032b68d
MB
159DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
160
161typedef struct UnitStatusInfo {
162 const char *id;
163 const char *load_state;
164 const char *active_state;
165 const char *freezer_state;
166 const char *sub_state;
167 const char *unit_file_state;
168 const char *unit_file_preset;
169
170 const char *description;
171 const char *following;
172
173 char **documentation;
174
175 const char *fragment_path;
176 const char *source_path;
177 const char *control_group;
178
179 char **dropin_paths;
180
181 char **triggered_by;
182 char **triggers;
183
184 const char *load_error;
185 const char *result;
186
187 usec_t inactive_exit_timestamp;
188 usec_t inactive_exit_timestamp_monotonic;
189 usec_t active_enter_timestamp;
190 usec_t active_exit_timestamp;
191 usec_t inactive_enter_timestamp;
192
193 bool need_daemon_reload;
194 bool transient;
195
196 /* Service */
197 pid_t main_pid;
198 pid_t control_pid;
199 const char *status_text;
200 const char *pid_file;
201 bool running:1;
202 int status_errno;
203
204 usec_t start_timestamp;
205 usec_t exit_timestamp;
206
207 int exit_code, exit_status;
208
209 const char *log_namespace;
210
211 usec_t condition_timestamp;
212 bool condition_result;
213 LIST_HEAD(UnitCondition, conditions);
214
215 usec_t assert_timestamp;
216 bool assert_result;
217 bool failed_assert_trigger;
218 bool failed_assert_negate;
219 const char *failed_assert;
220 const char *failed_assert_parameter;
221 usec_t next_elapse_real;
222 usec_t next_elapse_monotonic;
223
224 /* Socket */
225 unsigned n_accepted;
226 unsigned n_connections;
227 unsigned n_refused;
228 bool accept;
229
230 /* Pairs of type, path */
231 char **listen;
232
233 /* Device */
234 const char *sysfs_path;
235
236 /* Mount, Automount */
237 const char *where;
238
239 /* Swap */
240 const char *what;
241
242 /* CGroup */
243 uint64_t memory_current;
244 uint64_t memory_min;
245 uint64_t memory_low;
246 uint64_t memory_high;
247 uint64_t memory_max;
248 uint64_t memory_swap_max;
249 uint64_t memory_limit;
8b3d4ff0 250 uint64_t memory_available;
a032b68d
MB
251 uint64_t cpu_usage_nsec;
252 uint64_t tasks_current;
253 uint64_t tasks_max;
254 uint64_t ip_ingress_bytes;
255 uint64_t ip_egress_bytes;
256 uint64_t io_read_bytes;
257 uint64_t io_write_bytes;
258
259 uint64_t default_memory_min;
260 uint64_t default_memory_low;
261
262 LIST_HEAD(ExecStatusInfo, exec);
263} UnitStatusInfo;
264
265static void unit_status_info_free(UnitStatusInfo *info) {
266 ExecStatusInfo *p;
267 UnitCondition *c;
268
269 strv_free(info->documentation);
270 strv_free(info->dropin_paths);
271 strv_free(info->triggered_by);
272 strv_free(info->triggers);
273 strv_free(info->listen);
274
275 while ((c = info->conditions)) {
276 LIST_REMOVE(conditions, info->conditions, c);
277 unit_condition_free(c);
278 }
279
280 while ((p = info->exec)) {
281 LIST_REMOVE(exec, info->exec, p);
282 exec_status_info_free(p);
283 }
284}
285
286static void format_active_state(const char *active_state, const char **active_on, const char **active_off) {
287 if (streq_ptr(active_state, "failed")) {
288 *active_on = ansi_highlight_red();
289 *active_off = ansi_normal();
290 } else if (STRPTR_IN_SET(active_state, "active", "reloading")) {
291 *active_on = ansi_highlight_green();
292 *active_off = ansi_normal();
293 } else
294 *active_on = *active_off = "";
295}
296
297static void print_status_info(
298 sd_bus *bus,
299 UnitStatusInfo *i,
300 bool *ellipsized) {
301
302 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
303 const char *s1, *s2, *active_on, *active_off, *on, *off, *ss, *fs;
304 _cleanup_free_ char *formatted_path = NULL;
305 ExecStatusInfo *p;
306 usec_t timestamp;
307 const char *path;
308 char **t, **t2;
309 int r;
310
311 assert(i);
312
313 /* This shows pretty information about a unit. See print_property() for a low-level property
314 * printer */
315
316 format_active_state(i->active_state, &active_on, &active_off);
317
3a6ce677
BR
318 const SpecialGlyph glyph = unit_active_state_to_glyph(unit_active_state_from_string(i->active_state));
319
320 printf("%s%s%s %s", active_on, special_glyph(glyph), active_off, strna(i->id));
a032b68d
MB
321
322 if (i->description && !streq_ptr(i->id, i->description))
323 printf(" - %s", i->description);
324
325 printf("\n");
326
327 if (i->following)
8b3d4ff0 328 printf(" Follows: unit currently follows state of %s\n", i->following);
a032b68d
MB
329
330 if (STRPTR_IN_SET(i->load_state, "error", "not-found", "bad-setting")) {
331 on = ansi_highlight_red();
332 off = ansi_normal();
333 } else
334 on = off = "";
335
336 path = i->source_path ?: i->fragment_path;
337 if (path && terminal_urlify_path(path, NULL, &formatted_path) >= 0)
338 path = formatted_path;
339
340 if (!isempty(i->load_error))
341 printf(" Loaded: %s%s%s (Reason: %s)\n",
342 on, strna(i->load_state), off, i->load_error);
343 else if (path && !isempty(i->unit_file_state)) {
344 bool show_preset = !isempty(i->unit_file_preset) &&
345 show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
346
347 printf(" Loaded: %s%s%s (%s; %s%s%s)\n",
348 on, strna(i->load_state), off,
349 path,
350 i->unit_file_state,
351 show_preset ? "; vendor preset: " : "",
352 show_preset ? i->unit_file_preset : "");
353
354 } else if (path)
355 printf(" Loaded: %s%s%s (%s)\n",
356 on, strna(i->load_state), off, path);
357 else
358 printf(" Loaded: %s%s%s\n",
359 on, strna(i->load_state), off);
360
361 if (i->transient)
362 printf(" Transient: yes\n");
363
364 if (!strv_isempty(i->dropin_paths)) {
365 _cleanup_free_ char *dir = NULL;
366 bool last = false;
367 char ** dropin;
368
369 STRV_FOREACH(dropin, i->dropin_paths) {
370 _cleanup_free_ char *dropin_formatted = NULL;
371 const char *df;
372
373 if (!dir || last) {
374 printf(dir ? " " :
375 " Drop-In: ");
376
377 dir = mfree(dir);
378
379 dir = dirname_malloc(*dropin);
380 if (!dir) {
381 log_oom();
382 return;
383 }
384
385 printf("%s\n"
386 " %s", dir,
387 special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
388 }
389
390 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
391
392 if (terminal_urlify_path(*dropin, basename(*dropin), &dropin_formatted) >= 0)
393 df = dropin_formatted;
394 else
395 df = *dropin;
396
397 printf("%s%s", df, last ? "\n" : ", ");
398 }
399 }
400
401 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
402 if (ss)
403 printf(" Active: %s%s (%s)%s",
404 active_on, strna(i->active_state), ss, active_off);
405 else
406 printf(" Active: %s%s%s",
407 active_on, strna(i->active_state), active_off);
408
409 fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
410 if (fs)
411 printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
412
413 if (!isempty(i->result) && !streq(i->result, "success"))
414 printf(" (Result: %s)", i->result);
415
416 timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
417 STRPTR_IN_SET(i->active_state, "inactive", "failed") ? i->inactive_enter_timestamp :
418 STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
419 i->active_exit_timestamp;
420
421 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
422 s2 = format_timestamp_style(since2, sizeof(since2), timestamp, arg_timestamp_style);
423
424 if (s1)
425 printf(" since %s; %s\n", s2, s1);
426 else if (s2)
427 printf(" since %s\n", s2);
428 else
429 printf("\n");
430
431 STRV_FOREACH(t, i->triggered_by) {
432 UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
433
434 (void) get_state_one_unit(bus, *t, &state);
435 format_active_state(unit_active_state_to_string(state), &on, &off);
436
437 printf("%s %s%s%s %s\n",
438 t == i->triggered_by ? "TriggeredBy:" : " ",
3a6ce677 439 on, special_glyph(unit_active_state_to_glyph(state)), off,
a032b68d
MB
440 *t);
441 }
442
443 if (endswith(i->id, ".timer")) {
444 char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
445 tstamp2[FORMAT_TIMESTAMP_MAX];
446 const char *next_rel_time, *next_time;
447 dual_timestamp nw, next = {i->next_elapse_real,
448 i->next_elapse_monotonic};
449 usec_t next_elapse;
450
451 printf(" Trigger: ");
452
453 dual_timestamp_get(&nw);
454 next_elapse = calc_next_elapse(&nw, &next);
455 next_rel_time = format_timestamp_relative(tstamp1, sizeof tstamp1, next_elapse);
456 next_time = format_timestamp_style(tstamp2, sizeof tstamp2, next_elapse, arg_timestamp_style);
457
458 if (next_time && next_rel_time)
459 printf("%s; %s\n", next_time, next_rel_time);
460 else
461 printf("n/a\n");
462 }
463
464 STRV_FOREACH(t, i->triggers) {
465 UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
466
467 (void) get_state_one_unit(bus, *t, &state);
468 format_active_state(unit_active_state_to_string(state), &on, &off);
469
470 printf("%s %s%s%s %s\n",
471 t == i->triggers ? " Triggers:" : " ",
472 on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
473 *t);
474 }
475
476 if (!i->condition_result && i->condition_timestamp > 0) {
477 UnitCondition *c;
478 int n = 0;
479
480 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
481 s2 = format_timestamp_style(since2, sizeof(since2), i->condition_timestamp, arg_timestamp_style);
482
483 printf(" Condition: start %scondition failed%s at %s%s%s\n",
484 ansi_highlight_yellow(), ansi_normal(),
485 s2, s1 ? "; " : "", strempty(s1));
486
487 LIST_FOREACH(conditions, c, i->conditions)
488 if (c->tristate < 0)
489 n++;
490
491 LIST_FOREACH(conditions, c, i->conditions)
492 if (c->tristate < 0)
493 printf(" %s %s=%s%s%s was not met\n",
494 --n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
495 c->name,
496 c->trigger ? "|" : "",
497 c->negate ? "!" : "",
498 c->param);
499 }
500
501 if (!i->assert_result && i->assert_timestamp > 0) {
502 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
503 s2 = format_timestamp_style(since2, sizeof(since2), i->assert_timestamp, arg_timestamp_style);
504
505 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
506 ansi_highlight_red(), ansi_normal(),
507 s2, s1 ? "; " : "", strempty(s1));
508 if (i->failed_assert_trigger)
509 printf(" none of the trigger assertions were met\n");
510 else if (i->failed_assert)
511 printf(" %s=%s%s was not met\n",
512 i->failed_assert,
513 i->failed_assert_negate ? "!" : "",
514 i->failed_assert_parameter);
515 }
516
517 if (i->sysfs_path)
518 printf(" Device: %s\n", i->sysfs_path);
519 if (i->where)
520 printf(" Where: %s\n", i->where);
521 if (i->what)
522 printf(" What: %s\n", i->what);
523
524 STRV_FOREACH(t, i->documentation) {
525 _cleanup_free_ char *formatted = NULL;
526 const char *q;
527
528 if (terminal_urlify(*t, NULL, &formatted) >= 0)
529 q = formatted;
530 else
531 q = *t;
532
533 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
534 }
535
536 STRV_FOREACH_PAIR(t, t2, i->listen)
537 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
538
539 if (i->accept) {
540 printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
541 if (i->n_refused)
542 printf(" Refused: %u", i->n_refused);
543 printf("\n");
544 }
545
546 LIST_FOREACH(exec, p, i->exec) {
547 _cleanup_free_ char *argv = NULL;
548 bool good;
549
550 /* Only show exited processes here */
551 if (p->code == 0)
552 continue;
553
554 /* Don't print ExecXYZEx= properties here since it will appear as a
555 * duplicate of the non-Ex= variant. */
556 if (endswith(p->name, "Ex"))
557 continue;
558
559 argv = strv_join(p->argv, " ");
560 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
561
562 good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
563 if (!good) {
564 on = ansi_highlight_red();
565 off = ansi_normal();
566 } else
567 on = off = "";
568
569 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
570
571 if (p->code == CLD_EXITED) {
572 const char *c;
573
574 printf("status=%i", p->status);
575
576 c = exit_status_to_string(p->status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
577 if (c)
578 printf("/%s", c);
579
580 } else
581 printf("signal=%s", signal_to_string(p->status));
582
583 printf(")%s\n", off);
584
585 if (i->main_pid == p->pid &&
586 i->start_timestamp == p->start_timestamp &&
587 i->exit_timestamp == p->start_timestamp)
588 /* Let's not show this twice */
589 i->main_pid = 0;
590
591 if (p->pid == i->control_pid)
592 i->control_pid = 0;
593 }
594
595 if (i->main_pid > 0 || i->control_pid > 0) {
596 if (i->main_pid > 0) {
597 printf(" Main PID: "PID_FMT, i->main_pid);
598
599 if (i->running) {
600
601 if (arg_transport == BUS_TRANSPORT_LOCAL) {
602 _cleanup_free_ char *comm = NULL;
603
604 (void) get_process_comm(i->main_pid, &comm);
605 if (comm)
606 printf(" (%s)", comm);
607 }
608
609 } else if (i->exit_code > 0) {
610 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
611
612 if (i->exit_code == CLD_EXITED) {
613 const char *c;
614
615 printf("status=%i", i->exit_status);
616
617 c = exit_status_to_string(i->exit_status,
618 EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
619 if (c)
620 printf("/%s", c);
621
622 } else
623 printf("signal=%s", signal_to_string(i->exit_status));
624 printf(")");
625 }
626 }
627
628 if (i->control_pid > 0) {
629 _cleanup_free_ char *c = NULL;
630
631 if (i->main_pid > 0)
632 fputs("; Control PID: ", stdout);
633 else
634 fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
635
636 printf(PID_FMT, i->control_pid);
637
638 if (arg_transport == BUS_TRANSPORT_LOCAL) {
639 (void) get_process_comm(i->control_pid, &c);
640 if (c)
641 printf(" (%s)", c);
642 }
643 }
644
645 printf("\n");
646 }
647
648 if (i->status_text)
649 printf(" Status: \"%s\"\n", i->status_text);
650 if (i->status_errno > 0)
651 printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
652
3a6ce677 653 if (i->ip_ingress_bytes != UINT64_MAX && i->ip_egress_bytes != UINT64_MAX) {
a032b68d
MB
654 char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
655
656 printf(" IP: %s in, %s out\n",
657 format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
658 format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
659 }
660
661 if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
662 char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
663
664 printf(" IO: %s read, %s written\n",
665 format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
666 format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
667 }
668
3a6ce677 669 if (i->tasks_current != UINT64_MAX) {
a032b68d
MB
670 printf(" Tasks: %" PRIu64, i->tasks_current);
671
3a6ce677 672 if (i->tasks_max != UINT64_MAX)
a032b68d
MB
673 printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
674 else
675 printf("\n");
676 }
677
3a6ce677 678 if (i->memory_current != UINT64_MAX) {
a032b68d
MB
679 char buf[FORMAT_BYTES_MAX];
680
681 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
682
683 if (i->memory_min > 0 || i->memory_low > 0 ||
684 i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
685 i->memory_swap_max != CGROUP_LIMIT_MAX ||
8b3d4ff0 686 i->memory_available != CGROUP_LIMIT_MAX ||
a032b68d
MB
687 i->memory_limit != CGROUP_LIMIT_MAX) {
688 const char *prefix = "";
689
690 printf(" (");
691 if (i->memory_min > 0) {
692 printf("%smin: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_min));
693 prefix = " ";
694 }
695 if (i->memory_low > 0) {
696 printf("%slow: %s", prefix, format_bytes_cgroup_protection(buf, sizeof(buf), i->memory_low));
697 prefix = " ";
698 }
699 if (i->memory_high != CGROUP_LIMIT_MAX) {
700 printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
701 prefix = " ";
702 }
703 if (i->memory_max != CGROUP_LIMIT_MAX) {
704 printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
705 prefix = " ";
706 }
707 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
708 printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
709 prefix = " ";
710 }
711 if (i->memory_limit != CGROUP_LIMIT_MAX) {
712 printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
713 prefix = " ";
714 }
8b3d4ff0
MB
715 if (i->memory_available != CGROUP_LIMIT_MAX) {
716 printf("%savailable: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_available));
717 prefix = " ";
718 }
a032b68d
MB
719 printf(")");
720 }
721 printf("\n");
722 }
723
3a6ce677 724 if (i->cpu_usage_nsec != UINT64_MAX) {
a032b68d
MB
725 char buf[FORMAT_TIMESPAN_MAX];
726 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
727 }
728
729 if (i->control_group) {
730 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
731 static const char prefix[] = " ";
732 unsigned c;
733
734 printf(" CGroup: %s\n", i->control_group);
735
736 c = columns();
737 if (c > sizeof(prefix) - 1)
738 c -= sizeof(prefix) - 1;
739 else
740 c = 0;
741
742 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
743 if (r == -EBADR) {
744 unsigned k = 0;
745 pid_t extra[2];
746
747 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
748
749 if (i->main_pid > 0)
750 extra[k++] = i->main_pid;
751
752 if (i->control_pid > 0)
753 extra[k++] = i->control_pid;
754
755 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
756 } else if (r < 0)
757 log_warning_errno(r, "Failed to dump process list for '%s', ignoring: %s",
758 i->id, bus_error_message(&error, r));
759 }
760
761 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
762 show_journal_by_unit(
763 stdout,
764 i->id,
765 i->log_namespace,
766 arg_output,
767 0,
768 i->inactive_exit_timestamp_monotonic,
769 arg_lines,
770 getuid(),
771 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
772 SD_JOURNAL_LOCAL_ONLY,
773 arg_scope == UNIT_FILE_SYSTEM,
774 ellipsized);
775
776 if (i->need_daemon_reload)
777 warn_unit_file_changed(i->id);
778}
779
780static void show_unit_help(UnitStatusInfo *i) {
781 char **p;
782
783 assert(i);
784
785 if (!i->documentation) {
786 log_info("Documentation for %s not known.", i->id);
787 return;
788 }
789
790 STRV_FOREACH(p, i->documentation)
791 if (startswith(*p, "man:"))
792 show_man_page(*p + 4, false);
793 else
794 log_info("Can't show: %s", *p);
795}
796
797static int map_main_pid(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
798 UnitStatusInfo *i = userdata;
799 uint32_t u;
800 int r;
801
802 r = sd_bus_message_read(m, "u", &u);
803 if (r < 0)
804 return r;
805
806 i->main_pid = (pid_t) u;
807 i->running = u > 0;
808
809 return 0;
810}
811
812static int map_load_error(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
813 const char *message, **p = userdata;
814 int r;
815
816 r = sd_bus_message_read(m, "(ss)", NULL, &message);
817 if (r < 0)
818 return r;
819
820 if (!isempty(message))
821 *p = message;
822
823 return 0;
824}
825
826static int map_listen(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
827 const char *type, *path;
828 char ***p = userdata;
829 int r;
830
831 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
832 if (r < 0)
833 return r;
834
835 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
836
837 r = strv_extend(p, type);
838 if (r < 0)
839 return r;
840
841 r = strv_extend(p, path);
842 if (r < 0)
843 return r;
844 }
845 if (r < 0)
846 return r;
847
848 r = sd_bus_message_exit_container(m);
849 if (r < 0)
850 return r;
851
852 return 0;
853}
854
855static int map_conditions(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
856 UnitStatusInfo *i = userdata;
857 const char *cond, *param;
858 int trigger, negate;
859 int32_t state;
860 int r;
861
862 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
863 if (r < 0)
864 return r;
865
866 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
867 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
868
869 c = new(UnitCondition, 1);
870 if (!c)
871 return -ENOMEM;
872
873 *c = (UnitCondition) {
874 .name = strdup(cond),
875 .param = strdup(param),
876 .trigger = trigger,
877 .negate = negate,
878 .tristate = state,
879 };
880
881 if (!c->name || !c->param)
882 return -ENOMEM;
883
884 LIST_PREPEND(conditions, i->conditions, TAKE_PTR(c));
885 }
886 if (r < 0)
887 return r;
888
889 r = sd_bus_message_exit_container(m);
890 if (r < 0)
891 return r;
892
893 return 0;
894}
895
896static int map_asserts(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
897 UnitStatusInfo *i = userdata;
898 const char *cond, *param;
899 int trigger, negate;
900 int32_t state;
901 int r;
902
903 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
904 if (r < 0)
905 return r;
906
907 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
908 if (state < 0 && (!trigger || !i->failed_assert)) {
909 i->failed_assert = cond;
910 i->failed_assert_trigger = trigger;
911 i->failed_assert_negate = negate;
912 i->failed_assert_parameter = param;
913 }
914 }
915 if (r < 0)
916 return r;
917
918 r = sd_bus_message_exit_container(m);
919 if (r < 0)
920 return r;
921
922 return 0;
923}
924
925static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
926 _cleanup_free_ ExecStatusInfo *info = NULL;
927 ExecStatusInfo *last;
928 UnitStatusInfo *i = userdata;
929 bool is_ex_prop = endswith(member, "Ex");
930 int r;
931
932 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
933 if (r < 0)
934 return r;
935
936 info = new0(ExecStatusInfo, 1);
937 if (!info)
938 return -ENOMEM;
939
940 LIST_FIND_TAIL(exec, i->exec, last);
941
942 while ((r = exec_status_info_deserialize(m, info, is_ex_prop)) > 0) {
943
944 info->name = strdup(member);
945 if (!info->name)
946 return -ENOMEM;
947
948 LIST_INSERT_AFTER(exec, i->exec, last, info);
949 last = info;
950
951 info = new0(ExecStatusInfo, 1);
952 if (!info)
953 return -ENOMEM;
954 }
955 if (r < 0)
956 return r;
957
958 r = sd_bus_message_exit_container(m);
959 if (r < 0)
960 return r;
961
962 return 0;
963}
964
8b3d4ff0 965static int print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) {
a032b68d
MB
966 char bus_type;
967 const char *contents;
968 int r;
969
970 assert(name);
971 assert(m);
972
973 /* This is a low-level property printer, see print_status_info() for the nicer output */
974
975 r = sd_bus_message_peek_type(m, &bus_type, &contents);
976 if (r < 0)
977 return r;
978
979 switch (bus_type) {
980
981 case SD_BUS_TYPE_INT32:
982 if (endswith(name, "ActionExitStatus")) {
983 int32_t i;
984
985 r = sd_bus_message_read_basic(m, bus_type, &i);
986 if (r < 0)
987 return r;
988
989 if (i >= 0 && i <= 255)
8b3d4ff0
MB
990 bus_print_property_valuef(name, expected_value, flags, "%"PRIi32, i);
991 else if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY))
992 bus_print_property_value(name, expected_value, flags, "[not set]");
a032b68d
MB
993
994 return 1;
995 } else if (streq(name, "NUMAPolicy")) {
996 int32_t i;
997
998 r = sd_bus_message_read_basic(m, bus_type, &i);
999 if (r < 0)
1000 return r;
1001
8b3d4ff0 1002 bus_print_property_valuef(name, expected_value, flags, "%s", strna(mpol_to_string(i)));
a032b68d
MB
1003
1004 return 1;
1005 }
1006 break;
1007
1008 case SD_BUS_TYPE_STRUCT:
1009
1010 if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
1011 uint32_t u;
1012
1013 r = sd_bus_message_read(m, "(uo)", &u, NULL);
1014 if (r < 0)
1015 return bus_log_parse_error(r);
1016
1017 if (u > 0)
8b3d4ff0
MB
1018 bus_print_property_valuef(name, expected_value, flags, "%"PRIu32, u);
1019 else
1020 bus_print_property_value(name, expected_value, flags, NULL);
a032b68d
MB
1021
1022 return 1;
1023
1024 } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
1025 const char *s;
1026
1027 r = sd_bus_message_read(m, "(so)", &s, NULL);
1028 if (r < 0)
1029 return bus_log_parse_error(r);
1030
8b3d4ff0 1031 bus_print_property_value(name, expected_value, flags, s);
a032b68d
MB
1032
1033 return 1;
1034
1035 } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
1036 const char *a = NULL, *b = NULL;
1037
1038 r = sd_bus_message_read(m, "(ss)", &a, &b);
1039 if (r < 0)
1040 return bus_log_parse_error(r);
1041
1042 if (!isempty(a) || !isempty(b))
8b3d4ff0
MB
1043 bus_print_property_valuef(name, expected_value, flags, "%s \"%s\"", strempty(a), strempty(b));
1044 else
1045 bus_print_property_value(name, expected_value, flags, NULL);
a032b68d
MB
1046
1047 return 1;
1048
1049 } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies")) {
1050 _cleanup_strv_free_ char **l = NULL;
1051 int allow_list;
1052
1053 r = sd_bus_message_enter_container(m, 'r', "bas");
1054 if (r < 0)
1055 return bus_log_parse_error(r);
1056
1057 r = sd_bus_message_read(m, "b", &allow_list);
1058 if (r < 0)
1059 return bus_log_parse_error(r);
1060
1061 r = sd_bus_message_read_strv(m, &l);
1062 if (r < 0)
1063 return bus_log_parse_error(r);
1064
1065 r = sd_bus_message_exit_container(m);
1066 if (r < 0)
1067 return bus_log_parse_error(r);
1068
8b3d4ff0 1069 if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || allow_list || !strv_isempty(l)) {
a032b68d
MB
1070 bool first = true;
1071 char **i;
1072
8b3d4ff0 1073 if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) {
a032b68d
MB
1074 fputs(name, stdout);
1075 fputc('=', stdout);
1076 }
1077
1078 if (!allow_list)
1079 fputc('~', stdout);
1080
1081 STRV_FOREACH(i, l) {
1082 if (first)
1083 first = false;
1084 else
1085 fputc(' ', stdout);
1086
1087 fputs(*i, stdout);
1088 }
1089 fputc('\n', stdout);
1090 }
1091
1092 return 1;
1093
1094 } else if (STR_IN_SET(name, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
1095 int ignore;
1096 const char *s;
1097
1098 r = sd_bus_message_read(m, "(bs)", &ignore, &s);
1099 if (r < 0)
1100 return bus_log_parse_error(r);
1101
1102 if (!isempty(s))
8b3d4ff0
MB
1103 bus_print_property_valuef(name, expected_value, flags, "%s%s", ignore ? "-" : "", s);
1104 else
1105 bus_print_property_value(name, expected_value, flags, NULL);
a032b68d
MB
1106
1107 return 1;
1108
1109 } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
1110 const int32_t *status, *signal;
3a6ce677 1111 size_t n_status, n_signal;
a032b68d
MB
1112
1113 r = sd_bus_message_enter_container(m, 'r', "aiai");
1114 if (r < 0)
1115 return bus_log_parse_error(r);
1116
1117 r = sd_bus_message_read_array(m, 'i', (const void **) &status, &n_status);
1118 if (r < 0)
1119 return bus_log_parse_error(r);
1120
1121 r = sd_bus_message_read_array(m, 'i', (const void **) &signal, &n_signal);
1122 if (r < 0)
1123 return bus_log_parse_error(r);
1124
1125 r = sd_bus_message_exit_container(m);
1126 if (r < 0)
1127 return bus_log_parse_error(r);
1128
1129 n_status /= sizeof(int32_t);
1130 n_signal /= sizeof(int32_t);
1131
8b3d4ff0 1132 if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || n_status > 0 || n_signal > 0) {
a032b68d
MB
1133 bool first = true;
1134
8b3d4ff0 1135 if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) {
a032b68d
MB
1136 fputs(name, stdout);
1137 fputc('=', stdout);
1138 }
1139
3a6ce677 1140 for (size_t i = 0; i < n_status; i++) {
a032b68d
MB
1141 if (first)
1142 first = false;
1143 else
1144 fputc(' ', stdout);
1145
1146 printf("%"PRIi32, status[i]);
1147 }
1148
3a6ce677 1149 for (size_t i = 0; i < n_signal; i++) {
a032b68d
MB
1150 const char *str;
1151
1152 str = signal_to_string((int) signal[i]);
1153
1154 if (first)
1155 first = false;
1156 else
1157 fputc(' ', stdout);
1158
1159 if (str)
1160 fputs(str, stdout);
1161 else
1162 printf("%"PRIi32, status[i]);
1163 }
1164
1165 fputc('\n', stdout);
1166 }
1167 return 1;
1168 }
1169
1170 break;
1171
1172 case SD_BUS_TYPE_ARRAY:
1173
1174 if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
1175 const char *path;
1176 int ignore;
1177
1178 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
1179 if (r < 0)
1180 return bus_log_parse_error(r);
1181
1182 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
8b3d4ff0 1183 bus_print_property_valuef(name, expected_value, flags, "%s (ignore_errors=%s)", path, yes_no(ignore));
a032b68d
MB
1184 if (r < 0)
1185 return bus_log_parse_error(r);
1186
1187 r = sd_bus_message_exit_container(m);
1188 if (r < 0)
1189 return bus_log_parse_error(r);
1190
1191 return 1;
1192
1193 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
1194 const char *type, *path;
1195
1196 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1197 if (r < 0)
1198 return bus_log_parse_error(r);
1199
1200 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
8b3d4ff0 1201 bus_print_property_valuef(name, expected_value, flags, "%s (%s)", path, type);
a032b68d
MB
1202 if (r < 0)
1203 return bus_log_parse_error(r);
1204
1205 r = sd_bus_message_exit_container(m);
1206 if (r < 0)
1207 return bus_log_parse_error(r);
1208
1209 return 1;
1210
1211 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
1212 const char *type, *path;
1213
1214 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1215 if (r < 0)
1216 return bus_log_parse_error(r);
1217
1218 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
8b3d4ff0 1219 bus_print_property_valuef(name, expected_value, flags, "%s (%s)", path, type);
a032b68d
MB
1220 if (r < 0)
1221 return bus_log_parse_error(r);
1222
1223 r = sd_bus_message_exit_container(m);
1224 if (r < 0)
1225 return bus_log_parse_error(r);
1226
1227 return 1;
1228
1229 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
1230 const char *base;
1231 uint64_t v, next_elapse;
1232
1233 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
1234 if (r < 0)
1235 return bus_log_parse_error(r);
1236
1237 while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
1238 char timespan1[FORMAT_TIMESPAN_MAX] = "n/a", timespan2[FORMAT_TIMESPAN_MAX] = "n/a";
1239
1240 (void) format_timespan(timespan1, sizeof timespan1, v, 0);
1241 (void) format_timespan(timespan2, sizeof timespan2, next_elapse, 0);
1242
8b3d4ff0 1243 bus_print_property_valuef(name, expected_value, flags,
a032b68d
MB
1244 "{ %s=%s ; next_elapse=%s }", base, timespan1, timespan2);
1245 }
1246 if (r < 0)
1247 return bus_log_parse_error(r);
1248
1249 r = sd_bus_message_exit_container(m);
1250 if (r < 0)
1251 return bus_log_parse_error(r);
1252
1253 return 1;
1254
1255 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersCalendar")) {
1256 const char *base, *spec;
1257 uint64_t next_elapse;
1258
1259 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
1260 if (r < 0)
1261 return bus_log_parse_error(r);
1262
1263 while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
1264 char timestamp[FORMAT_TIMESTAMP_MAX] = "n/a";
1265
1266 (void) format_timestamp_style(timestamp, sizeof(timestamp), next_elapse, arg_timestamp_style);
8b3d4ff0 1267 bus_print_property_valuef(name, expected_value, flags,
a032b68d
MB
1268 "{ %s=%s ; next_elapse=%s }", base, spec, timestamp);
1269 }
1270 if (r < 0)
1271 return bus_log_parse_error(r);
1272
1273 r = sd_bus_message_exit_container(m);
1274 if (r < 0)
1275 return bus_log_parse_error(r);
1276
1277 return 1;
1278
1279 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
1280 ExecStatusInfo info = {};
1281 bool is_ex_prop = endswith(name, "Ex");
1282
1283 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
1284 if (r < 0)
1285 return bus_log_parse_error(r);
1286
1287 while ((r = exec_status_info_deserialize(m, &info, is_ex_prop)) > 0) {
1288 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
1289 _cleanup_strv_free_ char **optv = NULL;
5b5a102a 1290 _cleanup_free_ char *tt = NULL, *o = NULL;
a032b68d
MB
1291
1292 tt = strv_join(info.argv, " ");
1293
1294 if (is_ex_prop) {
1295 r = exec_command_flags_to_strv(info.flags, &optv);
1296 if (r < 0)
1297 return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
1298
1299 o = strv_join(optv, " ");
1300
8b3d4ff0 1301 bus_print_property_valuef(name, expected_value, flags,
a032b68d
MB
1302 "{ path=%s ; argv[]=%s ; flags=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
1303 strna(info.path),
1304 strna(tt),
1305 strna(o),
1306 strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
1307 strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
1308 info.pid,
1309 sigchld_code_to_string(info.code),
1310 info.status,
1311 info.code == CLD_EXITED ? "" : "/",
1312 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1313 } else
8b3d4ff0 1314 bus_print_property_valuef(name, expected_value, flags,
a032b68d
MB
1315 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
1316 strna(info.path),
1317 strna(tt),
1318 yes_no(info.ignore),
1319 strna(format_timestamp_style(timestamp1, sizeof(timestamp1), info.start_timestamp, arg_timestamp_style)),
1320 strna(format_timestamp_style(timestamp2, sizeof(timestamp2), info.exit_timestamp, arg_timestamp_style)),
1321 info.pid,
1322 sigchld_code_to_string(info.code),
1323 info.status,
1324 info.code == CLD_EXITED ? "" : "/",
1325 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1326
1327 free(info.path);
1328 strv_free(info.argv);
1329 zero(info);
1330 }
1331
1332 r = sd_bus_message_exit_container(m);
1333 if (r < 0)
1334 return bus_log_parse_error(r);
1335
1336 return 1;
1337
1338 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
1339 const char *path, *rwm;
1340
1341 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1342 if (r < 0)
1343 return bus_log_parse_error(r);
1344
1345 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
8b3d4ff0 1346 bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path), strna(rwm));
a032b68d
MB
1347 if (r < 0)
1348 return bus_log_parse_error(r);
1349
1350 r = sd_bus_message_exit_container(m);
1351 if (r < 0)
1352 return bus_log_parse_error(r);
1353
1354 return 1;
1355
1356 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
1357 STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
1358 const char *path;
1359 uint64_t weight;
1360
1361 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
1362 if (r < 0)
1363 return bus_log_parse_error(r);
1364
1365 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
8b3d4ff0 1366 bus_print_property_valuef(name, expected_value, flags, "%s %"PRIu64, strna(path), weight);
a032b68d
MB
1367 if (r < 0)
1368 return bus_log_parse_error(r);
1369
1370 r = sd_bus_message_exit_container(m);
1371 if (r < 0)
1372 return bus_log_parse_error(r);
1373
1374 return 1;
1375
1376 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
1377 (cgroup_io_limit_type_from_string(name) >= 0 ||
1378 STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
1379 const char *path;
1380 uint64_t bandwidth;
1381
1382 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
1383 if (r < 0)
1384 return bus_log_parse_error(r);
1385
1386 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
8b3d4ff0 1387 bus_print_property_valuef(name, expected_value, flags, "%s %"PRIu64, strna(path), bandwidth);
a032b68d
MB
1388 if (r < 0)
1389 return bus_log_parse_error(r);
1390
1391 r = sd_bus_message_exit_container(m);
1392 if (r < 0)
1393 return bus_log_parse_error(r);
1394
1395 return 1;
1396
1397 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
1398 streq(name, "IODeviceLatencyTargetUSec")) {
1399 char ts[FORMAT_TIMESPAN_MAX];
1400 const char *path;
1401 uint64_t target;
1402
1403 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
1404 if (r < 0)
1405 return bus_log_parse_error(r);
1406
1407 while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
8b3d4ff0 1408 bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path),
a032b68d
MB
1409 format_timespan(ts, sizeof(ts), target, 1));
1410 if (r < 0)
1411 return bus_log_parse_error(r);
1412
1413 r = sd_bus_message_exit_container(m);
1414 if (r < 0)
1415 return bus_log_parse_error(r);
1416
1417 return 1;
1418
1419 } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "StandardInputData", "RootHashSignature")) {
1420 _cleanup_free_ char *h = NULL;
1421 const void *p;
1422 size_t sz;
1423 ssize_t n;
1424
1425 r = sd_bus_message_read_array(m, 'y', &p, &sz);
1426 if (r < 0)
1427 return bus_log_parse_error(r);
1428
1429 n = base64mem(p, sz, &h);
1430 if (n < 0)
1431 return log_oom();
1432
8b3d4ff0 1433 bus_print_property_value(name, expected_value, flags, h);
a032b68d
MB
1434
1435 return 1;
1436
1437 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1438 _cleanup_free_ char *addresses = NULL;
1439
1440 r = sd_bus_message_enter_container(m, 'a', "(iayu)");
1441 if (r < 0)
1442 return bus_log_parse_error(r);
1443
1444 for (;;) {
1445 _cleanup_free_ char *str = NULL;
1446 uint32_t prefixlen;
1447 int32_t family;
1448 const void *ap;
1449 size_t an;
1450
1451 r = sd_bus_message_enter_container(m, 'r', "iayu");
1452 if (r < 0)
1453 return bus_log_parse_error(r);
1454 if (r == 0)
1455 break;
1456
1457 r = sd_bus_message_read(m, "i", &family);
1458 if (r < 0)
1459 return bus_log_parse_error(r);
1460
1461 r = sd_bus_message_read_array(m, 'y', &ap, &an);
1462 if (r < 0)
1463 return bus_log_parse_error(r);
1464
1465 r = sd_bus_message_read(m, "u", &prefixlen);
1466 if (r < 0)
1467 return bus_log_parse_error(r);
1468
1469 r = sd_bus_message_exit_container(m);
1470 if (r < 0)
1471 return bus_log_parse_error(r);
1472
1473 if (!IN_SET(family, AF_INET, AF_INET6))
1474 continue;
1475
1476 if (an != FAMILY_ADDRESS_SIZE(family))
1477 continue;
1478
1479 if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
1480 continue;
1481
3a6ce677 1482 if (in_addr_prefix_to_string(family, (const union in_addr_union*) ap, prefixlen, &str) < 0)
a032b68d
MB
1483 continue;
1484
3a6ce677 1485 if (!strextend_with_separator(&addresses, " ", str))
a032b68d
MB
1486 return log_oom();
1487 }
1488
1489 r = sd_bus_message_exit_container(m);
1490 if (r < 0)
1491 return bus_log_parse_error(r);
1492
8b3d4ff0 1493 bus_print_property_value(name, expected_value, flags, addresses);
a032b68d
MB
1494
1495 return 1;
1496
1497 } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
1498 _cleanup_free_ char *paths = NULL;
1499 const char *source, *dest;
1500 int ignore_enoent;
1501 uint64_t rbind;
1502
1503 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssbt)");
1504 if (r < 0)
1505 return bus_log_parse_error(r);
1506
1507 while ((r = sd_bus_message_read(m, "(ssbt)", &source, &dest, &ignore_enoent, &rbind)) > 0) {
1508 _cleanup_free_ char *str = NULL;
1509
1510 if (isempty(source))
1511 continue;
1512
1513 if (asprintf(&str, "%s%s%s%s%s",
1514 ignore_enoent ? "-" : "",
1515 source,
1516 isempty(dest) ? "" : ":",
1517 strempty(dest),
1518 rbind == MS_REC ? ":rbind" : "") < 0)
1519 return log_oom();
1520
3a6ce677 1521 if (!strextend_with_separator(&paths, " ", str))
a032b68d
MB
1522 return log_oom();
1523 }
1524 if (r < 0)
1525 return bus_log_parse_error(r);
1526
1527 r = sd_bus_message_exit_container(m);
1528 if (r < 0)
1529 return bus_log_parse_error(r);
1530
8b3d4ff0 1531 bus_print_property_value(name, expected_value, flags, paths);
a032b68d
MB
1532
1533 return 1;
1534
1535 } else if (streq(name, "TemporaryFileSystem")) {
1536 _cleanup_free_ char *paths = NULL;
1537 const char *target, *option;
1538
1539 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1540 if (r < 0)
1541 return bus_log_parse_error(r);
1542
1543 while ((r = sd_bus_message_read(m, "(ss)", &target, &option)) > 0) {
1544 _cleanup_free_ char *str = NULL;
1545
1546 if (isempty(target))
1547 continue;
1548
1549 if (asprintf(&str, "%s%s%s", target, isempty(option) ? "" : ":", strempty(option)) < 0)
1550 return log_oom();
1551
3a6ce677 1552 if (!strextend_with_separator(&paths, " ", str))
a032b68d
MB
1553 return log_oom();
1554 }
1555 if (r < 0)
1556 return bus_log_parse_error(r);
1557
1558 r = sd_bus_message_exit_container(m);
1559 if (r < 0)
1560 return bus_log_parse_error(r);
1561
8b3d4ff0 1562 bus_print_property_value(name, expected_value, flags, paths);
a032b68d
MB
1563
1564 return 1;
1565
1566 } else if (streq(name, "LogExtraFields")) {
1567 _cleanup_free_ char *fields = NULL;
1568 const void *p;
1569 size_t sz;
1570
1571 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "ay");
1572 if (r < 0)
1573 return bus_log_parse_error(r);
1574
1575 while ((r = sd_bus_message_read_array(m, 'y', &p, &sz)) > 0) {
1576 _cleanup_free_ char *str = NULL;
1577 const char *eq;
1578
1579 if (memchr(p, 0, sz))
1580 continue;
1581
1582 eq = memchr(p, '=', sz);
1583 if (!eq)
1584 continue;
1585
1586 if (!journal_field_valid(p, eq - (const char*) p, false))
1587 continue;
1588
1589 str = malloc(sz + 1);
1590 if (!str)
1591 return log_oom();
1592
1593 memcpy(str, p, sz);
1594 str[sz] = '\0';
1595
1596 if (!utf8_is_valid(str))
1597 continue;
1598
3a6ce677 1599 if (!strextend_with_separator(&fields, " ", str))
a032b68d
MB
1600 return log_oom();
1601 }
1602 if (r < 0)
1603 return bus_log_parse_error(r);
1604
1605 r = sd_bus_message_exit_container(m);
1606 if (r < 0)
1607 return bus_log_parse_error(r);
1608
8b3d4ff0 1609 bus_print_property_value(name, expected_value, flags, fields);
a032b68d
MB
1610
1611 return 1;
8b3d4ff0
MB
1612 } else if (contents[0] == SD_BUS_TYPE_BYTE &&
1613 STR_IN_SET(name,
1614 "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes",
1615 "EffectiveCPUs", "EffectiveMemoryNodes")) {
1616
a032b68d
MB
1617 _cleanup_free_ char *affinity = NULL;
1618 _cleanup_(cpu_set_reset) CPUSet set = {};
1619 const void *a;
1620 size_t n;
1621
1622 r = sd_bus_message_read_array(m, 'y', &a, &n);
1623 if (r < 0)
1624 return bus_log_parse_error(r);
1625
1626 r = cpu_set_from_dbus(a, n, &set);
1627 if (r < 0)
1628 return log_error_errno(r, "Failed to deserialize %s: %m", name);
1629
1630 affinity = cpu_set_to_range_string(&set);
1631 if (!affinity)
1632 return log_oom();
1633
8b3d4ff0 1634 bus_print_property_value(name, expected_value, flags, affinity);
a032b68d
MB
1635
1636 return 1;
1637 } else if (streq(name, "MountImages")) {
1638 _cleanup_free_ char *paths = NULL;
1639
1640 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssba(ss))");
1641 if (r < 0)
1642 return bus_log_parse_error(r);
1643
1644 for (;;) {
1645 _cleanup_free_ char *str = NULL;
1646 const char *source, *destination, *partition, *mount_options;
1647 int ignore_enoent;
1648
1649 r = sd_bus_message_enter_container(m, 'r', "ssba(ss)");
1650 if (r < 0)
1651 return r;
1652
1653 r = sd_bus_message_read(m, "ssb", &source, &destination, &ignore_enoent);
1654 if (r <= 0)
1655 break;
1656
1657 str = strjoin(ignore_enoent ? "-" : "",
1658 source,
1659 ":",
1660 destination);
1661 if (!str)
1662 return log_oom();
1663
1664 r = sd_bus_message_enter_container(m, 'a', "(ss)");
1665 if (r < 0)
1666 return r;
1667
8b3d4ff0
MB
1668 while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0)
1669 if (!strextend_with_separator(&str, ":", partition, ":", mount_options))
a032b68d 1670 return log_oom();
a032b68d
MB
1671 if (r < 0)
1672 return r;
1673
3a6ce677 1674 if (!strextend_with_separator(&paths, " ", str))
a032b68d
MB
1675 return log_oom();
1676
1677 r = sd_bus_message_exit_container(m);
1678 if (r < 0)
1679 return r;
1680
1681 r = sd_bus_message_exit_container(m);
1682 if (r < 0)
1683 return r;
1684 }
1685 if (r < 0)
1686 return bus_log_parse_error(r);
1687
1688 r = sd_bus_message_exit_container(m);
1689 if (r < 0)
1690 return bus_log_parse_error(r);
1691
8b3d4ff0
MB
1692 bus_print_property_value(name, expected_value, flags, paths);
1693
1694 return 1;
1695
1696 } else if (streq(name, "BPFProgram")) {
1697 const char *a, *p;
1698
1699 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1700 if (r < 0)
1701 return bus_log_parse_error(r);
1702
1703 while ((r = sd_bus_message_read(m, "(ss)", &a, &p)) > 0)
1704 bus_print_property_valuef(name, expected_value, flags, "%s:%s", a, p);
1705 if (r < 0)
1706 return bus_log_parse_error(r);
1707
1708 r = sd_bus_message_exit_container(m);
1709 if (r < 0)
1710 return bus_log_parse_error(r);
a032b68d
MB
1711
1712 return 1;
8b3d4ff0
MB
1713 } else if (STR_IN_SET(name, "SocketBindAllow", "SocketBindDeny")) {
1714 uint16_t nr_ports, port_min;
1715 int32_t af, ip_protocol;
a032b68d 1716
8b3d4ff0
MB
1717 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(iiqq)");
1718 if (r < 0)
1719 return bus_log_parse_error(r);
1720 while ((r = sd_bus_message_read(m, "(iiqq)", &af, &ip_protocol, &nr_ports, &port_min)) > 0) {
1721 const char *family, *colon;
1722
1723 family = strempty(af_to_ipv4_ipv6(af));
1724 colon = isempty(family) ? "" : ":";
1725
1726 if (nr_ports == 0)
1727 bus_print_property_valuef(name, expected_value, flags, "%s%sany", family, colon);
1728 else if (nr_ports == 1)
1729 bus_print_property_valuef(
1730 name, expected_value, flags, "%s%s%hu", family, colon, port_min);
1731 else
1732 bus_print_property_valuef(
1733 name, expected_value, flags, "%s%s%hu-%hu", family, colon, port_min,
1734 (uint16_t) (port_min + nr_ports - 1));
1735 }
1736 if (r < 0)
1737 return bus_log_parse_error(r);
1738
1739 r = sd_bus_message_exit_container(m);
1740 if (r < 0)
1741 return bus_log_parse_error(r);
1742
1743 return 1;
a032b68d
MB
1744 }
1745
1746 break;
1747 }
1748
1749 return 0;
1750}
1751
1752typedef enum SystemctlShowMode{
1753 SYSTEMCTL_SHOW_PROPERTIES,
1754 SYSTEMCTL_SHOW_STATUS,
1755 SYSTEMCTL_SHOW_HELP,
1756 _SYSTEMCTL_SHOW_MODE_MAX,
3a6ce677 1757 _SYSTEMCTL_SHOW_MODE_INVALID = -EINVAL,
a032b68d
MB
1758} SystemctlShowMode;
1759
1760static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
1761 [SYSTEMCTL_SHOW_PROPERTIES] = "show",
1762 [SYSTEMCTL_SHOW_STATUS] = "status",
1763 [SYSTEMCTL_SHOW_HELP] = "help",
1764};
1765
1766DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode, SystemctlShowMode);
1767
1768static int show_one(
1769 sd_bus *bus,
1770 const char *path,
1771 const char *unit,
1772 SystemctlShowMode show_mode,
1773 bool *new_line,
1774 bool *ellipsized) {
1775
1776 static const struct bus_properties_map property_map[] = {
1777 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
1778 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
1779 { "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
1780 { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
1781 {}
1782 }, status_map[] = {
1783 { "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
1784 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
1785 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
1786 { "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
1787 { "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
1788 { "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
1789 { "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },
1790 { "Description", "s", NULL, offsetof(UnitStatusInfo, description) },
1791 { "Following", "s", NULL, offsetof(UnitStatusInfo, following) },
1792 { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
1793 { "FragmentPath", "s", NULL, offsetof(UnitStatusInfo, fragment_path) },
1794 { "SourcePath", "s", NULL, offsetof(UnitStatusInfo, source_path) },
1795 { "ControlGroup", "s", NULL, offsetof(UnitStatusInfo, control_group) },
1796 { "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) },
1797 { "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) },
1798 { "Result", "s", NULL, offsetof(UnitStatusInfo, result) },
1799 { "TriggeredBy", "as", NULL, offsetof(UnitStatusInfo, triggered_by) },
1800 { "Triggers", "as", NULL, offsetof(UnitStatusInfo, triggers) },
1801 { "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) },
1802 { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
1803 { "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) },
1804 { "ActiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_exit_timestamp) },
1805 { "InactiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_enter_timestamp) },
1806 { "NeedDaemonReload", "b", NULL, offsetof(UnitStatusInfo, need_daemon_reload) },
1807 { "Transient", "b", NULL, offsetof(UnitStatusInfo, transient) },
1808 { "ExecMainPID", "u", NULL, offsetof(UnitStatusInfo, main_pid) },
1809 { "MainPID", "u", map_main_pid, 0 },
1810 { "ControlPID", "u", NULL, offsetof(UnitStatusInfo, control_pid) },
1811 { "StatusText", "s", NULL, offsetof(UnitStatusInfo, status_text) },
1812 { "PIDFile", "s", NULL, offsetof(UnitStatusInfo, pid_file) },
1813 { "StatusErrno", "i", NULL, offsetof(UnitStatusInfo, status_errno) },
1814 { "ExecMainStartTimestamp", "t", NULL, offsetof(UnitStatusInfo, start_timestamp) },
1815 { "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
1816 { "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
1817 { "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
1818 { "LogNamespace", "s", NULL, offsetof(UnitStatusInfo, log_namespace) },
1819 { "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
1820 { "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
1821 { "Conditions", "a(sbbsi)", map_conditions, 0 },
1822 { "AssertTimestamp", "t", NULL, offsetof(UnitStatusInfo, assert_timestamp) },
1823 { "AssertResult", "b", NULL, offsetof(UnitStatusInfo, assert_result) },
1824 { "Asserts", "a(sbbsi)", map_asserts, 0 },
1825 { "NextElapseUSecRealtime", "t", NULL, offsetof(UnitStatusInfo, next_elapse_real) },
1826 { "NextElapseUSecMonotonic", "t", NULL, offsetof(UnitStatusInfo, next_elapse_monotonic) },
1827 { "NAccepted", "u", NULL, offsetof(UnitStatusInfo, n_accepted) },
1828 { "NConnections", "u", NULL, offsetof(UnitStatusInfo, n_connections) },
1829 { "NRefused", "u", NULL, offsetof(UnitStatusInfo, n_refused) },
1830 { "Accept", "b", NULL, offsetof(UnitStatusInfo, accept) },
1831 { "Listen", "a(ss)", map_listen, offsetof(UnitStatusInfo, listen) },
1832 { "SysFSPath", "s", NULL, offsetof(UnitStatusInfo, sysfs_path) },
1833 { "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
1834 { "What", "s", NULL, offsetof(UnitStatusInfo, what) },
1835 { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
8b3d4ff0 1836 { "MemoryAvailable", "t", NULL, offsetof(UnitStatusInfo, memory_available) },
a032b68d
MB
1837 { "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
1838 { "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
1839 { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
1840 { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
1841 { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
1842 { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) },
1843 { "MemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_swap_max) },
1844 { "MemoryLimit", "t", NULL, offsetof(UnitStatusInfo, memory_limit) },
1845 { "CPUUsageNSec", "t", NULL, offsetof(UnitStatusInfo, cpu_usage_nsec) },
1846 { "TasksCurrent", "t", NULL, offsetof(UnitStatusInfo, tasks_current) },
1847 { "TasksMax", "t", NULL, offsetof(UnitStatusInfo, tasks_max) },
1848 { "IPIngressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_ingress_bytes) },
1849 { "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
1850 { "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) },
1851 { "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) },
1852 { "ExecCondition", "a(sasbttttuii)", map_exec, 0 },
1853 { "ExecConditionEx", "a(sasasttttuii)", map_exec, 0 },
1854 { "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
1855 { "ExecStartPreEx", "a(sasasttttuii)", map_exec, 0 },
1856 { "ExecStart", "a(sasbttttuii)", map_exec, 0 },
1857 { "ExecStartEx", "a(sasasttttuii)", map_exec, 0 },
1858 { "ExecStartPost", "a(sasbttttuii)", map_exec, 0 },
1859 { "ExecStartPostEx", "a(sasasttttuii)", map_exec, 0 },
1860 { "ExecReload", "a(sasbttttuii)", map_exec, 0 },
1861 { "ExecReloadEx", "a(sasasttttuii)", map_exec, 0 },
1862 { "ExecStopPre", "a(sasbttttuii)", map_exec, 0 },
1863 { "ExecStop", "a(sasbttttuii)", map_exec, 0 },
1864 { "ExecStopEx", "a(sasasttttuii)", map_exec, 0 },
1865 { "ExecStopPost", "a(sasbttttuii)", map_exec, 0 },
1866 { "ExecStopPostEx", "a(sasasttttuii)", map_exec, 0 },
1867 {}
1868 };
1869
1870 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1871 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1872 _cleanup_set_free_ Set *found_properties = NULL;
1873 _cleanup_(unit_status_info_free) UnitStatusInfo info = {
3a6ce677 1874 .memory_current = UINT64_MAX,
a032b68d
MB
1875 .memory_high = CGROUP_LIMIT_MAX,
1876 .memory_max = CGROUP_LIMIT_MAX,
1877 .memory_swap_max = CGROUP_LIMIT_MAX,
3a6ce677 1878 .memory_limit = UINT64_MAX,
8b3d4ff0 1879 .memory_available = CGROUP_LIMIT_MAX,
3a6ce677
BR
1880 .cpu_usage_nsec = UINT64_MAX,
1881 .tasks_current = UINT64_MAX,
1882 .tasks_max = UINT64_MAX,
1883 .ip_ingress_bytes = UINT64_MAX,
1884 .ip_egress_bytes = UINT64_MAX,
a032b68d
MB
1885 .io_read_bytes = UINT64_MAX,
1886 .io_write_bytes = UINT64_MAX,
1887 };
1888 char **pp;
1889 int r;
1890
1891 assert(path);
1892 assert(new_line);
1893
1894 log_debug("Showing one %s", path);
1895
1896 r = bus_map_all_properties(
1897 bus,
1898 "org.freedesktop.systemd1",
1899 path,
1900 show_mode == SYSTEMCTL_SHOW_STATUS ? status_map : property_map,
1901 BUS_MAP_BOOLEAN_AS_BOOL,
1902 &error,
1903 &reply,
1904 &info);
1905 if (r < 0)
1906 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
1907
1908 if (unit && streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
1909 log_full(show_mode == SYSTEMCTL_SHOW_STATUS ? LOG_ERR : LOG_DEBUG,
1910 "Unit %s could not be found.", unit);
1911
1912 if (show_mode == SYSTEMCTL_SHOW_STATUS)
1913 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
1914 else if (show_mode == SYSTEMCTL_SHOW_HELP)
1915 return -ENOENT;
1916 }
1917
1918 if (*new_line)
1919 printf("\n");
1920
1921 *new_line = true;
1922
1923 if (show_mode == SYSTEMCTL_SHOW_STATUS) {
1924 print_status_info(bus, &info, ellipsized);
1925
1926 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
1927 return EXIT_PROGRAM_NOT_RUNNING;
1928
1929 return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
1930
1931 } else if (show_mode == SYSTEMCTL_SHOW_HELP) {
1932 show_unit_help(&info);
1933 return 0;
1934 }
1935
1936 r = sd_bus_message_rewind(reply, true);
1937 if (r < 0)
1938 return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
1939
8b3d4ff0 1940 r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_print_flags, &found_properties);
a032b68d
MB
1941 if (r < 0)
1942 return bus_log_parse_error(r);
1943
1944 STRV_FOREACH(pp, arg_properties)
1945 if (!set_contains(found_properties, *pp))
1946 log_debug("Property %s does not exist.", *pp);
1947
1948 return 0;
1949}
1950
1951static int get_unit_dbus_path_by_pid(
1952 sd_bus *bus,
1953 uint32_t pid,
1954 char **unit) {
1955
1956 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1957 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1958 char *u;
1959 int r;
1960
1961 r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
1962 if (r < 0)
1963 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
1964
1965 r = sd_bus_message_read(reply, "o", &u);
1966 if (r < 0)
1967 return bus_log_parse_error(r);
1968
1969 u = strdup(u);
1970 if (!u)
1971 return log_oom();
1972
1973 *unit = u;
1974 return 0;
1975}
1976
1977static int show_all(
1978 sd_bus *bus,
1979 bool *new_line,
1980 bool *ellipsized) {
1981
1982 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1983 _cleanup_free_ UnitInfo *unit_infos = NULL;
a032b68d
MB
1984 unsigned c;
1985 int r, ret = 0;
1986
1987 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
1988 if (r < 0)
1989 return r;
1990
1991 (void) pager_open(arg_pager_flags);
1992
1993 c = (unsigned) r;
1994
1995 typesafe_qsort(unit_infos, c, unit_info_compare);
1996
3a6ce677 1997 for (const UnitInfo *u = unit_infos; u < unit_infos + c; u++) {
a032b68d
MB
1998 _cleanup_free_ char *p = NULL;
1999
2000 p = unit_dbus_path_from_name(u->id);
2001 if (!p)
2002 return log_oom();
2003
2004 r = show_one(bus, p, u->id, SYSTEMCTL_SHOW_STATUS, new_line, ellipsized);
2005 if (r < 0)
2006 return r;
2007 else if (r > 0 && ret == 0)
2008 ret = r;
2009 }
2010
2011 return ret;
2012}
2013
2014static int show_system_status(sd_bus *bus) {
2015 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
2016 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2017 _cleanup_(machine_info_clear) struct machine_info mi = {};
2018 _cleanup_free_ char *hn = NULL;
2019 const char *on, *off;
2020 int r;
2021
2022 hn = gethostname_malloc();
2023 if (!hn)
2024 return log_oom();
2025
2026 r = bus_map_all_properties(
2027 bus,
2028 "org.freedesktop.systemd1",
2029 "/org/freedesktop/systemd1",
2030 machine_info_property_map,
2031 BUS_MAP_STRDUP,
2032 &error,
2033 NULL,
2034 &mi);
2035 if (r < 0)
2036 return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
2037
2038 if (streq_ptr(mi.state, "degraded")) {
2039 on = ansi_highlight_red();
2040 off = ansi_normal();
2041 } else if (streq_ptr(mi.state, "running")) {
2042 on = ansi_highlight_green();
2043 off = ansi_normal();
2044 } else {
2045 on = ansi_highlight_yellow();
2046 off = ansi_normal();
2047 }
2048
2049 printf("%s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
2050
2051 printf(" State: %s%s%s\n",
2052 on, strna(mi.state), off);
2053
2054 printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
2055 printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
2056
2057 printf(" Since: %s; %s\n",
2058 format_timestamp_style(since2, sizeof(since2), mi.timestamp, arg_timestamp_style),
2059 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
2060
2061 printf(" CGroup: %s\n", mi.control_group ?: "/");
2062 if (IN_SET(arg_transport,
2063 BUS_TRANSPORT_LOCAL,
2064 BUS_TRANSPORT_MACHINE)) {
2065 static const char prefix[] = " ";
2066 unsigned c;
2067
2068 c = columns();
2069 if (c > sizeof(prefix) - 1)
2070 c -= sizeof(prefix) - 1;
2071 else
2072 c = 0;
2073
2074 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
2075 }
2076
2077 return 0;
2078}
2079
2080int show(int argc, char *argv[], void *userdata) {
2081 bool new_line = false, ellipsized = false;
2082 SystemctlShowMode show_mode;
2083 int r, ret = 0;
2084 sd_bus *bus;
2085
2086 assert(argv);
2087
2088 show_mode = systemctl_show_mode_from_string(argv[0]);
2089 if (show_mode < 0)
3a6ce677 2090 return log_error_errno(show_mode, "Invalid argument.");
a032b68d
MB
2091
2092 if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
2093 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2094 "'help' command expects one or more unit names.\n"
2095 "(Alternatively, help for systemctl itself may be shown with --help)");
2096
2097 r = acquire_bus(BUS_MANAGER, &bus);
2098 if (r < 0)
2099 return r;
2100
2101 (void) pager_open(arg_pager_flags);
2102
2103 /* If no argument is specified inspect the manager itself */
2104 if (show_mode == SYSTEMCTL_SHOW_PROPERTIES && argc <= 1)
2105 return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
2106
2107 if (show_mode == SYSTEMCTL_SHOW_STATUS && argc <= 1) {
2108
2109 show_system_status(bus);
2110 new_line = true;
2111
2112 if (arg_all)
2113 ret = show_all(bus, &new_line, &ellipsized);
2114 } else {
2115 _cleanup_free_ char **patterns = NULL;
2116 char **name;
2117
2118 STRV_FOREACH(name, strv_skip(argv, 1)) {
2119 _cleanup_free_ char *path = NULL, *unit = NULL;
2120 uint32_t id;
2121
2122 if (safe_atou32(*name, &id) < 0) {
2123 if (strv_push(&patterns, *name) < 0)
2124 return log_oom();
2125
2126 continue;
2127 } else if (show_mode == SYSTEMCTL_SHOW_PROPERTIES) {
2128 /* Interpret as job id */
2129 if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
2130 return log_oom();
2131
2132 } else {
2133 /* Interpret as PID */
2134 r = get_unit_dbus_path_by_pid(bus, id, &path);
2135 if (r < 0) {
2136 ret = r;
2137 continue;
2138 }
2139
2140 r = unit_name_from_dbus_path(path, &unit);
2141 if (r < 0)
2142 return log_oom();
2143 }
2144
2145 r = show_one(bus, path, unit, show_mode, &new_line, &ellipsized);
2146 if (r < 0)
2147 return r;
2148 else if (r > 0 && ret == 0)
2149 ret = r;
2150 }
2151
2152 if (!strv_isempty(patterns)) {
2153 _cleanup_strv_free_ char **names = NULL;
2154
2155 r = expand_unit_names(bus, patterns, NULL, &names, NULL);
2156 if (r < 0)
2157 return log_error_errno(r, "Failed to expand names: %m");
2158
2159 r = maybe_extend_with_unit_dependencies(bus, &names);
2160 if (r < 0)
2161 return r;
2162
2163 STRV_FOREACH(name, names) {
5b5a102a 2164 _cleanup_free_ char *path = NULL;
a032b68d
MB
2165
2166 path = unit_dbus_path_from_name(*name);
2167 if (!path)
2168 return log_oom();
2169
2170 r = show_one(bus, path, *name, show_mode, &new_line, &ellipsized);
2171 if (r < 0)
2172 return r;
2173 if (r > 0 && ret == 0)
2174 ret = r;
2175 }
2176 }
2177 }
2178
2179 if (ellipsized && !arg_quiet)
2180 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
2181
2182 return ret;
2183}