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