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 char **arg_types = NULL;
72 static char **arg_load_states = NULL;
73 static char **arg_properties = 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_types || ((dot = strrchr(u->id, '.')) &&
299 strv_find(arg_types, dot+1))) &&
300 (!arg_load_states || strv_find(arg_load_states, u->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_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
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);
900 char *name, *type, *state;
903 static void list_jobs_print(struct job_info* jobs, size_t n) {
906 const char *on, *off;
907 bool shorten = false;
909 assert(n == 0 || jobs);
912 on = ansi_highlight_green(true);
913 off = ansi_highlight_green(false);
915 printf("%sNo jobs running.%s\n", on, off);
919 pager_open_if_enabled();
922 /* JOB UNIT TYPE STATE */
923 unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5;
925 for (i = 0, j = jobs; i < n; i++, j++) {
926 assert(j->name && j->type && j->state);
927 l0 = MAX(l0, decimal_str_max(j->id));
928 l1 = MAX(l1, strlen(j->name));
929 l2 = MAX(l2, strlen(j->type));
930 l3 = MAX(l3, strlen(j->state));
933 if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) {
934 l1 = MAX(33u, columns() - l0 - l2 - l3 - 3);
939 printf("%*s %-*s %-*s %-*s\n",
945 for (i = 0, j = jobs; i < n; i++, j++) {
946 char _cleanup_free_ *e = NULL;
948 if (streq(j->state, "running")) {
949 on = ansi_highlight(true);
950 off = ansi_highlight(false);
954 e = shorten ? ellipsize(j->name, l1, 33) : NULL;
955 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
957 on, l1, e ? e : j->name, off,
959 on, l3, j->state, off);
963 on = ansi_highlight(true);
964 off = ansi_highlight(false);
967 printf("\n%s%zu jobs listed%s.\n", on, n, off);
970 static int list_jobs(DBusConnection *bus, char **args) {
971 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
972 DBusMessageIter iter, sub, sub2;
974 struct job_info *jobs = NULL;
975 size_t size = 0, used = 0;
977 r = bus_method_call_with_reply(
979 "org.freedesktop.systemd1",
980 "/org/freedesktop/systemd1",
981 "org.freedesktop.systemd1.Manager",
989 if (!dbus_message_iter_init(reply, &iter) ||
990 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
991 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
992 log_error("Failed to parse reply.");
996 dbus_message_iter_recurse(&iter, &sub);
998 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
999 const char *name, *type, *state, *job_path, *unit_path;
1002 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1003 log_error("Failed to parse reply.");
1007 dbus_message_iter_recurse(&sub, &sub2);
1009 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1010 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1011 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1012 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1013 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1014 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1015 log_error("Failed to parse reply.");
1020 if (!greedy_realloc((void**) &jobs, &size,
1021 sizeof(struct job_info) * (used + 1))) {
1026 jobs[used++] = (struct job_info) { id,
1030 if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) {
1035 dbus_message_iter_next(&sub);
1038 list_jobs_print(jobs, used);
1042 free(jobs[used].name);
1043 free(jobs[used].type);
1044 free(jobs[used].state);
1051 static int load_unit(DBusConnection *bus, char **args) {
1056 STRV_FOREACH(name, args+1) {
1057 _cleanup_free_ char *n = NULL;
1060 n = unit_name_mangle(*name);
1064 r = bus_method_call_with_reply(
1066 "org.freedesktop.systemd1",
1067 "/org/freedesktop/systemd1",
1068 "org.freedesktop.systemd1.Manager",
1072 DBUS_TYPE_STRING, &n,
1081 static int cancel_job(DBusConnection *bus, char **args) {
1086 if (strv_length(args) <= 1)
1087 return daemon_reload(bus, args);
1089 STRV_FOREACH(name, args+1) {
1093 r = safe_atou32(*name, &id);
1095 log_error("Failed to parse job id: %s", strerror(-r));
1099 r = bus_method_call_with_reply(
1101 "org.freedesktop.systemd1",
1102 "/org/freedesktop/systemd1",
1103 "org.freedesktop.systemd1.Manager",
1107 DBUS_TYPE_UINT32, &id,
1116 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1117 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1118 dbus_bool_t b = FALSE;
1119 DBusMessageIter iter, sub;
1121 *interface = "org.freedesktop.systemd1.Unit",
1122 *property = "NeedDaemonReload",
1124 _cleanup_free_ char *n = NULL;
1127 /* We ignore all errors here, since this is used to show a warning only */
1129 n = unit_name_mangle(unit);
1133 r = bus_method_call_with_reply(
1135 "org.freedesktop.systemd1",
1136 "/org/freedesktop/systemd1",
1137 "org.freedesktop.systemd1.Manager",
1141 DBUS_TYPE_STRING, &n,
1146 if (!dbus_message_get_args(reply, NULL,
1147 DBUS_TYPE_OBJECT_PATH, &path,
1151 dbus_message_unref(reply);
1154 r = bus_method_call_with_reply(
1156 "org.freedesktop.systemd1",
1158 "org.freedesktop.DBus.Properties",
1162 DBUS_TYPE_STRING, &interface,
1163 DBUS_TYPE_STRING, &property,
1168 if (!dbus_message_iter_init(reply, &iter) ||
1169 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1172 dbus_message_iter_recurse(&iter, &sub);
1173 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1176 dbus_message_iter_get_basic(&sub, &b);
1180 typedef struct WaitData {
1187 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1188 DBusError _cleanup_dbus_error_free_ error;
1191 dbus_error_init(&error);
1197 log_debug("Got D-Bus request: %s.%s() on %s",
1198 dbus_message_get_interface(message),
1199 dbus_message_get_member(message),
1200 dbus_message_get_path(message));
1202 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1203 log_error("Warning! D-Bus connection terminated.");
1204 dbus_connection_close(connection);
1206 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1208 const char *path, *result, *unit;
1210 if (dbus_message_get_args(message, &error,
1211 DBUS_TYPE_UINT32, &id,
1212 DBUS_TYPE_OBJECT_PATH, &path,
1213 DBUS_TYPE_STRING, &unit,
1214 DBUS_TYPE_STRING, &result,
1215 DBUS_TYPE_INVALID)) {
1217 free(set_remove(d->set, (char*) path));
1219 if (!isempty(result))
1220 d->result = strdup(result);
1223 d->name = strdup(unit);
1225 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1228 dbus_error_free(&error);
1229 if (dbus_message_get_args(message, &error,
1230 DBUS_TYPE_UINT32, &id,
1231 DBUS_TYPE_OBJECT_PATH, &path,
1232 DBUS_TYPE_STRING, &result,
1233 DBUS_TYPE_INVALID)) {
1234 /* Compatibility with older systemd versions <
1235 * 183 during upgrades. This should be dropped
1237 free(set_remove(d->set, (char*) path));
1240 d->result = strdup(result);
1242 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1246 log_error("Failed to parse message: %s", bus_error_message(&error));
1249 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1252 static int enable_wait_for_jobs(DBusConnection *bus) {
1260 dbus_error_init(&error);
1261 dbus_bus_add_match(bus,
1263 "sender='org.freedesktop.systemd1',"
1264 "interface='org.freedesktop.systemd1.Manager',"
1265 "member='JobRemoved',"
1266 "path='/org/freedesktop/systemd1'",
1269 if (dbus_error_is_set(&error)) {
1270 log_error("Failed to add match: %s", bus_error_message(&error));
1271 dbus_error_free(&error);
1275 /* This is slightly dirty, since we don't undo the match registrations. */
1279 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1281 WaitData d = { .set = s };
1286 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1289 while (!set_isempty(s)) {
1291 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1292 log_error("Disconnected from bus.");
1293 return -ECONNREFUSED;
1300 if (streq(d.result, "timeout"))
1301 log_error("Job for %s timed out.", strna(d.name));
1302 else if (streq(d.result, "canceled"))
1303 log_error("Job for %s canceled.", strna(d.name));
1304 else if (streq(d.result, "dependency"))
1305 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1306 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1307 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1310 if (streq_ptr(d.result, "timeout"))
1312 else if (streq_ptr(d.result, "canceled"))
1314 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1325 dbus_connection_remove_filter(bus, wait_filter, &d);
1329 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1330 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1331 _cleanup_free_ char *n = NULL;
1332 DBusMessageIter iter, sub;
1334 *interface = "org.freedesktop.systemd1.Unit",
1335 *property = "ActiveState";
1336 const char *state, *path;
1342 dbus_error_init(&error);
1344 n = unit_name_mangle(name);
1348 r = bus_method_call_with_reply (
1350 "org.freedesktop.systemd1",
1351 "/org/freedesktop/systemd1",
1352 "org.freedesktop.systemd1.Manager",
1356 DBUS_TYPE_STRING, &n,
1359 dbus_error_free(&error);
1366 if (!dbus_message_get_args(reply, NULL,
1367 DBUS_TYPE_OBJECT_PATH, &path,
1368 DBUS_TYPE_INVALID)) {
1369 log_error("Failed to parse reply.");
1373 dbus_message_unref(reply);
1376 r = bus_method_call_with_reply(
1378 "org.freedesktop.systemd1",
1380 "org.freedesktop.DBus.Properties",
1384 DBUS_TYPE_STRING, &interface,
1385 DBUS_TYPE_STRING, &property,
1393 if (!dbus_message_iter_init(reply, &iter) ||
1394 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1395 log_error("Failed to parse reply.");
1399 dbus_message_iter_recurse(&iter, &sub);
1401 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1402 log_error("Failed to parse reply.");
1406 dbus_message_iter_get_basic(&sub, &state);
1411 return strv_find(check_states, state) ? 1 : 0;
1414 static void check_triggering_units(
1415 DBusConnection *bus,
1416 const char *unit_name) {
1418 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1419 DBusMessageIter iter, sub;
1420 const char *interface = "org.freedesktop.systemd1.Unit",
1421 *load_state_property = "LoadState",
1422 *triggered_by_property = "TriggeredBy",
1424 char _cleanup_free_ *unit_path = NULL, *n = NULL;
1425 bool print_warning_label = true;
1428 n = unit_name_mangle(unit_name);
1434 unit_path = unit_dbus_path_from_name(n);
1440 r = bus_method_call_with_reply(
1442 "org.freedesktop.systemd1",
1444 "org.freedesktop.DBus.Properties",
1448 DBUS_TYPE_STRING, &interface,
1449 DBUS_TYPE_STRING, &load_state_property,
1454 if (!dbus_message_iter_init(reply, &iter) ||
1455 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1456 log_error("Failed to parse reply.");
1460 dbus_message_iter_recurse(&iter, &sub);
1462 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1463 log_error("Failed to parse reply.");
1467 dbus_message_iter_get_basic(&sub, &state);
1469 if (streq(state, "masked"))
1472 dbus_message_unref(reply);
1475 r = bus_method_call_with_reply(
1477 "org.freedesktop.systemd1",
1479 "org.freedesktop.DBus.Properties",
1483 DBUS_TYPE_STRING, &interface,
1484 DBUS_TYPE_STRING, &triggered_by_property,
1489 if (!dbus_message_iter_init(reply, &iter) ||
1490 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1491 log_error("Failed to parse reply.");
1495 dbus_message_iter_recurse(&iter, &sub);
1496 dbus_message_iter_recurse(&sub, &iter);
1499 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1500 const char * const check_states[] = {
1505 const char *service_trigger;
1507 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1508 log_error("Failed to parse reply.");
1512 dbus_message_iter_get_basic(&sub, &service_trigger);
1514 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1518 if (print_warning_label) {
1519 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1520 print_warning_label = false;
1523 log_warning(" %s", service_trigger);
1526 dbus_message_iter_next(&sub);
1530 static int start_unit_one(
1531 DBusConnection *bus,
1538 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1539 _cleanup_free_ char *n;
1548 n = unit_name_mangle(name);
1552 r = bus_method_call_with_reply(
1554 "org.freedesktop.systemd1",
1555 "/org/freedesktop/systemd1",
1556 "org.freedesktop.systemd1.Manager",
1560 DBUS_TYPE_STRING, &n,
1561 DBUS_TYPE_STRING, &mode,
1564 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1565 /* There's always a fallback possible for
1566 * legacy actions. */
1569 log_error("Failed to issue method call: %s", bus_error_message(error));
1574 if (!dbus_message_get_args(reply, error,
1575 DBUS_TYPE_OBJECT_PATH, &path,
1576 DBUS_TYPE_INVALID)) {
1577 log_error("Failed to parse reply: %s", bus_error_message(error));
1581 if (need_daemon_reload(bus, n))
1582 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1583 n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1595 log_error("Failed to add path to set.");
1603 static const struct {
1607 } action_table[_ACTION_MAX] = {
1608 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
1609 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
1610 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
1611 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
1612 [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
1613 [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
1614 [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
1615 [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
1616 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
1617 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
1618 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
1619 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
1620 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
1621 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
1622 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1625 static enum action verb_to_action(const char *verb) {
1628 for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1629 if (action_table[i].verb && streq(verb, action_table[i].verb))
1631 return ACTION_INVALID;
1634 static int start_unit(DBusConnection *bus, char **args) {
1637 const char *method, *mode, *one_name;
1638 Set _cleanup_set_free_free_ *s = NULL;
1639 DBusError _cleanup_dbus_error_free_ error;
1642 dbus_error_init(&error);
1646 ask_password_agent_open_if_enabled();
1648 if (arg_action == ACTION_SYSTEMCTL) {
1651 streq(args[0], "stop") ||
1652 streq(args[0], "condstop") ? "StopUnit" :
1653 streq(args[0], "reload") ? "ReloadUnit" :
1654 streq(args[0], "restart") ? "RestartUnit" :
1656 streq(args[0], "try-restart") ||
1657 streq(args[0], "condrestart") ? "TryRestartUnit" :
1659 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1661 streq(args[0], "reload-or-try-restart") ||
1662 streq(args[0], "condreload") ||
1664 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1666 action = verb_to_action(args[0]);
1668 mode = streq(args[0], "isolate") ? "isolate" :
1669 action_table[action].mode ?: arg_job_mode;
1671 one_name = action_table[action].target;
1674 assert(arg_action < ELEMENTSOF(action_table));
1675 assert(action_table[arg_action].target);
1677 method = "StartUnit";
1679 mode = action_table[arg_action].mode;
1680 one_name = action_table[arg_action].target;
1683 if (!arg_no_block) {
1684 ret = enable_wait_for_jobs(bus);
1686 log_error("Could not watch jobs: %s", strerror(-ret));
1690 s = set_new(string_hash_func, string_compare_func);
1696 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1698 ret = translate_bus_error_to_exit_status(ret, &error);
1700 STRV_FOREACH(name, args+1) {
1701 r = start_unit_one(bus, method, *name, mode, &error, s);
1703 ret = translate_bus_error_to_exit_status(r, &error);
1704 dbus_error_free(&error);
1709 if (!arg_no_block) {
1710 r = wait_for_jobs(bus, s);
1714 /* When stopping units, warn if they can still be triggered by
1715 * another active unit (socket, path, timer) */
1716 if (!arg_quiet && streq(method, "StopUnit")) {
1718 check_triggering_units(bus, one_name);
1720 STRV_FOREACH(name, args+1)
1721 check_triggering_units(bus, *name);
1728 /* Ask systemd-logind, which might grant access to unprivileged users
1729 * through PolicyKit */
1730 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1733 dbus_bool_t interactive = true;
1738 polkit_agent_open_if_enabled();
1746 case ACTION_POWEROFF:
1747 method = "PowerOff";
1750 case ACTION_SUSPEND:
1754 case ACTION_HIBERNATE:
1755 method = "Hibernate";
1758 case ACTION_HYBRID_SLEEP:
1759 method = "HybridSleep";
1766 return bus_method_call_with_reply(
1768 "org.freedesktop.login1",
1769 "/org/freedesktop/login1",
1770 "org.freedesktop.login1.Manager",
1774 DBUS_TYPE_BOOLEAN, &interactive,
1781 static int check_inhibitors(DBusConnection *bus, enum action a) {
1783 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1784 DBusMessageIter iter, sub, sub2;
1787 _cleanup_strv_free_ char **sessions = NULL;
1793 if (arg_ignore_inhibitors || arg_force > 0)
1805 r = bus_method_call_with_reply(
1807 "org.freedesktop.login1",
1808 "/org/freedesktop/login1",
1809 "org.freedesktop.login1.Manager",
1815 /* If logind is not around, then there are no inhibitors... */
1818 if (!dbus_message_iter_init(reply, &iter) ||
1819 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1820 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1821 log_error("Failed to parse reply.");
1825 dbus_message_iter_recurse(&iter, &sub);
1826 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1827 const char *what, *who, *why, *mode;
1829 _cleanup_strv_free_ char **sv = NULL;
1830 _cleanup_free_ char *comm = NULL, *user = NULL;
1832 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1833 log_error("Failed to parse reply.");
1837 dbus_message_iter_recurse(&sub, &sub2);
1839 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1840 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1841 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1842 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1843 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1844 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1845 log_error("Failed to parse reply.");
1849 if (!streq(mode, "block"))
1852 sv = strv_split(what, ":");
1856 if (!strv_contains(sv,
1858 a == ACTION_POWEROFF ||
1859 a == ACTION_REBOOT ||
1860 a == ACTION_KEXEC ? "shutdown" : "sleep"))
1863 get_process_comm(pid, &comm);
1864 user = uid_to_name(uid);
1865 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
1866 who, (unsigned long) pid, strna(comm), strna(user), why);
1870 dbus_message_iter_next(&sub);
1873 dbus_message_iter_recurse(&iter, &sub);
1875 /* Check for current sessions */
1876 sd_get_sessions(&sessions);
1877 STRV_FOREACH(s, sessions) {
1879 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1881 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1884 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1887 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1890 sd_session_get_tty(*s, &tty);
1891 sd_session_get_seat(*s, &seat);
1892 sd_session_get_service(*s, &service);
1893 user = uid_to_name(uid);
1895 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1902 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
1903 action_table[a].verb);
1911 static int start_special(DBusConnection *bus, char **args) {
1917 a = verb_to_action(args[0]);
1919 r = check_inhibitors(bus, a);
1923 if (arg_force >= 2 && geteuid() != 0) {
1924 log_error("Must be root.");
1928 if (arg_force >= 2 &&
1929 (a == ACTION_HALT ||
1930 a == ACTION_POWEROFF ||
1931 a == ACTION_REBOOT))
1934 if (arg_force >= 1 &&
1935 (a == ACTION_HALT ||
1936 a == ACTION_POWEROFF ||
1937 a == ACTION_REBOOT ||
1938 a == ACTION_KEXEC ||
1940 return daemon_reload(bus, args);
1942 /* first try logind, to allow authentication with polkit */
1943 if (geteuid() != 0 &&
1944 (a == ACTION_POWEROFF ||
1945 a == ACTION_REBOOT ||
1946 a == ACTION_SUSPEND ||
1947 a == ACTION_HIBERNATE ||
1948 a == ACTION_HYBRID_SLEEP)) {
1949 r = reboot_with_logind(bus, a);
1954 r = start_unit(bus, args);
1955 if (r == EXIT_SUCCESS)
1961 static int check_unit_active(DBusConnection *bus, char **args) {
1962 const char * const check_states[] = {
1969 int r = 3; /* According to LSB: "program is not running" */
1974 STRV_FOREACH(name, args+1) {
1977 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1987 static int check_unit_failed(DBusConnection *bus, char **args) {
1988 const char * const check_states[] = {
1999 STRV_FOREACH(name, args+1) {
2002 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2012 static int kill_unit(DBusConnection *bus, char **args) {
2020 arg_kill_who = "all";
2022 STRV_FOREACH(name, args+1) {
2023 _cleanup_free_ char *n = NULL;
2025 n = unit_name_mangle(*name);
2029 r = bus_method_call_with_reply(
2031 "org.freedesktop.systemd1",
2032 "/org/freedesktop/systemd1",
2033 "org.freedesktop.systemd1.Manager",
2037 DBUS_TYPE_STRING, &n,
2038 DBUS_TYPE_STRING, &arg_kill_who,
2039 DBUS_TYPE_INT32, &arg_signal,
2047 static int set_cgroup(DBusConnection *bus, char **args) {
2048 _cleanup_free_ char *n = NULL;
2049 const char *method, *runtime;
2057 streq(args[0], "set-cgroup") ? "SetUnitControlGroup" :
2058 streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
2059 : "UnsetUnitControlGroupAttribute";
2061 runtime = arg_runtime ? "runtime" : "persistent";
2063 n = unit_name_mangle(args[1]);
2067 STRV_FOREACH(argument, args + 2) {
2069 r = bus_method_call_with_reply(
2071 "org.freedesktop.systemd1",
2072 "/org/freedesktop/systemd1",
2073 "org.freedesktop.systemd1.Manager",
2077 DBUS_TYPE_STRING, &n,
2078 DBUS_TYPE_STRING, argument,
2079 DBUS_TYPE_STRING, &runtime,
2088 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2089 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2091 DBusMessageIter iter;
2092 _cleanup_free_ char *n = NULL;
2093 const char *runtime;
2099 dbus_error_init(&error);
2101 runtime = arg_runtime ? "runtime" : "persistent";
2103 n = unit_name_mangle(args[1]);
2107 m = dbus_message_new_method_call(
2108 "org.freedesktop.systemd1",
2109 "/org/freedesktop/systemd1",
2110 "org.freedesktop.systemd1.Manager",
2111 "SetUnitControlGroupAttribute");
2115 dbus_message_iter_init_append(m, &iter);
2116 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2117 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
2120 r = bus_append_strv_iter(&iter, args + 3);
2124 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2127 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2129 log_error("Failed to issue method call: %s", bus_error_message(&error));
2130 dbus_error_free(&error);
2137 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2138 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2139 _cleanup_free_ char *n = NULL;
2146 n = unit_name_mangle(args[1]);
2150 STRV_FOREACH(argument, args + 2) {
2151 _cleanup_strv_free_ char **list = NULL;
2152 DBusMessageIter iter;
2155 r = bus_method_call_with_reply(
2157 "org.freedesktop.systemd1",
2158 "/org/freedesktop/systemd1",
2159 "org.freedesktop.systemd1.Manager",
2160 "GetUnitControlGroupAttribute",
2163 DBUS_TYPE_STRING, &n,
2164 DBUS_TYPE_STRING, argument,
2169 if (!dbus_message_iter_init(reply, &iter)) {
2170 log_error("Failed to initialize iterator.");
2174 r = bus_parse_strv_iter(&iter, &list);
2176 log_error("Failed to parse value list.");
2180 STRV_FOREACH(a, list) {
2181 if (endswith(*a, "\n"))
2191 typedef struct ExecStatusInfo {
2199 usec_t start_timestamp;
2200 usec_t exit_timestamp;
2205 LIST_FIELDS(struct ExecStatusInfo, exec);
2208 static void exec_status_info_free(ExecStatusInfo *i) {
2217 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2218 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2219 DBusMessageIter sub2, sub3;
2223 int32_t code, status;
2229 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2232 dbus_message_iter_recurse(sub, &sub2);
2234 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2237 i->path = strdup(path);
2241 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2242 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2246 dbus_message_iter_recurse(&sub2, &sub3);
2247 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2248 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2249 dbus_message_iter_next(&sub3);
2253 i->argv = new0(char*, n+1);
2258 dbus_message_iter_recurse(&sub2, &sub3);
2259 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2262 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2263 dbus_message_iter_get_basic(&sub3, &s);
2264 dbus_message_iter_next(&sub3);
2266 i->argv[n] = strdup(s);
2273 if (!dbus_message_iter_next(&sub2) ||
2274 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2275 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2276 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2277 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2278 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2279 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2280 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2281 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2285 i->start_timestamp = (usec_t) start_timestamp;
2286 i->exit_timestamp = (usec_t) exit_timestamp;
2287 i->pid = (pid_t) pid;
2294 typedef struct UnitStatusInfo {
2296 const char *load_state;
2297 const char *active_state;
2298 const char *sub_state;
2299 const char *unit_file_state;
2301 const char *description;
2302 const char *following;
2304 char **documentation;
2306 const char *fragment_path;
2307 const char *source_path;
2308 const char *default_control_group;
2310 char **dropin_paths;
2312 const char *load_error;
2315 usec_t inactive_exit_timestamp;
2316 usec_t inactive_exit_timestamp_monotonic;
2317 usec_t active_enter_timestamp;
2318 usec_t active_exit_timestamp;
2319 usec_t inactive_enter_timestamp;
2321 bool need_daemon_reload;
2326 const char *status_text;
2329 usec_t start_timestamp;
2330 usec_t exit_timestamp;
2332 int exit_code, exit_status;
2334 usec_t condition_timestamp;
2335 bool condition_result;
2338 unsigned n_accepted;
2339 unsigned n_connections;
2342 /* Pairs of type, path */
2346 const char *sysfs_path;
2348 /* Mount, Automount */
2354 LIST_HEAD(ExecStatusInfo, exec);
2357 static void print_status_info(UnitStatusInfo *i) {
2359 const char *on, *off, *ss;
2361 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2362 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2365 arg_all * OUTPUT_SHOW_ALL |
2366 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2367 on_tty() * OUTPUT_COLOR |
2368 !arg_quiet * OUTPUT_WARN_CUTOFF |
2369 arg_full * OUTPUT_FULL_WIDTH;
2370 int maxlen = 8; /* a value that'll suffice most of the time */
2375 STRV_FOREACH_PAIR(t, t2, i->listen)
2376 maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
2378 maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
2379 if (i->main_pid > 0)
2380 maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
2381 else if (i->control_pid > 0)
2382 maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
2384 /* This shows pretty information about a unit. See
2385 * print_property() for a low-level property printer */
2387 printf("%s", strna(i->id));
2389 if (i->description && !streq_ptr(i->id, i->description))
2390 printf(" - %s", i->description);
2395 printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
2397 if (streq_ptr(i->load_state, "error")) {
2398 on = ansi_highlight_red(true);
2399 off = ansi_highlight_red(false);
2403 path = i->source_path ? i->source_path : i->fragment_path;
2406 printf(" %*s: %s%s%s (Reason: %s)\n",
2407 maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
2408 else if (path && i->unit_file_state)
2409 printf(" %*s: %s%s%s (%s; %s)\n",
2410 maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
2412 printf(" %*s: %s%s%s (%s)\n",
2413 maxlen, "Loaded", on, strna(i->load_state), off, path);
2415 printf(" %*s: %s%s%s\n",
2416 maxlen, "Loaded", on, strna(i->load_state), off);
2418 if (!strv_isempty(i->dropin_paths)) {
2423 STRV_FOREACH(dropin, i->dropin_paths) {
2424 if (! dir || last) {
2425 printf(" %*s ", maxlen, dir ? "" : "Drop-In:");
2429 if (path_get_parent(*dropin, &dir) < 0) {
2434 printf("%s\n %*s %s", dir, maxlen, "",
2435 draw_special_char(DRAW_TREE_RIGHT));
2438 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2440 printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2446 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2448 if (streq_ptr(i->active_state, "failed")) {
2449 on = ansi_highlight_red(true);
2450 off = ansi_highlight_red(false);
2451 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2452 on = ansi_highlight_green(true);
2453 off = ansi_highlight_green(false);
2458 printf(" %*s: %s%s (%s)%s",
2459 maxlen, "Active", on, strna(i->active_state), ss, off);
2461 printf(" %*s: %s%s%s",
2462 maxlen, "Active", on, strna(i->active_state), off);
2464 if (!isempty(i->result) && !streq(i->result, "success"))
2465 printf(" (Result: %s)", i->result);
2467 timestamp = (streq_ptr(i->active_state, "active") ||
2468 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2469 (streq_ptr(i->active_state, "inactive") ||
2470 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2471 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2472 i->active_exit_timestamp;
2474 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2475 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2478 printf(" since %s; %s\n", s2, s1);
2480 printf(" since %s\n", s2);
2484 if (!i->condition_result && i->condition_timestamp > 0) {
2485 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2486 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2489 printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
2491 printf(" %*s start condition failed at %s\n", maxlen, "", s2);
2495 printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
2497 printf(" %*s: %s\n", maxlen, "Where", i->where);
2499 printf(" %*s: %s\n", maxlen, "What", i->what);
2501 STRV_FOREACH(t, i->documentation)
2502 printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
2504 STRV_FOREACH_PAIR(t, t2, i->listen)
2505 printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
2508 printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
2510 LIST_FOREACH(exec, p, i->exec) {
2511 _cleanup_free_ char *argv = NULL;
2514 /* Only show exited processes here */
2518 argv = strv_join(p->argv, " ");
2519 printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
2521 good = is_clean_exit_lsb(p->code, p->status, NULL);
2523 on = ansi_highlight_red(true);
2524 off = ansi_highlight_red(false);
2528 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2530 if (p->code == CLD_EXITED) {
2533 printf("status=%i", p->status);
2535 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2540 printf("signal=%s", signal_to_string(p->status));
2542 printf(")%s\n", off);
2544 if (i->main_pid == p->pid &&
2545 i->start_timestamp == p->start_timestamp &&
2546 i->exit_timestamp == p->start_timestamp)
2547 /* Let's not show this twice */
2550 if (p->pid == i->control_pid)
2554 if (i->main_pid > 0 || i->control_pid > 0) {
2555 if (i->main_pid > 0) {
2556 printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
2559 _cleanup_free_ char *comm = NULL;
2560 get_process_comm(i->main_pid, &comm);
2562 printf(" (%s)", comm);
2563 } else if (i->exit_code > 0) {
2564 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2566 if (i->exit_code == CLD_EXITED) {
2569 printf("status=%i", i->exit_status);
2571 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2576 printf("signal=%s", signal_to_string(i->exit_status));
2580 if (i->control_pid > 0)
2584 if (i->control_pid > 0) {
2585 _cleanup_free_ char *c = NULL;
2587 printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
2589 get_process_comm(i->control_pid, &c);
2598 printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
2600 if (i->default_control_group &&
2601 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2604 printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
2606 if (arg_transport != TRANSPORT_SSH) {
2609 char prefix[maxlen + 4];
2610 memset(prefix, ' ', sizeof(prefix) - 1);
2611 prefix[sizeof(prefix) - 1] = '\0';
2614 if (c > sizeof(prefix) - 1)
2615 c -= sizeof(prefix) - 1;
2619 if (i->main_pid > 0)
2620 extra[k++] = i->main_pid;
2622 if (i->control_pid > 0)
2623 extra[k++] = i->control_pid;
2625 show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
2626 c, false, extra, k, flags);
2630 if (i->id && arg_transport != TRANSPORT_SSH) {
2632 show_journal_by_unit(stdout,
2636 i->inactive_exit_timestamp_monotonic,
2640 arg_scope == UNIT_FILE_SYSTEM);
2643 if (i->need_daemon_reload)
2644 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2645 ansi_highlight_red(true),
2646 ansi_highlight_red(false),
2647 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2650 static void show_unit_help(UnitStatusInfo *i) {
2655 if (!i->documentation) {
2656 log_info("Documentation for %s not known.", i->id);
2660 STRV_FOREACH(p, i->documentation) {
2662 if (startswith(*p, "man:")) {
2665 char _cleanup_free_ *page = NULL, *section = NULL;
2666 const char *args[4] = { "man", NULL, NULL, NULL };
2671 if ((*p)[k-1] == ')')
2672 e = strrchr(*p, '(');
2675 page = strndup((*p) + 4, e - *p - 4);
2676 section = strndup(e + 1, *p + k - e - 2);
2677 if (!page || !section) {
2689 log_error("Failed to fork: %m");
2695 execvp(args[0], (char**) args);
2696 log_error("Failed to execute man: %m");
2697 _exit(EXIT_FAILURE);
2700 wait_for_terminate(pid, NULL);
2702 log_info("Can't show: %s", *p);
2706 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2712 switch (dbus_message_iter_get_arg_type(iter)) {
2714 case DBUS_TYPE_STRING: {
2717 dbus_message_iter_get_basic(iter, &s);
2720 if (streq(name, "Id"))
2722 else if (streq(name, "LoadState"))
2724 else if (streq(name, "ActiveState"))
2725 i->active_state = s;
2726 else if (streq(name, "SubState"))
2728 else if (streq(name, "Description"))
2730 else if (streq(name, "FragmentPath"))
2731 i->fragment_path = s;
2732 else if (streq(name, "SourcePath"))
2734 else if (streq(name, "DefaultControlGroup"))
2735 i->default_control_group = s;
2736 else if (streq(name, "StatusText"))
2738 else if (streq(name, "SysFSPath"))
2740 else if (streq(name, "Where"))
2742 else if (streq(name, "What"))
2744 else if (streq(name, "Following"))
2746 else if (streq(name, "UnitFileState"))
2747 i->unit_file_state = s;
2748 else if (streq(name, "Result"))
2755 case DBUS_TYPE_BOOLEAN: {
2758 dbus_message_iter_get_basic(iter, &b);
2760 if (streq(name, "Accept"))
2762 else if (streq(name, "NeedDaemonReload"))
2763 i->need_daemon_reload = b;
2764 else if (streq(name, "ConditionResult"))
2765 i->condition_result = b;
2770 case DBUS_TYPE_UINT32: {
2773 dbus_message_iter_get_basic(iter, &u);
2775 if (streq(name, "MainPID")) {
2777 i->main_pid = (pid_t) u;
2780 } else if (streq(name, "ControlPID"))
2781 i->control_pid = (pid_t) u;
2782 else if (streq(name, "ExecMainPID")) {
2784 i->main_pid = (pid_t) u;
2785 } else if (streq(name, "NAccepted"))
2787 else if (streq(name, "NConnections"))
2788 i->n_connections = u;
2793 case DBUS_TYPE_INT32: {
2796 dbus_message_iter_get_basic(iter, &j);
2798 if (streq(name, "ExecMainCode"))
2799 i->exit_code = (int) j;
2800 else if (streq(name, "ExecMainStatus"))
2801 i->exit_status = (int) j;
2806 case DBUS_TYPE_UINT64: {
2809 dbus_message_iter_get_basic(iter, &u);
2811 if (streq(name, "ExecMainStartTimestamp"))
2812 i->start_timestamp = (usec_t) u;
2813 else if (streq(name, "ExecMainExitTimestamp"))
2814 i->exit_timestamp = (usec_t) u;
2815 else if (streq(name, "ActiveEnterTimestamp"))
2816 i->active_enter_timestamp = (usec_t) u;
2817 else if (streq(name, "InactiveEnterTimestamp"))
2818 i->inactive_enter_timestamp = (usec_t) u;
2819 else if (streq(name, "InactiveExitTimestamp"))
2820 i->inactive_exit_timestamp = (usec_t) u;
2821 else if (streq(name, "InactiveExitTimestampMonotonic"))
2822 i->inactive_exit_timestamp_monotonic = (usec_t) u;
2823 else if (streq(name, "ActiveExitTimestamp"))
2824 i->active_exit_timestamp = (usec_t) u;
2825 else if (streq(name, "ConditionTimestamp"))
2826 i->condition_timestamp = (usec_t) u;
2831 case DBUS_TYPE_ARRAY: {
2833 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2834 startswith(name, "Exec")) {
2835 DBusMessageIter sub;
2837 dbus_message_iter_recurse(iter, &sub);
2838 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2839 ExecStatusInfo *info;
2842 if (!(info = new0(ExecStatusInfo, 1)))
2845 if (!(info->name = strdup(name))) {
2850 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2855 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2857 dbus_message_iter_next(&sub);
2860 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2861 DBusMessageIter sub, sub2;
2863 dbus_message_iter_recurse(iter, &sub);
2864 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2865 const char *type, *path;
2867 dbus_message_iter_recurse(&sub, &sub2);
2869 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2870 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
2873 r = strv_extend(&i->listen, type);
2876 r = strv_extend(&i->listen, path);
2881 dbus_message_iter_next(&sub);
2886 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
2887 int r = bus_parse_strv_iter(iter, &i->dropin_paths);
2891 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2892 streq(name, "Documentation")) {
2894 DBusMessageIter sub;
2896 dbus_message_iter_recurse(iter, &sub);
2897 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2901 dbus_message_iter_get_basic(&sub, &s);
2903 r = strv_extend(&i->documentation, s);
2907 dbus_message_iter_next(&sub);
2914 case DBUS_TYPE_STRUCT: {
2916 if (streq(name, "LoadError")) {
2917 DBusMessageIter sub;
2918 const char *n, *message;
2921 dbus_message_iter_recurse(iter, &sub);
2923 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2927 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2931 if (!isempty(message))
2932 i->load_error = message;
2942 static int print_property(const char *name, DBusMessageIter *iter) {
2946 /* This is a low-level property printer, see
2947 * print_status_info() for the nicer output */
2949 if (arg_properties && !strv_find(arg_properties, name))
2952 switch (dbus_message_iter_get_arg_type(iter)) {
2954 case DBUS_TYPE_STRUCT: {
2955 DBusMessageIter sub;
2956 dbus_message_iter_recurse(iter, &sub);
2958 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2961 dbus_message_iter_get_basic(&sub, &u);
2964 printf("%s=%u\n", name, (unsigned) u);
2966 printf("%s=\n", name);
2969 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2972 dbus_message_iter_get_basic(&sub, &s);
2974 if (arg_all || s[0])
2975 printf("%s=%s\n", name, s);
2978 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2979 const char *a = NULL, *b = NULL;
2981 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2982 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2984 if (arg_all || !isempty(a) || !isempty(b))
2985 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2993 case DBUS_TYPE_ARRAY:
2995 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2996 DBusMessageIter sub, sub2;
2998 dbus_message_iter_recurse(iter, &sub);
2999 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3003 dbus_message_iter_recurse(&sub, &sub2);
3005 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3006 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
3007 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
3009 dbus_message_iter_next(&sub);
3014 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
3015 DBusMessageIter sub, sub2;
3017 dbus_message_iter_recurse(iter, &sub);
3019 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3020 const char *type, *path;
3022 dbus_message_iter_recurse(&sub, &sub2);
3024 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3025 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3026 printf("%s=%s\n", type, path);
3028 dbus_message_iter_next(&sub);
3033 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3034 DBusMessageIter sub, sub2;
3036 dbus_message_iter_recurse(iter, &sub);
3037 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3038 const char *type, *path;
3040 dbus_message_iter_recurse(&sub, &sub2);
3042 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3043 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3044 printf("Listen%s=%s\n", type, path);
3046 dbus_message_iter_next(&sub);
3051 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
3052 DBusMessageIter sub, sub2;
3054 dbus_message_iter_recurse(iter, &sub);
3055 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3057 uint64_t value, next_elapse;
3059 dbus_message_iter_recurse(&sub, &sub2);
3061 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
3062 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
3063 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
3064 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
3066 printf("%s={ value=%s ; next_elapse=%s }\n",
3068 format_timespan(timespan1, sizeof(timespan1), value, 0),
3069 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
3072 dbus_message_iter_next(&sub);