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) {
1204 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1207 while (!set_isempty(s)) {
1209 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1210 log_error("Disconnected from bus.");
1211 return -ECONNREFUSED;
1218 if (streq(d.result, "timeout"))
1219 log_error("Job for %s timed out.", strna(d.name));
1220 else if (streq(d.result, "canceled"))
1221 log_error("Job for %s canceled.", strna(d.name));
1222 else if (streq(d.result, "dependency"))
1223 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1224 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1225 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1228 if (streq_ptr(d.result, "timeout"))
1230 else if (streq_ptr(d.result, "canceled"))
1232 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1243 dbus_connection_remove_filter(bus, wait_filter, &d);
1247 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1248 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1249 _cleanup_free_ char *n = NULL;
1250 DBusMessageIter iter, sub;
1252 *interface = "org.freedesktop.systemd1.Unit",
1253 *property = "ActiveState";
1254 const char *state, *path;
1260 dbus_error_init(&error);
1262 n = unit_name_mangle(name);
1266 r = bus_method_call_with_reply (
1268 "org.freedesktop.systemd1",
1269 "/org/freedesktop/systemd1",
1270 "org.freedesktop.systemd1.Manager",
1274 DBUS_TYPE_STRING, &n,
1277 dbus_error_free(&error);
1284 if (!dbus_message_get_args(reply, NULL,
1285 DBUS_TYPE_OBJECT_PATH, &path,
1286 DBUS_TYPE_INVALID)) {
1287 log_error("Failed to parse reply.");
1291 dbus_message_unref(reply);
1294 r = bus_method_call_with_reply(
1296 "org.freedesktop.systemd1",
1298 "org.freedesktop.DBus.Properties",
1302 DBUS_TYPE_STRING, &interface,
1303 DBUS_TYPE_STRING, &property,
1311 if (!dbus_message_iter_init(reply, &iter) ||
1312 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1313 log_error("Failed to parse reply.");
1317 dbus_message_iter_recurse(&iter, &sub);
1319 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1320 log_error("Failed to parse reply.");
1324 dbus_message_iter_get_basic(&sub, &state);
1329 return strv_find(check_states, state) ? 1 : 0;
1332 static void check_triggering_units(
1333 DBusConnection *bus,
1334 const char *unit_name) {
1336 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1337 DBusMessageIter iter, sub;
1338 const char *interface = "org.freedesktop.systemd1.Unit",
1339 *load_state_property = "LoadState",
1340 *triggered_by_property = "TriggeredBy",
1342 char _cleanup_free_ *unit_path = NULL, *n = NULL;
1343 bool print_warning_label = true;
1346 n = unit_name_mangle(unit_name);
1352 unit_path = unit_dbus_path_from_name(n);
1358 r = bus_method_call_with_reply(
1360 "org.freedesktop.systemd1",
1362 "org.freedesktop.DBus.Properties",
1366 DBUS_TYPE_STRING, &interface,
1367 DBUS_TYPE_STRING, &load_state_property,
1372 if (!dbus_message_iter_init(reply, &iter) ||
1373 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1374 log_error("Failed to parse reply.");
1378 dbus_message_iter_recurse(&iter, &sub);
1380 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1381 log_error("Failed to parse reply.");
1385 dbus_message_iter_get_basic(&sub, &state);
1387 if (streq(state, "masked"))
1390 dbus_message_unref(reply);
1393 r = bus_method_call_with_reply(
1395 "org.freedesktop.systemd1",
1397 "org.freedesktop.DBus.Properties",
1401 DBUS_TYPE_STRING, &interface,
1402 DBUS_TYPE_STRING, &triggered_by_property,
1407 if (!dbus_message_iter_init(reply, &iter) ||
1408 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1409 log_error("Failed to parse reply.");
1413 dbus_message_iter_recurse(&iter, &sub);
1414 dbus_message_iter_recurse(&sub, &iter);
1417 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1418 const char * const check_states[] = {
1423 const char *service_trigger;
1425 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1426 log_error("Failed to parse reply.");
1430 dbus_message_iter_get_basic(&sub, &service_trigger);
1432 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1436 if (print_warning_label) {
1437 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1438 print_warning_label = false;
1441 log_warning(" %s", service_trigger);
1444 dbus_message_iter_next(&sub);
1448 static int start_unit_one(
1449 DBusConnection *bus,
1456 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1457 _cleanup_free_ char *n;
1466 n = unit_name_mangle(name);
1470 r = bus_method_call_with_reply(
1472 "org.freedesktop.systemd1",
1473 "/org/freedesktop/systemd1",
1474 "org.freedesktop.systemd1.Manager",
1478 DBUS_TYPE_STRING, &n,
1479 DBUS_TYPE_STRING, &mode,
1482 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1483 /* There's always a fallback possible for
1484 * legacy actions. */
1487 log_error("Failed to issue method call: %s", bus_error_message(error));
1492 if (!dbus_message_get_args(reply, error,
1493 DBUS_TYPE_OBJECT_PATH, &path,
1494 DBUS_TYPE_INVALID)) {
1495 log_error("Failed to parse reply: %s", bus_error_message(error));
1499 if (need_daemon_reload(bus, n))
1500 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1501 n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1513 log_error("Failed to add path to set.");
1521 static const struct {
1525 } action_table[_ACTION_MAX] = {
1526 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
1527 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
1528 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
1529 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
1530 [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
1531 [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
1532 [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
1533 [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
1534 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
1535 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
1536 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
1537 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
1538 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
1539 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
1540 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1543 static enum action verb_to_action(const char *verb) {
1546 for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1547 if (action_table[i].verb && streq(verb, action_table[i].verb))
1549 return ACTION_INVALID;
1552 static int start_unit(DBusConnection *bus, char **args) {
1555 const char *method, *mode, *one_name;
1556 Set _cleanup_set_free_free_ *s = NULL;
1557 DBusError _cleanup_dbus_error_free_ error;
1560 dbus_error_init(&error);
1564 ask_password_agent_open_if_enabled();
1566 if (arg_action == ACTION_SYSTEMCTL) {
1569 streq(args[0], "stop") ||
1570 streq(args[0], "condstop") ? "StopUnit" :
1571 streq(args[0], "reload") ? "ReloadUnit" :
1572 streq(args[0], "restart") ? "RestartUnit" :
1574 streq(args[0], "try-restart") ||
1575 streq(args[0], "condrestart") ? "TryRestartUnit" :
1577 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1579 streq(args[0], "reload-or-try-restart") ||
1580 streq(args[0], "condreload") ||
1582 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1584 action = verb_to_action(args[0]);
1586 mode = streq(args[0], "isolate") ? "isolate" :
1587 action_table[action].mode ?: arg_job_mode;
1589 one_name = action_table[action].target;
1592 assert(arg_action < ELEMENTSOF(action_table));
1593 assert(action_table[arg_action].target);
1595 method = "StartUnit";
1597 mode = action_table[arg_action].mode;
1598 one_name = action_table[arg_action].target;
1601 if (!arg_no_block) {
1602 ret = enable_wait_for_jobs(bus);
1604 log_error("Could not watch jobs: %s", strerror(-ret));
1608 s = set_new(string_hash_func, string_compare_func);
1614 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1616 ret = translate_bus_error_to_exit_status(ret, &error);
1618 STRV_FOREACH(name, args+1) {
1619 r = start_unit_one(bus, method, *name, mode, &error, s);
1621 ret = translate_bus_error_to_exit_status(r, &error);
1622 dbus_error_free(&error);
1627 if (!arg_no_block) {
1628 r = wait_for_jobs(bus, s);
1632 /* When stopping units, warn if they can still be triggered by
1633 * another active unit (socket, path, timer) */
1634 if (!arg_quiet && streq(method, "StopUnit")) {
1636 check_triggering_units(bus, one_name);
1638 STRV_FOREACH(name, args+1)
1639 check_triggering_units(bus, *name);
1646 /* Ask systemd-logind, which might grant access to unprivileged users
1647 * through PolicyKit */
1648 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1651 dbus_bool_t interactive = true;
1656 polkit_agent_open_if_enabled();
1664 case ACTION_POWEROFF:
1665 method = "PowerOff";
1668 case ACTION_SUSPEND:
1672 case ACTION_HIBERNATE:
1673 method = "Hibernate";
1676 case ACTION_HYBRID_SLEEP:
1677 method = "HybridSleep";
1684 return bus_method_call_with_reply(
1686 "org.freedesktop.login1",
1687 "/org/freedesktop/login1",
1688 "org.freedesktop.login1.Manager",
1692 DBUS_TYPE_BOOLEAN, &interactive,
1699 static int check_inhibitors(DBusConnection *bus, enum action a) {
1701 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1702 DBusMessageIter iter, sub, sub2;
1705 _cleanup_strv_free_ char **sessions = NULL;
1711 if (arg_ignore_inhibitors || arg_force > 0)
1723 r = bus_method_call_with_reply(
1725 "org.freedesktop.login1",
1726 "/org/freedesktop/login1",
1727 "org.freedesktop.login1.Manager",
1733 /* If logind is not around, then there are no inhibitors... */
1736 if (!dbus_message_iter_init(reply, &iter) ||
1737 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1738 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1739 log_error("Failed to parse reply.");
1743 dbus_message_iter_recurse(&iter, &sub);
1744 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1745 const char *what, *who, *why, *mode;
1747 _cleanup_strv_free_ char **sv = NULL;
1748 _cleanup_free_ char *comm = NULL, *user = NULL;
1750 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1751 log_error("Failed to parse reply.");
1755 dbus_message_iter_recurse(&sub, &sub2);
1757 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1758 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1759 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1760 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1761 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1762 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1763 log_error("Failed to parse reply.");
1767 if (!streq(mode, "block"))
1770 sv = strv_split(what, ":");
1774 if (!strv_contains(sv,
1776 a == ACTION_POWEROFF ||
1777 a == ACTION_REBOOT ||
1778 a == ACTION_KEXEC ? "shutdown" : "sleep"))
1781 get_process_comm(pid, &comm);
1782 user = uid_to_name(uid);
1783 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
1784 who, (unsigned long) pid, strna(comm), strna(user), why);
1788 dbus_message_iter_next(&sub);
1791 dbus_message_iter_recurse(&iter, &sub);
1793 /* Check for current sessions */
1794 sd_get_sessions(&sessions);
1795 STRV_FOREACH(s, sessions) {
1797 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1799 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1802 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1805 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1808 sd_session_get_tty(*s, &tty);
1809 sd_session_get_seat(*s, &seat);
1810 sd_session_get_service(*s, &service);
1811 user = uid_to_name(uid);
1813 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1820 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
1821 action_table[a].verb);
1829 static int start_special(DBusConnection *bus, char **args) {
1835 a = verb_to_action(args[0]);
1837 r = check_inhibitors(bus, a);
1841 if (arg_force >= 2 && geteuid() != 0) {
1842 log_error("Must be root.");
1846 if (arg_force >= 2 &&
1847 (a == ACTION_HALT ||
1848 a == ACTION_POWEROFF ||
1849 a == ACTION_REBOOT))
1852 if (arg_force >= 1 &&
1853 (a == ACTION_HALT ||
1854 a == ACTION_POWEROFF ||
1855 a == ACTION_REBOOT ||
1856 a == ACTION_KEXEC ||
1858 return daemon_reload(bus, args);
1860 /* first try logind, to allow authentication with polkit */
1861 if (geteuid() != 0 &&
1862 (a == ACTION_POWEROFF ||
1863 a == ACTION_REBOOT ||
1864 a == ACTION_SUSPEND ||
1865 a == ACTION_HIBERNATE ||
1866 a == ACTION_HYBRID_SLEEP)) {
1867 r = reboot_with_logind(bus, a);
1872 r = start_unit(bus, args);
1873 if (r == EXIT_SUCCESS)
1879 static int check_unit_active(DBusConnection *bus, char **args) {
1880 const char * const check_states[] = {
1887 int r = 3; /* According to LSB: "program is not running" */
1892 STRV_FOREACH(name, args+1) {
1895 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1905 static int check_unit_failed(DBusConnection *bus, char **args) {
1906 const char * const check_states[] = {
1917 STRV_FOREACH(name, args+1) {
1920 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1930 static int kill_unit(DBusConnection *bus, char **args) {
1938 arg_kill_who = "all";
1940 STRV_FOREACH(name, args+1) {
1941 _cleanup_free_ char *n = NULL;
1943 n = unit_name_mangle(*name);
1947 r = bus_method_call_with_reply(
1949 "org.freedesktop.systemd1",
1950 "/org/freedesktop/systemd1",
1951 "org.freedesktop.systemd1.Manager",
1955 DBUS_TYPE_STRING, &n,
1956 DBUS_TYPE_STRING, &arg_kill_who,
1957 DBUS_TYPE_INT32, &arg_signal,
1965 static int set_cgroup(DBusConnection *bus, char **args) {
1966 _cleanup_free_ char *n = NULL;
1967 const char *method, *runtime;
1975 streq(args[0], "set-cgroup") ? "SetUnitControlGroup" :
1976 streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
1977 : "UnsetUnitControlGroupAttribute";
1979 runtime = arg_runtime ? "runtime" : "persistent";
1981 n = unit_name_mangle(args[1]);
1985 STRV_FOREACH(argument, args + 2) {
1987 r = bus_method_call_with_reply(
1989 "org.freedesktop.systemd1",
1990 "/org/freedesktop/systemd1",
1991 "org.freedesktop.systemd1.Manager",
1995 DBUS_TYPE_STRING, &n,
1996 DBUS_TYPE_STRING, argument,
1997 DBUS_TYPE_STRING, &runtime,
2006 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2007 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2009 DBusMessageIter iter;
2010 _cleanup_free_ char *n = NULL;
2011 const char *runtime;
2017 dbus_error_init(&error);
2019 runtime = arg_runtime ? "runtime" : "persistent";
2021 n = unit_name_mangle(args[1]);
2025 m = dbus_message_new_method_call(
2026 "org.freedesktop.systemd1",
2027 "/org/freedesktop/systemd1",
2028 "org.freedesktop.systemd1.Manager",
2029 "SetUnitControlGroupAttribute");
2033 dbus_message_iter_init_append(m, &iter);
2034 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2035 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
2038 r = bus_append_strv_iter(&iter, args + 3);
2042 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2045 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2047 log_error("Failed to issue method call: %s", bus_error_message(&error));
2048 dbus_error_free(&error);
2055 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2056 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2057 _cleanup_free_ char *n = NULL;
2064 n = unit_name_mangle(args[1]);
2068 STRV_FOREACH(argument, args + 2) {
2069 _cleanup_strv_free_ char **list = NULL;
2070 DBusMessageIter iter;
2073 r = bus_method_call_with_reply(
2075 "org.freedesktop.systemd1",
2076 "/org/freedesktop/systemd1",
2077 "org.freedesktop.systemd1.Manager",
2078 "GetUnitControlGroupAttribute",
2081 DBUS_TYPE_STRING, &n,
2082 DBUS_TYPE_STRING, argument,
2087 if (!dbus_message_iter_init(reply, &iter)) {
2088 log_error("Failed to initialize iterator.");
2092 r = bus_parse_strv_iter(&iter, &list);
2094 log_error("Failed to parse value list.");
2098 STRV_FOREACH(a, list) {
2099 if (endswith(*a, "\n"))
2109 typedef struct ExecStatusInfo {
2117 usec_t start_timestamp;
2118 usec_t exit_timestamp;
2123 LIST_FIELDS(struct ExecStatusInfo, exec);
2126 static void exec_status_info_free(ExecStatusInfo *i) {
2135 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2136 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2137 DBusMessageIter sub2, sub3;
2141 int32_t code, status;
2147 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2150 dbus_message_iter_recurse(sub, &sub2);
2152 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2155 i->path = strdup(path);
2159 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2160 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2164 dbus_message_iter_recurse(&sub2, &sub3);
2165 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2166 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2167 dbus_message_iter_next(&sub3);
2171 i->argv = new0(char*, n+1);
2176 dbus_message_iter_recurse(&sub2, &sub3);
2177 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2180 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2181 dbus_message_iter_get_basic(&sub3, &s);
2182 dbus_message_iter_next(&sub3);
2184 i->argv[n] = strdup(s);
2191 if (!dbus_message_iter_next(&sub2) ||
2192 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2193 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2194 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2195 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2196 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2197 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2198 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2199 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2203 i->start_timestamp = (usec_t) start_timestamp;
2204 i->exit_timestamp = (usec_t) exit_timestamp;
2205 i->pid = (pid_t) pid;
2212 typedef struct UnitStatusInfo {
2214 const char *load_state;
2215 const char *active_state;
2216 const char *sub_state;
2217 const char *unit_file_state;
2219 const char *description;
2220 const char *following;
2222 char **documentation;
2224 const char *fragment_path;
2225 const char *source_path;
2226 const char *default_control_group;
2228 char **dropin_paths;
2230 const char *load_error;
2233 usec_t inactive_exit_timestamp;
2234 usec_t inactive_exit_timestamp_monotonic;
2235 usec_t active_enter_timestamp;
2236 usec_t active_exit_timestamp;
2237 usec_t inactive_enter_timestamp;
2239 bool need_daemon_reload;
2244 const char *status_text;
2247 usec_t start_timestamp;
2248 usec_t exit_timestamp;
2250 int exit_code, exit_status;
2252 usec_t condition_timestamp;
2253 bool condition_result;
2256 unsigned n_accepted;
2257 unsigned n_connections;
2260 /* Pairs of type, path */
2264 const char *sysfs_path;
2266 /* Mount, Automount */
2272 LIST_HEAD(ExecStatusInfo, exec);
2275 static void print_status_info(UnitStatusInfo *i) {
2277 const char *on, *off, *ss;
2279 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2280 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2283 arg_all * OUTPUT_SHOW_ALL |
2284 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2285 on_tty() * OUTPUT_COLOR |
2286 !arg_quiet * OUTPUT_WARN_CUTOFF |
2287 arg_full * OUTPUT_FULL_WIDTH;
2288 int maxlen = 8; /* a value that'll suffice most of the time */
2293 STRV_FOREACH_PAIR(t, t2, i->listen)
2294 maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
2296 maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
2297 if (i->main_pid > 0)
2298 maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
2299 else if (i->control_pid > 0)
2300 maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
2302 /* This shows pretty information about a unit. See
2303 * print_property() for a low-level property printer */
2305 printf("%s", strna(i->id));
2307 if (i->description && !streq_ptr(i->id, i->description))
2308 printf(" - %s", i->description);
2313 printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
2315 if (streq_ptr(i->load_state, "error")) {
2316 on = ansi_highlight_red(true);
2317 off = ansi_highlight_red(false);
2321 path = i->source_path ? i->source_path : i->fragment_path;
2324 printf(" %*s: %s%s%s (Reason: %s)\n",
2325 maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
2326 else if (path && i->unit_file_state)
2327 printf(" %*s: %s%s%s (%s; %s)\n",
2328 maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
2330 printf(" %*s: %s%s%s (%s)\n",
2331 maxlen, "Loaded", on, strna(i->load_state), off, path);
2333 printf(" %*s: %s%s%s\n",
2334 maxlen, "Loaded", on, strna(i->load_state), off);
2336 if (!strv_isempty(i->dropin_paths)) {
2341 STRV_FOREACH(dropin, i->dropin_paths) {
2342 if (! dir || last) {
2343 printf(" %*s ", maxlen, dir ? "" : "Drop-In:");
2347 if (path_get_parent(*dropin, &dir) < 0) {
2352 printf("%s\n %*s %s ", dir, maxlen, "",
2353 draw_special_char(DRAW_TREE_RIGHT));
2356 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2358 printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2364 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2366 if (streq_ptr(i->active_state, "failed")) {
2367 on = ansi_highlight_red(true);
2368 off = ansi_highlight_red(false);
2369 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2370 on = ansi_highlight_green(true);
2371 off = ansi_highlight_green(false);
2376 printf(" %*s: %s%s (%s)%s",
2377 maxlen, "Active", on, strna(i->active_state), ss, off);
2379 printf(" %*s: %s%s%s",
2380 maxlen, "Active", on, strna(i->active_state), off);
2382 if (!isempty(i->result) && !streq(i->result, "success"))
2383 printf(" (Result: %s)", i->result);
2385 timestamp = (streq_ptr(i->active_state, "active") ||
2386 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2387 (streq_ptr(i->active_state, "inactive") ||
2388 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2389 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2390 i->active_exit_timestamp;
2392 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2393 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2396 printf(" since %s; %s\n", s2, s1);
2398 printf(" since %s\n", s2);
2402 if (!i->condition_result && i->condition_timestamp > 0) {
2403 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2404 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2407 printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
2409 printf(" %*s start condition failed at %s\n", maxlen, "", s2);
2413 printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
2415 printf(" %*s: %s\n", maxlen, "Where", i->where);
2417 printf(" %*s: %s\n", maxlen, "What", i->what);
2419 STRV_FOREACH(t, i->documentation)
2420 printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
2422 STRV_FOREACH_PAIR(t, t2, i->listen)
2423 printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
2426 printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
2428 LIST_FOREACH(exec, p, i->exec) {
2429 _cleanup_free_ char *argv = NULL;
2432 /* Only show exited processes here */
2436 argv = strv_join(p->argv, " ");
2437 printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
2439 good = is_clean_exit_lsb(p->code, p->status, NULL);
2441 on = ansi_highlight_red(true);
2442 off = ansi_highlight_red(false);
2446 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2448 if (p->code == CLD_EXITED) {
2451 printf("status=%i", p->status);
2453 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2458 printf("signal=%s", signal_to_string(p->status));
2460 printf(")%s\n", off);
2462 if (i->main_pid == p->pid &&
2463 i->start_timestamp == p->start_timestamp &&
2464 i->exit_timestamp == p->start_timestamp)
2465 /* Let's not show this twice */
2468 if (p->pid == i->control_pid)
2472 if (i->main_pid > 0 || i->control_pid > 0) {
2473 if (i->main_pid > 0) {
2474 printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
2477 _cleanup_free_ char *comm = NULL;
2478 get_process_comm(i->main_pid, &comm);
2480 printf(" (%s)", comm);
2481 } else if (i->exit_code > 0) {
2482 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2484 if (i->exit_code == CLD_EXITED) {
2487 printf("status=%i", i->exit_status);
2489 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2494 printf("signal=%s", signal_to_string(i->exit_status));
2498 if (i->control_pid > 0)
2502 if (i->control_pid > 0) {
2503 _cleanup_free_ char *c = NULL;
2505 printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
2507 get_process_comm(i->control_pid, &c);
2516 printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
2518 if (i->default_control_group &&
2519 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2522 printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
2524 if (arg_transport != TRANSPORT_SSH) {
2527 char prefix[maxlen + 4];
2528 memset(prefix, ' ', sizeof(prefix) - 1);
2529 prefix[sizeof(prefix) - 1] = '\0';
2532 if (c > sizeof(prefix) - 1)
2533 c -= sizeof(prefix) - 1;
2537 if (i->main_pid > 0)
2538 extra[k++] = i->main_pid;
2540 if (i->control_pid > 0)
2541 extra[k++] = i->control_pid;
2543 show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
2544 c, false, extra, k, flags);
2548 if (i->id && arg_transport != TRANSPORT_SSH) {
2550 show_journal_by_unit(stdout,
2554 i->inactive_exit_timestamp_monotonic,
2558 arg_scope == UNIT_FILE_SYSTEM);
2561 if (i->need_daemon_reload)
2562 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2563 ansi_highlight_red(true),
2564 ansi_highlight_red(false),
2565 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2568 static void show_unit_help(UnitStatusInfo *i) {
2573 if (!i->documentation) {
2574 log_info("Documentation for %s not known.", i->id);
2578 STRV_FOREACH(p, i->documentation) {
2580 if (startswith(*p, "man:")) {
2583 char _cleanup_free_ *page = NULL, *section = NULL;
2584 const char *args[4] = { "man", NULL, NULL, NULL };
2589 if ((*p)[k-1] == ')')
2590 e = strrchr(*p, '(');
2593 page = strndup((*p) + 4, e - *p - 4);
2594 section = strndup(e + 1, *p + k - e - 2);
2595 if (!page || !section) {
2607 log_error("Failed to fork: %m");
2613 execvp(args[0], (char**) args);
2614 log_error("Failed to execute man: %m");
2615 _exit(EXIT_FAILURE);
2618 wait_for_terminate(pid, NULL);
2620 log_info("Can't show: %s", *p);
2624 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2630 switch (dbus_message_iter_get_arg_type(iter)) {
2632 case DBUS_TYPE_STRING: {
2635 dbus_message_iter_get_basic(iter, &s);
2638 if (streq(name, "Id"))
2640 else if (streq(name, "LoadState"))
2642 else if (streq(name, "ActiveState"))
2643 i->active_state = s;
2644 else if (streq(name, "SubState"))
2646 else if (streq(name, "Description"))
2648 else if (streq(name, "FragmentPath"))
2649 i->fragment_path = s;
2650 else if (streq(name, "SourcePath"))
2652 else if (streq(name, "DefaultControlGroup"))
2653 i->default_control_group = s;
2654 else if (streq(name, "StatusText"))
2656 else if (streq(name, "SysFSPath"))
2658 else if (streq(name, "Where"))
2660 else if (streq(name, "What"))
2662 else if (streq(name, "Following"))
2664 else if (streq(name, "UnitFileState"))
2665 i->unit_file_state = s;
2666 else if (streq(name, "Result"))
2673 case DBUS_TYPE_BOOLEAN: {
2676 dbus_message_iter_get_basic(iter, &b);
2678 if (streq(name, "Accept"))
2680 else if (streq(name, "NeedDaemonReload"))
2681 i->need_daemon_reload = b;
2682 else if (streq(name, "ConditionResult"))
2683 i->condition_result = b;
2688 case DBUS_TYPE_UINT32: {
2691 dbus_message_iter_get_basic(iter, &u);
2693 if (streq(name, "MainPID")) {
2695 i->main_pid = (pid_t) u;
2698 } else if (streq(name, "ControlPID"))
2699 i->control_pid = (pid_t) u;
2700 else if (streq(name, "ExecMainPID")) {
2702 i->main_pid = (pid_t) u;
2703 } else if (streq(name, "NAccepted"))
2705 else if (streq(name, "NConnections"))
2706 i->n_connections = u;
2711 case DBUS_TYPE_INT32: {
2714 dbus_message_iter_get_basic(iter, &j);
2716 if (streq(name, "ExecMainCode"))
2717 i->exit_code = (int) j;
2718 else if (streq(name, "ExecMainStatus"))
2719 i->exit_status = (int) j;
2724 case DBUS_TYPE_UINT64: {
2727 dbus_message_iter_get_basic(iter, &u);
2729 if (streq(name, "ExecMainStartTimestamp"))
2730 i->start_timestamp = (usec_t) u;
2731 else if (streq(name, "ExecMainExitTimestamp"))
2732 i->exit_timestamp = (usec_t) u;
2733 else if (streq(name, "ActiveEnterTimestamp"))
2734 i->active_enter_timestamp = (usec_t) u;
2735 else if (streq(name, "InactiveEnterTimestamp"))
2736 i->inactive_enter_timestamp = (usec_t) u;
2737 else if (streq(name, "InactiveExitTimestamp"))
2738 i->inactive_exit_timestamp = (usec_t) u;
2739 else if (streq(name, "InactiveExitTimestampMonotonic"))
2740 i->inactive_exit_timestamp_monotonic = (usec_t) u;
2741 else if (streq(name, "ActiveExitTimestamp"))
2742 i->active_exit_timestamp = (usec_t) u;
2743 else if (streq(name, "ConditionTimestamp"))
2744 i->condition_timestamp = (usec_t) u;
2749 case DBUS_TYPE_ARRAY: {
2751 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2752 startswith(name, "Exec")) {
2753 DBusMessageIter sub;
2755 dbus_message_iter_recurse(iter, &sub);
2756 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2757 ExecStatusInfo *info;
2760 if (!(info = new0(ExecStatusInfo, 1)))
2763 if (!(info->name = strdup(name))) {
2768 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2773 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2775 dbus_message_iter_next(&sub);
2778 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2779 DBusMessageIter sub, sub2;
2781 dbus_message_iter_recurse(iter, &sub);
2782 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2783 const char *type, *path;
2785 dbus_message_iter_recurse(&sub, &sub2);
2787 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2788 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
2791 r = strv_extend(&i->listen, type);
2794 r = strv_extend(&i->listen, path);
2799 dbus_message_iter_next(&sub);
2804 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
2805 int r = bus_parse_strv_iter(iter, &i->dropin_paths);
2809 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2810 streq(name, "Documentation")) {
2812 DBusMessageIter sub;
2814 dbus_message_iter_recurse(iter, &sub);
2815 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2819 dbus_message_iter_get_basic(&sub, &s);
2821 r = strv_extend(&i->documentation, s);
2825 dbus_message_iter_next(&sub);
2832 case DBUS_TYPE_STRUCT: {
2834 if (streq(name, "LoadError")) {
2835 DBusMessageIter sub;
2836 const char *n, *message;
2839 dbus_message_iter_recurse(iter, &sub);
2841 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2845 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2849 if (!isempty(message))
2850 i->load_error = message;
2860 static int print_property(const char *name, DBusMessageIter *iter) {
2864 /* This is a low-level property printer, see
2865 * print_status_info() for the nicer output */
2867 if (arg_property && !strv_find(arg_property, name))
2870 switch (dbus_message_iter_get_arg_type(iter)) {
2872 case DBUS_TYPE_STRUCT: {
2873 DBusMessageIter sub;
2874 dbus_message_iter_recurse(iter, &sub);
2876 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2879 dbus_message_iter_get_basic(&sub, &u);
2882 printf("%s=%u\n", name, (unsigned) u);
2884 printf("%s=\n", name);
2887 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2890 dbus_message_iter_get_basic(&sub, &s);
2892 if (arg_all || s[0])
2893 printf("%s=%s\n", name, s);
2896 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2897 const char *a = NULL, *b = NULL;
2899 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2900 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2902 if (arg_all || !isempty(a) || !isempty(b))
2903 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2911 case DBUS_TYPE_ARRAY:
2913 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2914 DBusMessageIter sub, sub2;
2916 dbus_message_iter_recurse(iter, &sub);
2917 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2921 dbus_message_iter_recurse(&sub, &sub2);
2923 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2924 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2925 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2927 dbus_message_iter_next(&sub);
2932 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2933 DBusMessageIter sub, sub2;
2935 dbus_message_iter_recurse(iter, &sub);
2937 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2938 const char *type, *path;
2940 dbus_message_iter_recurse(&sub, &sub2);
2942 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2943 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2944 printf("%s=%s\n", type, path);
2946 dbus_message_iter_next(&sub);
2951 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2952 DBusMessageIter sub, sub2;
2954 dbus_message_iter_recurse(iter, &sub);
2955 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2956 const char *type, *path;
2958 dbus_message_iter_recurse(&sub, &sub2);
2960 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2961 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2962 printf("Listen%s=%s\n", type, path);
2964 dbus_message_iter_next(&sub);
2969 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2970 DBusMessageIter sub, sub2;
2972 dbus_message_iter_recurse(iter, &sub);
2973 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2975 uint64_t value, next_elapse;
2977 dbus_message_iter_recurse(&sub, &sub2);
2979 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2980 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2981 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2982 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2984 printf("%s={ value=%s ; next_elapse=%s }\n",
2986 format_timespan(timespan1, sizeof(timespan1), value, 0),
2987 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
2990 dbus_message_iter_next(&sub);
2995 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2996 DBusMessageIter sub, sub2;
2998 dbus_message_iter_recurse(iter, &sub);
2999 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3000 const char *controller, *attr, *value;
3002 dbus_message_iter_recurse(&sub, &sub2);
3004 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
3005 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
3006 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
3008 printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
3014 dbus_message_iter_next(&sub);
3019 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3020 DBusMessageIter sub;
3022 dbus_message_iter_recurse(iter, &sub);
3023 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3024 ExecStatusInfo info;
3027 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3028 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3029 char _cleanup_free_ *t;
3031 t = strv_join(info.argv, " ");
3033 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3037 yes_no(info.ignore),
3038 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3039 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3040 (unsigned) info. pid,
3041 sigchld_code_to_string(info.code),
3043 info.code == CLD_EXITED ? "" : "/",
3044 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3048 strv_free(info.argv);
3050 dbus_message_iter_next(&sub);
3059 if (generic_print_property(name, iter, arg_all) > 0)
3063 printf("%s=[unprintable]\n", name);