1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/reboot.h>
29 #include <sys/ioctl.h>
33 #include <sys/socket.h>
36 #include <sys/prctl.h>
37 #include <dbus/dbus.h>
39 #include <systemd/sd-daemon.h>
40 #include <systemd/sd-shutdown.h>
41 #include <systemd/sd-login.h>
47 #include "utmp-wtmp.h"
50 #include "path-util.h"
52 #include "dbus-common.h"
53 #include "cgroup-show.h"
54 #include "cgroup-util.h"
56 #include "path-lookup.h"
57 #include "conf-parser.h"
58 #include "exit-status.h"
59 #include "bus-errors.h"
61 #include "unit-name.h"
63 #include "spawn-ask-password-agent.h"
64 #include "spawn-polkit-agent.h"
66 #include "logs-show.h"
67 #include "path-util.h"
68 #include "socket-util.h"
71 static const char *arg_type = NULL;
72 static const char *arg_load_state = NULL;
73 static char **arg_property = NULL;
74 static bool arg_all = false;
75 static const char *arg_job_mode = "replace";
76 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
77 static bool arg_no_block = false;
78 static bool arg_no_legend = false;
79 static bool arg_no_pager = false;
80 static bool arg_no_wtmp = false;
81 static bool arg_no_wall = false;
82 static bool arg_no_reload = false;
83 static bool arg_ignore_inhibitors = false;
84 static bool arg_dry = false;
85 static bool arg_quiet = false;
86 static bool arg_full = false;
87 static int arg_force = 0;
88 static bool arg_ask_password = true;
89 static bool arg_failed = false;
90 static bool arg_runtime = false;
91 static char **arg_wall = NULL;
92 static const char *arg_kill_who = NULL;
93 static int arg_signal = SIGTERM;
94 static const char *arg_root = NULL;
95 static usec_t arg_when = 0;
117 ACTION_CANCEL_SHUTDOWN,
119 } arg_action = ACTION_SYSTEMCTL;
120 static enum transport {
124 } arg_transport = TRANSPORT_NORMAL;
125 static const char *arg_host = NULL;
126 static unsigned arg_lines = 10;
127 static OutputMode arg_output = OUTPUT_SHORT;
129 static bool private_bus = false;
131 static int daemon_reload(DBusConnection *bus, char **args);
132 static void halt_now(enum action a);
134 static void pager_open_if_enabled(void) {
142 static void ask_password_agent_open_if_enabled(void) {
144 /* Open the password agent as a child process if necessary */
146 if (!arg_ask_password)
149 if (arg_scope != UNIT_FILE_SYSTEM)
152 ask_password_agent_open();
156 static void polkit_agent_open_if_enabled(void) {
158 /* Open the polkit agent as a child process if necessary */
160 if (!arg_ask_password)
163 if (arg_scope != UNIT_FILE_SYSTEM)
170 static const char *ansi_highlight(bool b) {
175 return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
178 static const char *ansi_highlight_red(bool b) {
183 return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
186 static const char *ansi_highlight_green(bool b) {
191 return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
194 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
197 if (!dbus_error_is_set(error))
200 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
201 dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
202 dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
203 dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
204 return EXIT_NOPERMISSION;
206 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
207 return EXIT_NOTINSTALLED;
209 if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
210 dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
211 return EXIT_NOTIMPLEMENTED;
213 if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
214 return EXIT_NOTCONFIGURED;
222 static void warn_wall(enum action a) {
223 static const char *table[_ACTION_MAX] = {
224 [ACTION_HALT] = "The system is going down for system halt NOW!",
225 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
226 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
227 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
228 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
229 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
230 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
237 _cleanup_free_ char *p;
239 p = strv_join(arg_wall, " ");
254 utmp_wall(table[a], NULL);
257 static bool avoid_bus(void) {
259 if (running_in_chroot() > 0)
262 if (sd_booted() <= 0)
265 if (!isempty(arg_root))
268 if (arg_scope == UNIT_FILE_GLOBAL)
274 static int compare_unit_info(const void *a, const void *b) {
276 const struct unit_info *u = a, *v = b;
278 d1 = strrchr(u->id, '.');
279 d2 = strrchr(v->id, '.');
284 r = strcasecmp(d1, d2);
289 return strcasecmp(u->id, v->id);
292 static bool output_show_unit(const struct unit_info *u) {
296 return streq(u->active_state, "failed");
298 return (!arg_type || ((dot = strrchr(u->id, '.')) &&
299 streq(dot+1, arg_type))) &&
300 (!arg_load_state || streq(u->load_state, arg_load_state)) &&
301 (arg_all || !(streq(u->active_state, "inactive")
302 || u->following[0]) || u->job_id > 0);
305 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
306 unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
307 const struct unit_info *u;
310 max_id_len = sizeof("UNIT")-1;
311 active_len = sizeof("ACTIVE")-1;
312 sub_len = sizeof("SUB")-1;
313 job_len = sizeof("JOB")-1;
316 for (u = unit_infos; u < unit_infos + c; u++) {
317 if (!output_show_unit(u))
320 max_id_len = MAX(max_id_len, strlen(u->id));
321 active_len = MAX(active_len, strlen(u->active_state));
322 sub_len = MAX(sub_len, strlen(u->sub_state));
323 if (u->job_id != 0) {
324 job_len = MAX(job_len, strlen(u->job_type));
331 id_len = MIN(max_id_len, 25u);
332 basic_len = 5 + id_len + 5 + active_len + sub_len;
334 basic_len += job_len + 1;
335 if (basic_len < (unsigned) columns()) {
336 unsigned extra_len, incr;
337 extra_len = columns() - basic_len;
338 /* Either UNIT already got 25, or is fully satisfied.
339 * Grant up to 25 to DESC now. */
340 incr = MIN(extra_len, 25u);
343 /* split the remaining space between UNIT and DESC,
344 * but do not give UNIT more than it needs. */
346 incr = MIN(extra_len / 2, max_id_len - id_len);
348 desc_len += extra_len - incr;
354 for (u = unit_infos; u < unit_infos + c; u++) {
355 char _cleanup_free_ *e = NULL;
356 const char *on_loaded, *off_loaded;
357 const char *on_active, *off_active;
359 if (!output_show_unit(u))
362 if (!n_shown && !arg_no_legend) {
363 printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
364 active_len, "ACTIVE", sub_len, "SUB");
366 printf("%-*s ", job_len, "JOB");
367 if (!arg_full && arg_no_pager)
368 printf("%.*s\n", desc_len, "DESCRIPTION");
370 printf("%s\n", "DESCRIPTION");
375 if (streq(u->load_state, "error")) {
376 on_loaded = ansi_highlight_red(true);
377 off_loaded = ansi_highlight_red(false);
379 on_loaded = off_loaded = "";
381 if (streq(u->active_state, "failed")) {
382 on_active = ansi_highlight_red(true);
383 off_active = ansi_highlight_red(false);
385 on_active = off_active = "";
387 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
389 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s",
390 id_len, e ? e : u->id,
391 on_loaded, u->load_state, off_loaded,
392 on_active, active_len, u->active_state,
393 sub_len, u->sub_state, off_active,
394 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
395 if (!arg_full && arg_no_pager)
396 printf("%.*s\n", desc_len, u->description);
398 printf("%s\n", u->description);
401 if (!arg_no_legend) {
402 const char *on, *off;
405 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
406 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
407 "SUB = The low-level unit activation state, values depend on unit type.\n");
409 printf("JOB = Pending job for the unit.\n");
411 on = ansi_highlight(true);
412 off = ansi_highlight(false);
414 on = ansi_highlight_red(true);
415 off = ansi_highlight_red(false);
419 printf("%s%u loaded units listed.%s\n"
420 "To show all installed unit files use 'systemctl list-unit-files'.\n",
423 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
424 "To show all installed unit files use 'systemctl list-unit-files'.\n",
429 static int get_unit_list(DBusConnection *bus, DBusMessage **reply,
430 struct unit_info **unit_infos, unsigned *c) {
431 DBusMessageIter iter, sub;
432 unsigned n_units = 0;
439 r = bus_method_call_with_reply(
441 "org.freedesktop.systemd1",
442 "/org/freedesktop/systemd1",
443 "org.freedesktop.systemd1.Manager",
451 if (!dbus_message_iter_init(*reply, &iter) ||
452 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
453 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
454 log_error("Failed to parse reply.");
458 dbus_message_iter_recurse(&iter, &sub);
460 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
466 n_units = MAX(2 * *c, 16u);
467 w = realloc(*unit_infos, sizeof(struct unit_info) * n_units);
474 u = *unit_infos + *c;
476 bus_parse_unit_info(&sub, u);
478 dbus_message_iter_next(&sub);
483 qsort(*unit_infos, *c, sizeof(struct unit_info), compare_unit_info);
488 static int list_units(DBusConnection *bus, char **args) {
489 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
490 _cleanup_free_ struct unit_info *unit_infos = NULL;
494 pager_open_if_enabled();
496 r = get_unit_list(bus, &reply, &unit_infos, &c);
501 output_units_list(unit_infos, c);
506 static int compare_unit_file_list(const void *a, const void *b) {
508 const UnitFileList *u = a, *v = b;
510 d1 = strrchr(u->path, '.');
511 d2 = strrchr(v->path, '.');
516 r = strcasecmp(d1, d2);
521 return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
524 static bool output_show_unit_file(const UnitFileList *u) {
527 return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
530 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
531 unsigned max_id_len, id_cols, state_cols, n_shown = 0;
532 const UnitFileList *u;
534 max_id_len = sizeof("UNIT FILE")-1;
535 state_cols = sizeof("STATE")-1;
536 for (u = units; u < units + c; u++) {
537 if (!output_show_unit_file(u))
540 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
541 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
546 id_cols = MIN(max_id_len, 25u);
547 basic_cols = 1 + id_cols + state_cols;
548 if (basic_cols < (unsigned) columns())
549 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
551 id_cols = max_id_len;
554 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
556 for (u = units; u < units + c; u++) {
557 char _cleanup_free_ *e = NULL;
558 const char *on, *off;
561 if (!output_show_unit_file(u))
566 if (u->state == UNIT_FILE_MASKED ||
567 u->state == UNIT_FILE_MASKED_RUNTIME ||
568 u->state == UNIT_FILE_DISABLED ||
569 u->state == UNIT_FILE_INVALID) {
570 on = ansi_highlight_red(true);
571 off = ansi_highlight_red(false);
572 } else if (u->state == UNIT_FILE_ENABLED) {
573 on = ansi_highlight_green(true);
574 off = ansi_highlight_green(false);
578 id = path_get_file_name(u->path);
580 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
582 printf("%-*s %s%-*s%s\n",
584 on, state_cols, unit_file_state_to_string(u->state), off);
588 printf("\n%u unit files listed.\n", n_shown);
591 static int list_unit_files(DBusConnection *bus, char **args) {
592 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
593 _cleanup_free_ UnitFileList *units = NULL;
594 DBusMessageIter iter, sub, sub2;
595 unsigned c = 0, n_units = 0;
598 pager_open_if_enabled();
605 h = hashmap_new(string_hash_func, string_compare_func);
609 r = unit_file_get_list(arg_scope, arg_root, h);
611 unit_file_list_free(h);
612 log_error("Failed to get unit file list: %s", strerror(-r));
616 n_units = hashmap_size(h);
617 units = new(UnitFileList, n_units);
619 unit_file_list_free(h);
623 HASHMAP_FOREACH(u, h, i) {
624 memcpy(units + c++, u, sizeof(UnitFileList));
630 r = bus_method_call_with_reply(
632 "org.freedesktop.systemd1",
633 "/org/freedesktop/systemd1",
634 "org.freedesktop.systemd1.Manager",
642 if (!dbus_message_iter_init(reply, &iter) ||
643 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
644 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
645 log_error("Failed to parse reply.");
649 dbus_message_iter_recurse(&iter, &sub);
651 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
655 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
660 n_units = MAX(2*c, 16u);
661 w = realloc(units, sizeof(struct UnitFileList) * n_units);
670 dbus_message_iter_recurse(&sub, &sub2);
672 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
673 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
674 log_error("Failed to parse reply.");
678 u->state = unit_file_state_from_string(state);
680 dbus_message_iter_next(&sub);
686 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
687 output_unit_file_list(units, c);
693 static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
695 _cleanup_free_ char *n = NULL;
697 size_t max_len = MAX(columns(),20u);
699 for (i = level - 1; i >= 0; i--) {
701 if(len > max_len - 3 && !arg_full) {
702 printf("%s...\n",max_len % 2 ? "" : " ");
705 printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
708 if(len > max_len - 3 && !arg_full) {
709 printf("%s...\n",max_len % 2 ? "" : " ");
712 printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
715 printf("%s\n", name);
719 n = ellipsize(name, max_len-len, 100);
727 static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
728 static const char dependencies[] =
730 "RequiresOverridable\0"
732 "RequisiteOverridable\0"
735 _cleanup_free_ char *path;
736 const char *interface = "org.freedesktop.systemd1.Unit";
738 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
739 DBusMessageIter iter, sub, sub2, sub3;
748 path = unit_dbus_path_from_name(name);
754 r = bus_method_call_with_reply(
756 "org.freedesktop.systemd1",
758 "org.freedesktop.DBus.Properties",
762 DBUS_TYPE_STRING, &interface,
767 if (!dbus_message_iter_init(reply, &iter) ||
768 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
769 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
770 log_error("Failed to parse reply.");
775 dbus_message_iter_recurse(&iter, &sub);
777 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
780 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
781 dbus_message_iter_recurse(&sub, &sub2);
783 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
784 log_error("Failed to parse reply.");
789 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
790 log_error("Failed to parse reply.");
795 dbus_message_iter_recurse(&sub2, &sub3);
796 dbus_message_iter_next(&sub);
798 if (!nulstr_contains(dependencies, prop))
801 if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
802 if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
803 DBusMessageIter sub4;
804 dbus_message_iter_recurse(&sub3, &sub4);
806 while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
809 assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
810 dbus_message_iter_get_basic(&sub4, &s);
812 r = strv_extend(&ret, s);
818 dbus_message_iter_next(&sub4);
831 static int list_dependencies_compare(const void *_a, const void *_b) {
832 const char **a = (const char**) _a, **b = (const char**) _b;
833 if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
835 if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
837 return strcasecmp(*a, *b);
840 static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char **units, unsigned int branches) {
841 char _cleanup_strv_free_ **deps = NULL, **u;
845 u = strv_append(units, name);
849 r = list_dependencies_get_dependencies(bus, name, &deps);
853 qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
855 STRV_FOREACH(c, deps) {
856 if (strv_contains(u, *c)) {
857 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
863 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
867 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
868 r = list_dependencies_one(bus, *c, level + 1, u, (branches << 1) | (c[1] == NULL ? 0 : 1));
877 static int list_dependencies(DBusConnection *bus, char **args) {
878 _cleanup_free_ char *unit = NULL;
884 unit = unit_name_mangle(args[1]);
889 u = SPECIAL_DEFAULT_TARGET;
891 pager_open_if_enabled();
895 return list_dependencies_one(bus, u, 0, NULL, 0);
898 static int list_jobs(DBusConnection *bus, char **args) {
899 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
900 DBusMessageIter iter, sub, sub2;
904 pager_open_if_enabled();
906 r = bus_method_call_with_reply(
908 "org.freedesktop.systemd1",
909 "/org/freedesktop/systemd1",
910 "org.freedesktop.systemd1.Manager",
918 if (!dbus_message_iter_init(reply, &iter) ||
919 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
920 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
921 log_error("Failed to parse reply.");
925 dbus_message_iter_recurse(&iter, &sub);
928 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
930 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
931 const char *name, *type, *state, *job_path, *unit_path;
933 char _cleanup_free_ *e = NULL;
935 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
936 log_error("Failed to parse reply.");
940 dbus_message_iter_recurse(&sub, &sub2);
942 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
943 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
944 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
945 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
946 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
947 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
948 log_error("Failed to parse reply.");
952 e = arg_full ? NULL : ellipsize(name, 25, 33);
953 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
957 dbus_message_iter_next(&sub);
961 printf("\n%u jobs listed.\n", k);
966 static int load_unit(DBusConnection *bus, char **args) {
971 STRV_FOREACH(name, args+1) {
972 _cleanup_free_ char *n = NULL;
975 n = unit_name_mangle(*name);
979 r = bus_method_call_with_reply(
981 "org.freedesktop.systemd1",
982 "/org/freedesktop/systemd1",
983 "org.freedesktop.systemd1.Manager",
987 DBUS_TYPE_STRING, &n,
996 static int cancel_job(DBusConnection *bus, char **args) {
1001 if (strv_length(args) <= 1)
1002 return daemon_reload(bus, args);
1004 STRV_FOREACH(name, args+1) {
1008 r = safe_atou32(*name, &id);
1010 log_error("Failed to parse job id: %s", strerror(-r));
1014 r = bus_method_call_with_reply(
1016 "org.freedesktop.systemd1",
1017 "/org/freedesktop/systemd1",
1018 "org.freedesktop.systemd1.Manager",
1022 DBUS_TYPE_UINT32, &id,
1031 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1032 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1033 dbus_bool_t b = FALSE;
1034 DBusMessageIter iter, sub;
1036 *interface = "org.freedesktop.systemd1.Unit",
1037 *property = "NeedDaemonReload",
1039 _cleanup_free_ char *n = NULL;
1042 /* We ignore all errors here, since this is used to show a warning only */
1044 n = unit_name_mangle(unit);
1048 r = bus_method_call_with_reply(
1050 "org.freedesktop.systemd1",
1051 "/org/freedesktop/systemd1",
1052 "org.freedesktop.systemd1.Manager",
1056 DBUS_TYPE_STRING, &n,
1061 if (!dbus_message_get_args(reply, NULL,
1062 DBUS_TYPE_OBJECT_PATH, &path,
1066 dbus_message_unref(reply);
1069 r = bus_method_call_with_reply(
1071 "org.freedesktop.systemd1",
1073 "org.freedesktop.DBus.Properties",
1077 DBUS_TYPE_STRING, &interface,
1078 DBUS_TYPE_STRING, &property,
1083 if (!dbus_message_iter_init(reply, &iter) ||
1084 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1087 dbus_message_iter_recurse(&iter, &sub);
1088 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1091 dbus_message_iter_get_basic(&sub, &b);
1095 typedef struct WaitData {
1102 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1103 DBusError _cleanup_dbus_error_free_ error;
1106 dbus_error_init(&error);
1112 log_debug("Got D-Bus request: %s.%s() on %s",
1113 dbus_message_get_interface(message),
1114 dbus_message_get_member(message),
1115 dbus_message_get_path(message));
1117 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1118 log_error("Warning! D-Bus connection terminated.");
1119 dbus_connection_close(connection);
1121 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1123 const char *path, *result, *unit;
1125 if (dbus_message_get_args(message, &error,
1126 DBUS_TYPE_UINT32, &id,
1127 DBUS_TYPE_OBJECT_PATH, &path,
1128 DBUS_TYPE_STRING, &unit,
1129 DBUS_TYPE_STRING, &result,
1130 DBUS_TYPE_INVALID)) {
1132 free(set_remove(d->set, (char*) path));
1134 if (!isempty(result))
1135 d->result = strdup(result);
1138 d->name = strdup(unit);
1140 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1143 dbus_error_free(&error);
1144 if (dbus_message_get_args(message, &error,
1145 DBUS_TYPE_UINT32, &id,
1146 DBUS_TYPE_OBJECT_PATH, &path,
1147 DBUS_TYPE_STRING, &result,
1148 DBUS_TYPE_INVALID)) {
1149 /* Compatibility with older systemd versions <
1150 * 183 during upgrades. This should be dropped
1152 free(set_remove(d->set, (char*) path));
1155 d->result = strdup(result);
1157 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1161 log_error("Failed to parse message: %s", bus_error_message(&error));
1164 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1167 static int enable_wait_for_jobs(DBusConnection *bus) {
1175 dbus_error_init(&error);
1176 dbus_bus_add_match(bus,
1178 "sender='org.freedesktop.systemd1',"
1179 "interface='org.freedesktop.systemd1.Manager',"
1180 "member='JobRemoved',"
1181 "path='/org/freedesktop/systemd1'",
1184 if (dbus_error_is_set(&error)) {
1185 log_error("Failed to add match: %s", bus_error_message(&error));
1186 dbus_error_free(&error);
1190 /* This is slightly dirty, since we don't undo the match registrations. */
1194 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1196 WaitData d = { .set = s };
1201 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1204 while (!set_isempty(s)) {
1206 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1207 log_error("Disconnected from bus.");
1208 return -ECONNREFUSED;
1215 if (streq(d.result, "timeout"))
1216 log_error("Job for %s timed out.", strna(d.name));
1217 else if (streq(d.result, "canceled"))
1218 log_error("Job for %s canceled.", strna(d.name));
1219 else if (streq(d.result, "dependency"))
1220 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1221 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1222 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1225 if (streq_ptr(d.result, "timeout"))
1227 else if (streq_ptr(d.result, "canceled"))
1229 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1240 dbus_connection_remove_filter(bus, wait_filter, &d);
1244 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1245 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1246 _cleanup_free_ char *n = NULL;
1247 DBusMessageIter iter, sub;
1249 *interface = "org.freedesktop.systemd1.Unit",
1250 *property = "ActiveState";
1251 const char *state, *path;
1257 dbus_error_init(&error);
1259 n = unit_name_mangle(name);
1263 r = bus_method_call_with_reply (
1265 "org.freedesktop.systemd1",
1266 "/org/freedesktop/systemd1",
1267 "org.freedesktop.systemd1.Manager",
1271 DBUS_TYPE_STRING, &n,
1274 dbus_error_free(&error);
1281 if (!dbus_message_get_args(reply, NULL,
1282 DBUS_TYPE_OBJECT_PATH, &path,
1283 DBUS_TYPE_INVALID)) {
1284 log_error("Failed to parse reply.");
1288 dbus_message_unref(reply);
1291 r = bus_method_call_with_reply(
1293 "org.freedesktop.systemd1",
1295 "org.freedesktop.DBus.Properties",
1299 DBUS_TYPE_STRING, &interface,
1300 DBUS_TYPE_STRING, &property,
1308 if (!dbus_message_iter_init(reply, &iter) ||
1309 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1310 log_error("Failed to parse reply.");
1314 dbus_message_iter_recurse(&iter, &sub);
1316 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1317 log_error("Failed to parse reply.");
1321 dbus_message_iter_get_basic(&sub, &state);
1326 return strv_find(check_states, state) ? 1 : 0;
1329 static void check_triggering_units(
1330 DBusConnection *bus,
1331 const char *unit_name) {
1333 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1334 DBusMessageIter iter, sub;
1335 const char *interface = "org.freedesktop.systemd1.Unit",
1336 *load_state_property = "LoadState",
1337 *triggered_by_property = "TriggeredBy",
1339 char _cleanup_free_ *unit_path = NULL, *n = NULL;
1340 bool print_warning_label = true;
1343 n = unit_name_mangle(unit_name);
1349 unit_path = unit_dbus_path_from_name(n);
1355 r = bus_method_call_with_reply(
1357 "org.freedesktop.systemd1",
1359 "org.freedesktop.DBus.Properties",
1363 DBUS_TYPE_STRING, &interface,
1364 DBUS_TYPE_STRING, &load_state_property,
1369 if (!dbus_message_iter_init(reply, &iter) ||
1370 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1371 log_error("Failed to parse reply.");
1375 dbus_message_iter_recurse(&iter, &sub);
1377 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1378 log_error("Failed to parse reply.");
1382 dbus_message_iter_get_basic(&sub, &state);
1384 if (streq(state, "masked"))
1387 dbus_message_unref(reply);
1390 r = bus_method_call_with_reply(
1392 "org.freedesktop.systemd1",
1394 "org.freedesktop.DBus.Properties",
1398 DBUS_TYPE_STRING, &interface,
1399 DBUS_TYPE_STRING, &triggered_by_property,
1404 if (!dbus_message_iter_init(reply, &iter) ||
1405 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1406 log_error("Failed to parse reply.");
1410 dbus_message_iter_recurse(&iter, &sub);
1411 dbus_message_iter_recurse(&sub, &iter);
1414 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1415 const char * const check_states[] = {
1420 const char *service_trigger;
1422 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1423 log_error("Failed to parse reply.");
1427 dbus_message_iter_get_basic(&sub, &service_trigger);
1429 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1433 if (print_warning_label) {
1434 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1435 print_warning_label = false;
1438 log_warning(" %s", service_trigger);
1441 dbus_message_iter_next(&sub);
1445 static int start_unit_one(
1446 DBusConnection *bus,
1453 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1454 _cleanup_free_ char *n;
1463 n = unit_name_mangle(name);
1467 r = bus_method_call_with_reply(
1469 "org.freedesktop.systemd1",
1470 "/org/freedesktop/systemd1",
1471 "org.freedesktop.systemd1.Manager",
1475 DBUS_TYPE_STRING, &n,
1476 DBUS_TYPE_STRING, &mode,
1479 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1480 /* There's always a fallback possible for
1481 * legacy actions. */
1484 log_error("Failed to issue method call: %s", bus_error_message(error));
1489 if (!dbus_message_get_args(reply, error,
1490 DBUS_TYPE_OBJECT_PATH, &path,
1491 DBUS_TYPE_INVALID)) {
1492 log_error("Failed to parse reply: %s", bus_error_message(error));
1496 if (need_daemon_reload(bus, n))
1497 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1498 n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1510 log_error("Failed to add path to set.");
1518 static const struct {
1522 } action_table[_ACTION_MAX] = {
1523 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
1524 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
1525 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
1526 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
1527 [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
1528 [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
1529 [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
1530 [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
1531 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
1532 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
1533 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
1534 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
1535 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
1536 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
1537 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1540 static enum action verb_to_action(const char *verb) {
1543 for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1544 if (action_table[i].verb && streq(verb, action_table[i].verb))
1546 return ACTION_INVALID;
1549 static int start_unit(DBusConnection *bus, char **args) {
1552 const char *method, *mode, *one_name;
1553 Set _cleanup_set_free_free_ *s = NULL;
1554 DBusError _cleanup_dbus_error_free_ error;
1557 dbus_error_init(&error);
1561 ask_password_agent_open_if_enabled();
1563 if (arg_action == ACTION_SYSTEMCTL) {
1566 streq(args[0], "stop") ||
1567 streq(args[0], "condstop") ? "StopUnit" :
1568 streq(args[0], "reload") ? "ReloadUnit" :
1569 streq(args[0], "restart") ? "RestartUnit" :
1571 streq(args[0], "try-restart") ||
1572 streq(args[0], "condrestart") ? "TryRestartUnit" :
1574 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1576 streq(args[0], "reload-or-try-restart") ||
1577 streq(args[0], "condreload") ||
1579 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1581 action = verb_to_action(args[0]);
1583 mode = streq(args[0], "isolate") ? "isolate" :
1584 action_table[action].mode ?: arg_job_mode;
1586 one_name = action_table[action].target;
1589 assert(arg_action < ELEMENTSOF(action_table));
1590 assert(action_table[arg_action].target);
1592 method = "StartUnit";
1594 mode = action_table[arg_action].mode;
1595 one_name = action_table[arg_action].target;
1598 if (!arg_no_block) {
1599 ret = enable_wait_for_jobs(bus);
1601 log_error("Could not watch jobs: %s", strerror(-ret));
1605 s = set_new(string_hash_func, string_compare_func);
1611 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1613 ret = translate_bus_error_to_exit_status(ret, &error);
1615 STRV_FOREACH(name, args+1) {
1616 r = start_unit_one(bus, method, *name, mode, &error, s);
1618 ret = translate_bus_error_to_exit_status(r, &error);
1619 dbus_error_free(&error);
1624 if (!arg_no_block) {
1625 r = wait_for_jobs(bus, s);
1629 /* When stopping units, warn if they can still be triggered by
1630 * another active unit (socket, path, timer) */
1631 if (!arg_quiet && streq(method, "StopUnit")) {
1633 check_triggering_units(bus, one_name);
1635 STRV_FOREACH(name, args+1)
1636 check_triggering_units(bus, *name);
1643 /* Ask systemd-logind, which might grant access to unprivileged users
1644 * through PolicyKit */
1645 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1648 dbus_bool_t interactive = true;
1653 polkit_agent_open_if_enabled();
1661 case ACTION_POWEROFF:
1662 method = "PowerOff";
1665 case ACTION_SUSPEND:
1669 case ACTION_HIBERNATE:
1670 method = "Hibernate";
1673 case ACTION_HYBRID_SLEEP:
1674 method = "HybridSleep";
1681 return bus_method_call_with_reply(
1683 "org.freedesktop.login1",
1684 "/org/freedesktop/login1",
1685 "org.freedesktop.login1.Manager",
1689 DBUS_TYPE_BOOLEAN, &interactive,
1696 static int check_inhibitors(DBusConnection *bus, enum action a) {
1698 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1699 DBusMessageIter iter, sub, sub2;
1702 _cleanup_strv_free_ char **sessions = NULL;
1708 if (arg_ignore_inhibitors || arg_force > 0)
1720 r = bus_method_call_with_reply(
1722 "org.freedesktop.login1",
1723 "/org/freedesktop/login1",
1724 "org.freedesktop.login1.Manager",
1730 /* If logind is not around, then there are no inhibitors... */
1733 if (!dbus_message_iter_init(reply, &iter) ||
1734 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1735 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1736 log_error("Failed to parse reply.");
1740 dbus_message_iter_recurse(&iter, &sub);
1741 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1742 const char *what, *who, *why, *mode;
1744 _cleanup_strv_free_ char **sv = NULL;
1745 _cleanup_free_ char *comm = NULL, *user = NULL;
1747 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1748 log_error("Failed to parse reply.");
1752 dbus_message_iter_recurse(&sub, &sub2);
1754 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1755 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1756 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1757 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1758 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1759 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1760 log_error("Failed to parse reply.");
1764 if (!streq(mode, "block"))
1767 sv = strv_split(what, ":");
1771 if (!strv_contains(sv,
1773 a == ACTION_POWEROFF ||
1774 a == ACTION_REBOOT ||
1775 a == ACTION_KEXEC ? "shutdown" : "sleep"))
1778 get_process_comm(pid, &comm);
1779 user = uid_to_name(uid);
1780 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
1781 who, (unsigned long) pid, strna(comm), strna(user), why);
1785 dbus_message_iter_next(&sub);
1788 dbus_message_iter_recurse(&iter, &sub);
1790 /* Check for current sessions */
1791 sd_get_sessions(&sessions);
1792 STRV_FOREACH(s, sessions) {
1794 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1796 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1799 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1802 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1805 sd_session_get_tty(*s, &tty);
1806 sd_session_get_seat(*s, &seat);
1807 sd_session_get_service(*s, &service);
1808 user = uid_to_name(uid);
1810 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1817 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
1818 action_table[a].verb);
1826 static int start_special(DBusConnection *bus, char **args) {
1832 a = verb_to_action(args[0]);
1834 r = check_inhibitors(bus, a);
1838 if (arg_force >= 2 && geteuid() != 0) {
1839 log_error("Must be root.");
1843 if (arg_force >= 2 &&
1844 (a == ACTION_HALT ||
1845 a == ACTION_POWEROFF ||
1846 a == ACTION_REBOOT))
1849 if (arg_force >= 1 &&
1850 (a == ACTION_HALT ||
1851 a == ACTION_POWEROFF ||
1852 a == ACTION_REBOOT ||
1853 a == ACTION_KEXEC ||
1855 return daemon_reload(bus, args);
1857 /* first try logind, to allow authentication with polkit */
1858 if (geteuid() != 0 &&
1859 (a == ACTION_POWEROFF ||
1860 a == ACTION_REBOOT ||
1861 a == ACTION_SUSPEND ||
1862 a == ACTION_HIBERNATE ||
1863 a == ACTION_HYBRID_SLEEP)) {
1864 r = reboot_with_logind(bus, a);
1869 r = start_unit(bus, args);
1870 if (r == EXIT_SUCCESS)
1876 static int check_unit_active(DBusConnection *bus, char **args) {
1877 const char * const check_states[] = {
1884 int r = 3; /* According to LSB: "program is not running" */
1889 STRV_FOREACH(name, args+1) {
1892 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1902 static int check_unit_failed(DBusConnection *bus, char **args) {
1903 const char * const check_states[] = {
1914 STRV_FOREACH(name, args+1) {
1917 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1927 static int kill_unit(DBusConnection *bus, char **args) {
1935 arg_kill_who = "all";
1937 STRV_FOREACH(name, args+1) {
1938 _cleanup_free_ char *n = NULL;
1940 n = unit_name_mangle(*name);
1944 r = bus_method_call_with_reply(
1946 "org.freedesktop.systemd1",
1947 "/org/freedesktop/systemd1",
1948 "org.freedesktop.systemd1.Manager",
1952 DBUS_TYPE_STRING, &n,
1953 DBUS_TYPE_STRING, &arg_kill_who,
1954 DBUS_TYPE_INT32, &arg_signal,
1962 static int set_cgroup(DBusConnection *bus, char **args) {
1963 _cleanup_free_ char *n = NULL;
1964 const char *method, *runtime;
1972 streq(args[0], "set-cgroup") ? "SetUnitControlGroup" :
1973 streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
1974 : "UnsetUnitControlGroupAttribute";
1976 runtime = arg_runtime ? "runtime" : "persistent";
1978 n = unit_name_mangle(args[1]);
1982 STRV_FOREACH(argument, args + 2) {
1984 r = bus_method_call_with_reply(
1986 "org.freedesktop.systemd1",
1987 "/org/freedesktop/systemd1",
1988 "org.freedesktop.systemd1.Manager",
1992 DBUS_TYPE_STRING, &n,
1993 DBUS_TYPE_STRING, argument,
1994 DBUS_TYPE_STRING, &runtime,
2003 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2004 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2006 DBusMessageIter iter;
2007 _cleanup_free_ char *n = NULL;
2008 const char *runtime;
2014 dbus_error_init(&error);
2016 runtime = arg_runtime ? "runtime" : "persistent";
2018 n = unit_name_mangle(args[1]);
2022 m = dbus_message_new_method_call(
2023 "org.freedesktop.systemd1",
2024 "/org/freedesktop/systemd1",
2025 "org.freedesktop.systemd1.Manager",
2026 "SetUnitControlGroupAttribute");
2030 dbus_message_iter_init_append(m, &iter);
2031 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2032 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
2035 r = bus_append_strv_iter(&iter, args + 3);
2039 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2042 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2044 log_error("Failed to issue method call: %s", bus_error_message(&error));
2045 dbus_error_free(&error);
2052 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2053 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2054 _cleanup_free_ char *n = NULL;
2061 n = unit_name_mangle(args[1]);
2065 STRV_FOREACH(argument, args + 2) {
2066 _cleanup_strv_free_ char **list = NULL;
2067 DBusMessageIter iter;
2070 r = bus_method_call_with_reply(
2072 "org.freedesktop.systemd1",
2073 "/org/freedesktop/systemd1",
2074 "org.freedesktop.systemd1.Manager",
2075 "GetUnitControlGroupAttribute",
2078 DBUS_TYPE_STRING, &n,
2079 DBUS_TYPE_STRING, argument,
2084 if (!dbus_message_iter_init(reply, &iter)) {
2085 log_error("Failed to initialize iterator.");
2089 r = bus_parse_strv_iter(&iter, &list);
2091 log_error("Failed to parse value list.");
2095 STRV_FOREACH(a, list) {
2096 if (endswith(*a, "\n"))
2106 typedef struct ExecStatusInfo {
2114 usec_t start_timestamp;
2115 usec_t exit_timestamp;
2120 LIST_FIELDS(struct ExecStatusInfo, exec);
2123 static void exec_status_info_free(ExecStatusInfo *i) {
2132 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2133 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2134 DBusMessageIter sub2, sub3;
2138 int32_t code, status;
2144 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2147 dbus_message_iter_recurse(sub, &sub2);
2149 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2152 i->path = strdup(path);
2156 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2157 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2161 dbus_message_iter_recurse(&sub2, &sub3);
2162 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2163 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2164 dbus_message_iter_next(&sub3);
2168 i->argv = new0(char*, n+1);
2173 dbus_message_iter_recurse(&sub2, &sub3);
2174 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2177 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2178 dbus_message_iter_get_basic(&sub3, &s);
2179 dbus_message_iter_next(&sub3);
2181 i->argv[n] = strdup(s);
2188 if (!dbus_message_iter_next(&sub2) ||
2189 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2190 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2191 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2192 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2193 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2194 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2195 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2196 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2200 i->start_timestamp = (usec_t) start_timestamp;
2201 i->exit_timestamp = (usec_t) exit_timestamp;
2202 i->pid = (pid_t) pid;
2209 typedef struct UnitStatusInfo {
2211 const char *load_state;
2212 const char *active_state;
2213 const char *sub_state;
2214 const char *unit_file_state;
2216 const char *description;
2217 const char *following;
2219 char **documentation;
2221 const char *fragment_path;
2222 const char *source_path;
2223 const char *default_control_group;
2225 char **dropin_paths;
2227 const char *load_error;
2230 usec_t inactive_exit_timestamp;
2231 usec_t inactive_exit_timestamp_monotonic;
2232 usec_t active_enter_timestamp;
2233 usec_t active_exit_timestamp;
2234 usec_t inactive_enter_timestamp;
2236 bool need_daemon_reload;
2241 const char *status_text;
2244 usec_t start_timestamp;
2245 usec_t exit_timestamp;
2247 int exit_code, exit_status;
2249 usec_t condition_timestamp;
2250 bool condition_result;
2253 unsigned n_accepted;
2254 unsigned n_connections;
2257 /* Pairs of type, path */
2261 const char *sysfs_path;
2263 /* Mount, Automount */
2269 LIST_HEAD(ExecStatusInfo, exec);
2272 static void print_status_info(UnitStatusInfo *i) {
2274 const char *on, *off, *ss;
2276 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2277 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2280 arg_all * OUTPUT_SHOW_ALL |
2281 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2282 on_tty() * OUTPUT_COLOR |
2283 !arg_quiet * OUTPUT_WARN_CUTOFF |
2284 arg_full * OUTPUT_FULL_WIDTH;
2285 int maxlen = 8; /* a value that'll suffice most of the time */
2290 STRV_FOREACH_PAIR(t, t2, i->listen)
2291 maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
2293 maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
2294 if (i->main_pid > 0)
2295 maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
2296 else if (i->control_pid > 0)
2297 maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
2299 /* This shows pretty information about a unit. See
2300 * print_property() for a low-level property printer */
2302 printf("%s", strna(i->id));
2304 if (i->description && !streq_ptr(i->id, i->description))
2305 printf(" - %s", i->description);
2310 printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
2312 if (streq_ptr(i->load_state, "error")) {
2313 on = ansi_highlight_red(true);
2314 off = ansi_highlight_red(false);
2318 path = i->source_path ? i->source_path : i->fragment_path;
2321 printf(" %*s: %s%s%s (Reason: %s)\n",
2322 maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
2323 else if (path && i->unit_file_state)
2324 printf(" %*s: %s%s%s (%s; %s)\n",
2325 maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
2327 printf(" %*s: %s%s%s (%s)\n",
2328 maxlen, "Loaded", on, strna(i->load_state), off, path);
2330 printf(" %*s: %s%s%s\n",
2331 maxlen, "Loaded", on, strna(i->load_state), off);
2333 if (!strv_isempty(i->dropin_paths)) {
2338 STRV_FOREACH(dropin, i->dropin_paths) {
2339 if (! dir || last) {
2340 printf(" %*s ", maxlen, dir ? "" : "Drop-In:");
2344 if (path_get_parent(*dropin, &dir) < 0) {
2349 printf("%s\n %*s %s", dir, maxlen, "",
2350 draw_special_char(DRAW_TREE_RIGHT));
2353 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2355 printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2361 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2363 if (streq_ptr(i->active_state, "failed")) {
2364 on = ansi_highlight_red(true);
2365 off = ansi_highlight_red(false);
2366 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2367 on = ansi_highlight_green(true);
2368 off = ansi_highlight_green(false);
2373 printf(" %*s: %s%s (%s)%s",
2374 maxlen, "Active", on, strna(i->active_state), ss, off);
2376 printf(" %*s: %s%s%s",
2377 maxlen, "Active", on, strna(i->active_state), off);
2379 if (!isempty(i->result) && !streq(i->result, "success"))
2380 printf(" (Result: %s)", i->result);
2382 timestamp = (streq_ptr(i->active_state, "active") ||
2383 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2384 (streq_ptr(i->active_state, "inactive") ||
2385 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2386 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2387 i->active_exit_timestamp;
2389 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2390 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2393 printf(" since %s; %s\n", s2, s1);
2395 printf(" since %s\n", s2);
2399 if (!i->condition_result && i->condition_timestamp > 0) {
2400 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2401 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2404 printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
2406 printf(" %*s start condition failed at %s\n", maxlen, "", s2);
2410 printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
2412 printf(" %*s: %s\n", maxlen, "Where", i->where);
2414 printf(" %*s: %s\n", maxlen, "What", i->what);
2416 STRV_FOREACH(t, i->documentation)
2417 printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
2419 STRV_FOREACH_PAIR(t, t2, i->listen)
2420 printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
2423 printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
2425 LIST_FOREACH(exec, p, i->exec) {
2426 _cleanup_free_ char *argv = NULL;
2429 /* Only show exited processes here */
2433 argv = strv_join(p->argv, " ");
2434 printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
2436 good = is_clean_exit_lsb(p->code, p->status, NULL);
2438 on = ansi_highlight_red(true);
2439 off = ansi_highlight_red(false);
2443 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2445 if (p->code == CLD_EXITED) {
2448 printf("status=%i", p->status);
2450 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2455 printf("signal=%s", signal_to_string(p->status));
2457 printf(")%s\n", off);
2459 if (i->main_pid == p->pid &&
2460 i->start_timestamp == p->start_timestamp &&
2461 i->exit_timestamp == p->start_timestamp)
2462 /* Let's not show this twice */
2465 if (p->pid == i->control_pid)
2469 if (i->main_pid > 0 || i->control_pid > 0) {
2470 if (i->main_pid > 0) {
2471 printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
2474 _cleanup_free_ char *comm = NULL;
2475 get_process_comm(i->main_pid, &comm);
2477 printf(" (%s)", comm);
2478 } else if (i->exit_code > 0) {
2479 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2481 if (i->exit_code == CLD_EXITED) {
2484 printf("status=%i", i->exit_status);
2486 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2491 printf("signal=%s", signal_to_string(i->exit_status));
2495 if (i->control_pid > 0)
2499 if (i->control_pid > 0) {
2500 _cleanup_free_ char *c = NULL;
2502 printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
2504 get_process_comm(i->control_pid, &c);
2513 printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
2515 if (i->default_control_group &&
2516 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2519 printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
2521 if (arg_transport != TRANSPORT_SSH) {
2524 char prefix[maxlen + 4];
2525 memset(prefix, ' ', sizeof(prefix) - 1);
2526 prefix[sizeof(prefix) - 1] = '\0';
2529 if (c > sizeof(prefix) - 1)
2530 c -= sizeof(prefix) - 1;
2534 if (i->main_pid > 0)
2535 extra[k++] = i->main_pid;
2537 if (i->control_pid > 0)
2538 extra[k++] = i->control_pid;
2540 show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
2541 c, false, extra, k, flags);
2545 if (i->id && arg_transport != TRANSPORT_SSH) {
2547 show_journal_by_unit(stdout,
2551 i->inactive_exit_timestamp_monotonic,
2555 arg_scope == UNIT_FILE_SYSTEM);
2558 if (i->need_daemon_reload)
2559 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2560 ansi_highlight_red(true),
2561 ansi_highlight_red(false),
2562 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2565 static void show_unit_help(UnitStatusInfo *i) {
2570 if (!i->documentation) {
2571 log_info("Documentation for %s not known.", i->id);
2575 STRV_FOREACH(p, i->documentation) {
2577 if (startswith(*p, "man:")) {
2580 char _cleanup_free_ *page = NULL, *section = NULL;
2581 const char *args[4] = { "man", NULL, NULL, NULL };
2586 if ((*p)[k-1] == ')')
2587 e = strrchr(*p, '(');
2590 page = strndup((*p) + 4, e - *p - 4);
2591 section = strndup(e + 1, *p + k - e - 2);
2592 if (!page || !section) {
2604 log_error("Failed to fork: %m");
2610 execvp(args[0], (char**) args);
2611 log_error("Failed to execute man: %m");
2612 _exit(EXIT_FAILURE);
2615 wait_for_terminate(pid, NULL);
2617 log_info("Can't show: %s", *p);
2621 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2627 switch (dbus_message_iter_get_arg_type(iter)) {
2629 case DBUS_TYPE_STRING: {
2632 dbus_message_iter_get_basic(iter, &s);
2635 if (streq(name, "Id"))
2637 else if (streq(name, "LoadState"))
2639 else if (streq(name, "ActiveState"))
2640 i->active_state = s;
2641 else if (streq(name, "SubState"))
2643 else if (streq(name, "Description"))
2645 else if (streq(name, "FragmentPath"))
2646 i->fragment_path = s;
2647 else if (streq(name, "SourcePath"))
2649 else if (streq(name, "DefaultControlGroup"))
2650 i->default_control_group = s;
2651 else if (streq(name, "StatusText"))
2653 else if (streq(name, "SysFSPath"))
2655 else if (streq(name, "Where"))
2657 else if (streq(name, "What"))
2659 else if (streq(name, "Following"))
2661 else if (streq(name, "UnitFileState"))
2662 i->unit_file_state = s;
2663 else if (streq(name, "Result"))
2670 case DBUS_TYPE_BOOLEAN: {
2673 dbus_message_iter_get_basic(iter, &b);
2675 if (streq(name, "Accept"))
2677 else if (streq(name, "NeedDaemonReload"))
2678 i->need_daemon_reload = b;
2679 else if (streq(name, "ConditionResult"))
2680 i->condition_result = b;
2685 case DBUS_TYPE_UINT32: {
2688 dbus_message_iter_get_basic(iter, &u);
2690 if (streq(name, "MainPID")) {
2692 i->main_pid = (pid_t) u;
2695 } else if (streq(name, "ControlPID"))
2696 i->control_pid = (pid_t) u;
2697 else if (streq(name, "ExecMainPID")) {
2699 i->main_pid = (pid_t) u;
2700 } else if (streq(name, "NAccepted"))
2702 else if (streq(name, "NConnections"))
2703 i->n_connections = u;
2708 case DBUS_TYPE_INT32: {
2711 dbus_message_iter_get_basic(iter, &j);
2713 if (streq(name, "ExecMainCode"))
2714 i->exit_code = (int) j;
2715 else if (streq(name, "ExecMainStatus"))
2716 i->exit_status = (int) j;
2721 case DBUS_TYPE_UINT64: {
2724 dbus_message_iter_get_basic(iter, &u);
2726 if (streq(name, "ExecMainStartTimestamp"))
2727 i->start_timestamp = (usec_t) u;
2728 else if (streq(name, "ExecMainExitTimestamp"))
2729 i->exit_timestamp = (usec_t) u;
2730 else if (streq(name, "ActiveEnterTimestamp"))
2731 i->active_enter_timestamp = (usec_t) u;
2732 else if (streq(name, "InactiveEnterTimestamp"))
2733 i->inactive_enter_timestamp = (usec_t) u;
2734 else if (streq(name, "InactiveExitTimestamp"))
2735 i->inactive_exit_timestamp = (usec_t) u;
2736 else if (streq(name, "InactiveExitTimestampMonotonic"))
2737 i->inactive_exit_timestamp_monotonic = (usec_t) u;
2738 else if (streq(name, "ActiveExitTimestamp"))
2739 i->active_exit_timestamp = (usec_t) u;
2740 else if (streq(name, "ConditionTimestamp"))
2741 i->condition_timestamp = (usec_t) u;
2746 case DBUS_TYPE_ARRAY: {
2748 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2749 startswith(name, "Exec")) {
2750 DBusMessageIter sub;
2752 dbus_message_iter_recurse(iter, &sub);
2753 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2754 ExecStatusInfo *info;
2757 if (!(info = new0(ExecStatusInfo, 1)))
2760 if (!(info->name = strdup(name))) {
2765 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2770 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2772 dbus_message_iter_next(&sub);
2775 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2776 DBusMessageIter sub, sub2;
2778 dbus_message_iter_recurse(iter, &sub);
2779 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2780 const char *type, *path;
2782 dbus_message_iter_recurse(&sub, &sub2);
2784 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2785 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
2788 r = strv_extend(&i->listen, type);
2791 r = strv_extend(&i->listen, path);
2796 dbus_message_iter_next(&sub);
2801 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
2802 int r = bus_parse_strv_iter(iter, &i->dropin_paths);
2806 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2807 streq(name, "Documentation")) {
2809 DBusMessageIter sub;
2811 dbus_message_iter_recurse(iter, &sub);
2812 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2816 dbus_message_iter_get_basic(&sub, &s);
2818 r = strv_extend(&i->documentation, s);
2822 dbus_message_iter_next(&sub);
2829 case DBUS_TYPE_STRUCT: {
2831 if (streq(name, "LoadError")) {
2832 DBusMessageIter sub;
2833 const char *n, *message;
2836 dbus_message_iter_recurse(iter, &sub);
2838 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2842 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2846 if (!isempty(message))
2847 i->load_error = message;
2857 static int print_property(const char *name, DBusMessageIter *iter) {
2861 /* This is a low-level property printer, see
2862 * print_status_info() for the nicer output */
2864 if (arg_property && !strv_find(arg_property, name))
2867 switch (dbus_message_iter_get_arg_type(iter)) {
2869 case DBUS_TYPE_STRUCT: {
2870 DBusMessageIter sub;
2871 dbus_message_iter_recurse(iter, &sub);
2873 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2876 dbus_message_iter_get_basic(&sub, &u);
2879 printf("%s=%u\n", name, (unsigned) u);
2881 printf("%s=\n", name);
2884 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2887 dbus_message_iter_get_basic(&sub, &s);
2889 if (arg_all || s[0])
2890 printf("%s=%s\n", name, s);
2893 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2894 const char *a = NULL, *b = NULL;
2896 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2897 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2899 if (arg_all || !isempty(a) || !isempty(b))
2900 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2908 case DBUS_TYPE_ARRAY:
2910 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2911 DBusMessageIter sub, sub2;
2913 dbus_message_iter_recurse(iter, &sub);
2914 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2918 dbus_message_iter_recurse(&sub, &sub2);
2920 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2921 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2922 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2924 dbus_message_iter_next(&sub);
2929 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2930 DBusMessageIter sub, sub2;
2932 dbus_message_iter_recurse(iter, &sub);
2934 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2935 const char *type, *path;
2937 dbus_message_iter_recurse(&sub, &sub2);
2939 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2940 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2941 printf("%s=%s\n", type, path);
2943 dbus_message_iter_next(&sub);
2948 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2949 DBusMessageIter sub, sub2;
2951 dbus_message_iter_recurse(iter, &sub);
2952 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2953 const char *type, *path;
2955 dbus_message_iter_recurse(&sub, &sub2);
2957 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2958 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2959 printf("Listen%s=%s\n", type, path);
2961 dbus_message_iter_next(&sub);
2966 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2967 DBusMessageIter sub, sub2;
2969 dbus_message_iter_recurse(iter, &sub);
2970 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2972 uint64_t value, next_elapse;
2974 dbus_message_iter_recurse(&sub, &sub2);
2976 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2977 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2978 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2979 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2981 printf("%s={ value=%s ; next_elapse=%s }\n",
2983 format_timespan(timespan1, sizeof(timespan1), value, 0),
2984 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
2987 dbus_message_iter_next(&sub);
2992 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2993 DBusMessageIter sub, sub2;
2995 dbus_message_iter_recurse(iter, &sub);
2996 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2997 const char *controller, *attr, *value;
2999 dbus_message_iter_recurse(&sub, &sub2);
3001 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
3002 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
3003 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
3005 printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
3011 dbus_message_iter_next(&sub);
3016 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3017 DBusMessageIter sub;
3019 dbus_message_iter_recurse(iter, &sub);
3020 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3021 ExecStatusInfo info = {};
3023 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3024 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3025 char _cleanup_free_ *t;
3027 t = strv_join(info.argv, " ");
3029 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3033 yes_no(info.ignore),
3034 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3035 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3036 (unsigned) info. pid,
3037 sigchld_code_to_string(info.code),
3039 info.code == CLD_EXITED ? "" : "/",
3040 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3044 strv_free(info.argv);
3046 dbus_message_iter_next(&sub);
3055 if (generic_print_property(name, iter, arg_all) > 0)
3059 printf("%s=[unprintable]\n", name);
3064 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3065 DBusMessage _cleanup_free_ *reply = NULL;
3066 const char *interface = "";
3068 DBusMessageIter iter, sub, sub2, sub3;
3069 UnitStatusInfo info = {};