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