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>
46 #include "utmp-wtmp.h"
49 #include "path-util.h"
51 #include "dbus-common.h"
52 #include "cgroup-show.h"
53 #include "cgroup-util.h"
55 #include "path-lookup.h"
56 #include "conf-parser.h"
57 #include "exit-status.h"
58 #include "bus-errors.h"
60 #include "unit-name.h"
62 #include "spawn-ask-password-agent.h"
63 #include "spawn-polkit-agent.h"
65 #include "logs-show.h"
66 #include "path-util.h"
67 #include "socket-util.h"
69 static const char *arg_type = NULL;
70 static const char *arg_load_state = NULL;
71 static char **arg_property = NULL;
72 static bool arg_all = false;
73 static const char *arg_job_mode = "replace";
74 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
75 static bool arg_no_block = false;
76 static bool arg_no_legend = false;
77 static bool arg_no_pager = false;
78 static bool arg_no_wtmp = false;
79 static bool arg_no_wall = false;
80 static bool arg_no_reload = false;
81 static bool arg_ignore_inhibitors = false;
82 static bool arg_dry = false;
83 static bool arg_quiet = false;
84 static bool arg_full = false;
85 static int arg_force = 0;
86 static bool arg_ask_password = true;
87 static bool arg_failed = false;
88 static bool arg_runtime = false;
89 static char **arg_wall = NULL;
90 static const char *arg_kill_who = NULL;
91 static int arg_signal = SIGTERM;
92 static const char *arg_root = NULL;
93 static usec_t arg_when = 0;
115 ACTION_CANCEL_SHUTDOWN,
117 } arg_action = ACTION_SYSTEMCTL;
123 static enum transport {
127 } arg_transport = TRANSPORT_NORMAL;
128 static const char *arg_host = NULL;
129 static unsigned arg_lines = 10;
130 static OutputMode arg_output = OUTPUT_SHORT;
132 static bool private_bus = false;
134 static int daemon_reload(DBusConnection *bus, char **args);
135 static void halt_now(enum action a);
137 static void pager_open_if_enabled(void) {
145 static void ask_password_agent_open_if_enabled(void) {
147 /* Open the password agent as a child process if necessary */
149 if (!arg_ask_password)
152 if (arg_scope != UNIT_FILE_SYSTEM)
155 ask_password_agent_open();
159 static void polkit_agent_open_if_enabled(void) {
161 /* Open the polkit agent as a child process if necessary */
163 if (!arg_ask_password)
166 if (arg_scope != UNIT_FILE_SYSTEM)
173 static const char *ansi_highlight(bool b) {
178 return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
181 static const char *ansi_highlight_red(bool b) {
186 return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
189 static const char *ansi_highlight_green(bool b) {
194 return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
197 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
200 if (!dbus_error_is_set(error))
203 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
204 dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
205 dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
206 dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
207 return EXIT_NOPERMISSION;
209 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
210 return EXIT_NOTINSTALLED;
212 if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
213 dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
214 return EXIT_NOTIMPLEMENTED;
216 if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
217 return EXIT_NOTCONFIGURED;
225 static void warn_wall(enum action a) {
226 static const char *table[_ACTION_MAX] = {
227 [ACTION_HALT] = "The system is going down for system halt NOW!",
228 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
229 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
230 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
231 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
232 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
233 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
242 p = strv_join(arg_wall, " ");
244 log_error("Failed to join strings.");
260 utmp_wall(table[a], NULL);
263 static bool avoid_bus(void) {
265 if (running_in_chroot() > 0)
268 if (sd_booted() <= 0)
271 if (!isempty(arg_root))
274 if (arg_scope == UNIT_FILE_GLOBAL)
282 const char *description;
283 const char *load_state;
284 const char *active_state;
285 const char *sub_state;
286 const char *following;
287 const char *unit_path;
289 const char *job_type;
290 const char *job_path;
293 static int compare_unit_info(const void *a, const void *b) {
295 const struct unit_info *u = a, *v = b;
297 d1 = strrchr(u->id, '.');
298 d2 = strrchr(v->id, '.');
303 if ((r = strcasecmp(d1, d2)) != 0)
307 return strcasecmp(u->id, v->id);
310 static bool output_show_unit(const struct unit_info *u) {
314 return streq(u->active_state, "failed");
316 return (!arg_type || ((dot = strrchr(u->id, '.')) &&
317 streq(dot+1, arg_type))) &&
318 (!arg_load_state || streq(u->load_state, arg_load_state)) &&
319 (arg_all || !(streq(u->active_state, "inactive")
320 || u->following[0]) || u->job_id > 0);
323 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
324 unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
325 const struct unit_info *u;
328 max_id_len = sizeof("UNIT")-1;
329 active_len = sizeof("ACTIVE")-1;
330 sub_len = sizeof("SUB")-1;
331 job_len = sizeof("JOB")-1;
334 for (u = unit_infos; u < unit_infos + c; u++) {
335 if (!output_show_unit(u))
338 max_id_len = MAX(max_id_len, strlen(u->id));
339 active_len = MAX(active_len, strlen(u->active_state));
340 sub_len = MAX(sub_len, strlen(u->sub_state));
341 if (u->job_id != 0) {
342 job_len = MAX(job_len, strlen(u->job_type));
349 id_len = MIN(max_id_len, 25);
350 basic_len = 5 + id_len + 5 + active_len + sub_len;
352 basic_len += job_len + 1;
353 if (basic_len < (unsigned) columns()) {
354 unsigned extra_len, incr;
355 extra_len = columns() - basic_len;
356 /* Either UNIT already got 25, or is fully satisfied.
357 * Grant up to 25 to DESC now. */
358 incr = MIN(extra_len, 25);
361 /* split the remaining space between UNIT and DESC,
362 * but do not give UNIT more than it needs. */
364 incr = MIN(extra_len / 2, max_id_len - id_len);
366 desc_len += extra_len - incr;
372 for (u = unit_infos; u < unit_infos + c; u++) {
374 const char *on_loaded, *off_loaded;
375 const char *on_active, *off_active;
377 if (!output_show_unit(u))
380 if (!n_shown && !arg_no_legend) {
381 printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
382 active_len, "ACTIVE", sub_len, "SUB");
384 printf("%-*s ", job_len, "JOB");
385 if (!arg_full && arg_no_pager)
386 printf("%.*s\n", desc_len, "DESCRIPTION");
388 printf("%s\n", "DESCRIPTION");
393 if (streq(u->load_state, "error")) {
394 on_loaded = ansi_highlight_red(true);
395 off_loaded = ansi_highlight_red(false);
397 on_loaded = off_loaded = "";
399 if (streq(u->active_state, "failed")) {
400 on_active = ansi_highlight_red(true);
401 off_active = ansi_highlight_red(false);
403 on_active = off_active = "";
405 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
407 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s",
408 id_len, e ? e : u->id,
409 on_loaded, u->load_state, off_loaded,
410 on_active, active_len, u->active_state,
411 sub_len, u->sub_state, off_active,
412 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
413 if (!arg_full && arg_no_pager)
414 printf("%.*s\n", desc_len, u->description);
416 printf("%s\n", u->description);
421 if (!arg_no_legend) {
422 const char *on, *off;
425 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
426 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
427 "SUB = The low-level unit activation state, values depend on unit type.\n");
429 printf("JOB = Pending job for the unit.\n");
431 on = ansi_highlight(true);
432 off = ansi_highlight(false);
434 on = ansi_highlight_red(true);
435 off = ansi_highlight_red(false);
439 printf("%s%u loaded units listed.%s\n"
440 "To show all installed unit files use 'systemctl list-unit-files'.\n",
443 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
444 "To show all installed unit files use 'systemctl list-unit-files'.\n",
449 static int list_units(DBusConnection *bus, char **args) {
450 DBusMessage *reply = NULL;
452 DBusMessageIter iter, sub, sub2;
453 unsigned c = 0, n_units = 0;
454 struct unit_info *unit_infos = NULL;
456 pager_open_if_enabled();
458 r = bus_method_call_with_reply (
460 "org.freedesktop.systemd1",
461 "/org/freedesktop/systemd1",
462 "org.freedesktop.systemd1.Manager",
470 if (!dbus_message_iter_init(reply, &iter) ||
471 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
472 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
473 log_error("Failed to parse reply.");
478 dbus_message_iter_recurse(&iter, &sub);
480 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
483 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
484 log_error("Failed to parse reply.");
492 n_units = MAX(2*c, 16);
493 w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
496 log_error("Failed to allocate unit array.");
506 dbus_message_iter_recurse(&sub, &sub2);
508 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
509 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
510 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
511 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
512 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
513 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
514 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
515 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
516 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
517 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
518 log_error("Failed to parse reply.");
523 dbus_message_iter_next(&sub);
528 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
529 output_units_list(unit_infos, c);
534 dbus_message_unref(reply);
541 static int compare_unit_file_list(const void *a, const void *b) {
543 const UnitFileList *u = a, *v = b;
545 d1 = strrchr(u->path, '.');
546 d2 = strrchr(v->path, '.');
551 r = strcasecmp(d1, d2);
556 return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
559 static bool output_show_unit_file(const UnitFileList *u) {
562 return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
565 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
566 unsigned max_id_len, id_cols, state_cols, n_shown = 0;
567 const UnitFileList *u;
569 max_id_len = sizeof("UNIT FILE")-1;
570 state_cols = sizeof("STATE")-1;
571 for (u = units; u < units + c; u++) {
572 if (!output_show_unit_file(u))
575 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
576 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
581 id_cols = MIN(max_id_len, 25);
582 basic_cols = 1 + id_cols + state_cols;
583 if (basic_cols < (unsigned) columns())
584 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
586 id_cols = max_id_len;
589 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
591 for (u = units; u < units + c; u++) {
593 const char *on, *off;
596 if (!output_show_unit_file(u))
601 if (u->state == UNIT_FILE_MASKED ||
602 u->state == UNIT_FILE_MASKED_RUNTIME ||
603 u->state == UNIT_FILE_DISABLED ||
604 u->state == UNIT_FILE_INVALID) {
605 on = ansi_highlight_red(true);
606 off = ansi_highlight_red(false);
607 } else if (u->state == UNIT_FILE_ENABLED) {
608 on = ansi_highlight_green(true);
609 off = ansi_highlight_green(false);
613 id = path_get_file_name(u->path);
615 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
617 printf("%-*s %s%-*s%s\n",
619 on, state_cols, unit_file_state_to_string(u->state), off);
625 printf("\n%u unit files listed.\n", n_shown);
628 static int list_unit_files(DBusConnection *bus, char **args) {
629 DBusMessage *reply = NULL;
631 DBusMessageIter iter, sub, sub2;
632 unsigned c = 0, n_units = 0;
633 UnitFileList *units = NULL;
635 pager_open_if_enabled();
642 h = hashmap_new(string_hash_func, string_compare_func);
646 r = unit_file_get_list(arg_scope, arg_root, h);
648 unit_file_list_free(h);
649 log_error("Failed to get unit file list: %s", strerror(-r));
653 n_units = hashmap_size(h);
654 units = new(UnitFileList, n_units);
656 unit_file_list_free(h);
660 HASHMAP_FOREACH(u, h, i) {
661 memcpy(units + c++, u, sizeof(UnitFileList));
667 r = bus_method_call_with_reply (
669 "org.freedesktop.systemd1",
670 "/org/freedesktop/systemd1",
671 "org.freedesktop.systemd1.Manager",
679 if (!dbus_message_iter_init(reply, &iter) ||
680 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
681 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
682 log_error("Failed to parse reply.");
687 dbus_message_iter_recurse(&iter, &sub);
689 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
693 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
694 log_error("Failed to parse reply.");
702 n_units = MAX(2*c, 16);
703 w = realloc(units, sizeof(struct UnitFileList) * n_units);
706 log_error("Failed to allocate unit array.");
716 dbus_message_iter_recurse(&sub, &sub2);
718 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
719 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
720 log_error("Failed to parse reply.");
725 u->state = unit_file_state_from_string(state);
727 dbus_message_iter_next(&sub);
733 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
734 output_unit_file_list(units, c);
741 dbus_message_unref(reply);
748 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
749 static const char * const colors[] = {
750 "Requires", "[color=\"black\"]",
751 "RequiresOverridable", "[color=\"black\"]",
752 "Requisite", "[color=\"darkblue\"]",
753 "RequisiteOverridable", "[color=\"darkblue\"]",
754 "Wants", "[color=\"grey66\"]",
755 "Conflicts", "[color=\"red\"]",
756 "ConflictedBy", "[color=\"red\"]",
757 "After", "[color=\"green\"]"
760 const char *c = NULL;
767 for (i = 0; i < ELEMENTSOF(colors); i += 2)
768 if (streq(colors[i], prop)) {
776 if (arg_dot != DOT_ALL)
777 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
780 switch (dbus_message_iter_get_arg_type(iter)) {
782 case DBUS_TYPE_ARRAY:
784 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
787 dbus_message_iter_recurse(iter, &sub);
789 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
792 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
793 dbus_message_iter_get_basic(&sub, &s);
794 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
796 dbus_message_iter_next(&sub);
806 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
807 DBusMessage *reply = NULL;
808 const char *interface = "org.freedesktop.systemd1.Unit";
810 DBusMessageIter iter, sub, sub2, sub3;
814 r = bus_method_call_with_reply (
816 "org.freedesktop.systemd1",
818 "org.freedesktop.DBus.Properties",
822 DBUS_TYPE_STRING, &interface,
827 if (!dbus_message_iter_init(reply, &iter) ||
828 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
829 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
830 log_error("Failed to parse reply.");
835 dbus_message_iter_recurse(&iter, &sub);
837 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
840 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
841 log_error("Failed to parse reply.");
846 dbus_message_iter_recurse(&sub, &sub2);
848 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
849 log_error("Failed to parse reply.");
854 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
855 log_error("Failed to parse reply.");
860 dbus_message_iter_recurse(&sub2, &sub3);
862 if (dot_one_property(name, prop, &sub3)) {
863 log_error("Failed to parse reply.");
868 dbus_message_iter_next(&sub);
873 dbus_message_unref(reply);
878 static int dot(DBusConnection *bus, char **args) {
879 DBusMessage *reply = NULL;
881 DBusMessageIter iter, sub, sub2;
883 r = bus_method_call_with_reply (
885 "org.freedesktop.systemd1",
886 "/org/freedesktop/systemd1",
887 "org.freedesktop.systemd1.Manager",
895 if (!dbus_message_iter_init(reply, &iter) ||
896 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
897 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
898 log_error("Failed to parse reply.");
903 printf("digraph systemd {\n");
905 dbus_message_iter_recurse(&iter, &sub);
906 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
907 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
909 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
910 log_error("Failed to parse reply.");
915 dbus_message_iter_recurse(&sub, &sub2);
917 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
918 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
919 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
920 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
921 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
922 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
923 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
924 log_error("Failed to parse reply.");
929 if ((r = dot_one(bus, id, unit_path)) < 0)
932 /* printf("\t\"%s\";\n", id); */
933 dbus_message_iter_next(&sub);
938 log_info(" Color legend: black = Requires\n"
939 " dark blue = Requisite\n"
940 " dark grey = Wants\n"
945 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
946 "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
952 dbus_message_unref(reply);
957 static int list_jobs(DBusConnection *bus, char **args) {
958 DBusMessage *reply = NULL;
960 DBusMessageIter iter, sub, sub2;
963 pager_open_if_enabled();
965 r = bus_method_call_with_reply (
967 "org.freedesktop.systemd1",
968 "/org/freedesktop/systemd1",
969 "org.freedesktop.systemd1.Manager",
977 if (!dbus_message_iter_init(reply, &iter) ||
978 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
979 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
980 log_error("Failed to parse reply.");
985 dbus_message_iter_recurse(&iter, &sub);
988 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
990 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
991 const char *name, *type, *state, *job_path, *unit_path;
995 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
996 log_error("Failed to parse reply.");
1001 dbus_message_iter_recurse(&sub, &sub2);
1003 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1004 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1005 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1006 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1007 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1008 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1009 log_error("Failed to parse reply.");
1014 e = arg_full ? NULL : ellipsize(name, 25, 33);
1015 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1020 dbus_message_iter_next(&sub);
1024 printf("\n%u jobs listed.\n", k);
1030 dbus_message_unref(reply);
1035 static int load_unit(DBusConnection *bus, char **args) {
1040 STRV_FOREACH(name, args+1) {
1041 _cleanup_free_ char *n = NULL;
1044 n = unit_name_mangle(*name);
1045 r = bus_method_call_with_reply (
1047 "org.freedesktop.systemd1",
1048 "/org/freedesktop/systemd1",
1049 "org.freedesktop.systemd1.Manager",
1053 DBUS_TYPE_STRING, n ? &n : name,
1062 static int cancel_job(DBusConnection *bus, char **args) {
1067 if (strv_length(args) <= 1)
1068 return daemon_reload(bus, args);
1070 STRV_FOREACH(name, args+1) {
1074 r = safe_atou32(*name, &id);
1076 log_error("Failed to parse job id: %s", strerror(-r));
1080 r = bus_method_call_with_reply(
1082 "org.freedesktop.systemd1",
1083 "/org/freedesktop/systemd1",
1084 "org.freedesktop.systemd1.Manager",
1088 DBUS_TYPE_UINT32, &id,
1097 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1098 DBusMessage *reply = NULL;
1099 dbus_bool_t b = FALSE;
1100 DBusMessageIter iter, sub;
1102 *interface = "org.freedesktop.systemd1.Unit",
1103 *property = "NeedDaemonReload",
1108 /* We ignore all errors here, since this is used to show a warning only */
1110 n = unit_name_mangle(unit);
1111 r = bus_method_call_with_reply (
1113 "org.freedesktop.systemd1",
1114 "/org/freedesktop/systemd1",
1115 "org.freedesktop.systemd1.Manager",
1119 DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
1125 if (!dbus_message_get_args(reply, NULL,
1126 DBUS_TYPE_OBJECT_PATH, &path,
1130 dbus_message_unref(reply);
1131 r = bus_method_call_with_reply (
1133 "org.freedesktop.systemd1",
1135 "org.freedesktop.DBus.Properties",
1139 DBUS_TYPE_STRING, &interface,
1140 DBUS_TYPE_STRING, &property,
1145 if (!dbus_message_iter_init(reply, &iter) ||
1146 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1149 dbus_message_iter_recurse(&iter, &sub);
1151 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1154 dbus_message_iter_get_basic(&sub, &b);
1158 dbus_message_unref(reply);
1163 typedef struct WaitData {
1170 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1178 dbus_error_init(&error);
1180 log_debug("Got D-Bus request: %s.%s() on %s",
1181 dbus_message_get_interface(message),
1182 dbus_message_get_member(message),
1183 dbus_message_get_path(message));
1185 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1186 log_error("Warning! D-Bus connection terminated.");
1187 dbus_connection_close(connection);
1189 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1191 const char *path, *result, *unit;
1192 dbus_bool_t success = true;
1194 if (dbus_message_get_args(message, &error,
1195 DBUS_TYPE_UINT32, &id,
1196 DBUS_TYPE_OBJECT_PATH, &path,
1197 DBUS_TYPE_STRING, &unit,
1198 DBUS_TYPE_STRING, &result,
1199 DBUS_TYPE_INVALID)) {
1202 p = set_remove(d->set, (char*) path);
1205 if (!isempty(result))
1206 d->result = strdup(result);
1209 d->name = strdup(unit);
1214 dbus_error_free(&error);
1215 if (dbus_message_get_args(message, &error,
1216 DBUS_TYPE_UINT32, &id,
1217 DBUS_TYPE_OBJECT_PATH, &path,
1218 DBUS_TYPE_STRING, &result,
1219 DBUS_TYPE_INVALID)) {
1222 /* Compatibility with older systemd versions <
1223 * 183 during upgrades. This should be dropped
1225 p = set_remove(d->set, (char*) path);
1229 d->result = strdup(result);
1234 dbus_error_free(&error);
1235 if (dbus_message_get_args(message, &error,
1236 DBUS_TYPE_UINT32, &id,
1237 DBUS_TYPE_OBJECT_PATH, &path,
1238 DBUS_TYPE_BOOLEAN, &success,
1239 DBUS_TYPE_INVALID)) {
1242 /* Compatibility with older systemd versions <
1243 * 19 during upgrades. This should be dropped
1246 p = set_remove(d->set, (char*) path);
1250 d->result = strdup("failed");
1256 log_error("Failed to parse message: %s", bus_error_message(&error));
1260 dbus_error_free(&error);
1261 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1264 static int enable_wait_for_jobs(DBusConnection *bus) {
1272 dbus_error_init(&error);
1273 dbus_bus_add_match(bus,
1275 "sender='org.freedesktop.systemd1',"
1276 "interface='org.freedesktop.systemd1.Manager',"
1277 "member='JobRemoved',"
1278 "path='/org/freedesktop/systemd1'",
1281 if (dbus_error_is_set(&error)) {
1282 log_error("Failed to add match: %s", bus_error_message(&error));
1283 dbus_error_free(&error);
1287 /* This is slightly dirty, since we don't undo the match registrations. */
1291 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1301 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1304 while (!set_isempty(s)) {
1306 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1307 log_error("Disconnected from bus.");
1308 return -ECONNREFUSED;
1315 if (streq(d.result, "timeout"))
1316 log_error("Job for %s timed out.", strna(d.name));
1317 else if (streq(d.result, "canceled"))
1318 log_error("Job for %s canceled.", strna(d.name));
1319 else if (streq(d.result, "dependency"))
1320 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1321 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1322 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1325 if (streq_ptr(d.result, "timeout"))
1327 else if (streq_ptr(d.result, "canceled"))
1329 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1340 dbus_connection_remove_filter(bus, wait_filter, &d);
1344 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1345 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1346 DBusMessageIter iter, sub;
1348 *interface = "org.freedesktop.systemd1.Unit",
1349 *property = "ActiveState";
1350 const char *state, *path;
1351 _cleanup_free_ char *n = NULL;
1357 dbus_error_init(&error);
1359 n = unit_name_mangle(name);
1363 r = bus_method_call_with_reply (
1365 "org.freedesktop.systemd1",
1366 "/org/freedesktop/systemd1",
1367 "org.freedesktop.systemd1.Manager",
1371 DBUS_TYPE_STRING, &n,
1374 dbus_error_free(&error);
1381 if (!dbus_message_get_args(reply, NULL,
1382 DBUS_TYPE_OBJECT_PATH, &path,
1383 DBUS_TYPE_INVALID)) {
1384 log_error("Failed to parse reply.");
1388 dbus_message_unref(reply);
1391 r = bus_method_call_with_reply(
1393 "org.freedesktop.systemd1",
1395 "org.freedesktop.DBus.Properties",
1399 DBUS_TYPE_STRING, &interface,
1400 DBUS_TYPE_STRING, &property,
1408 if (!dbus_message_iter_init(reply, &iter) ||
1409 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1410 log_error("Failed to parse reply.");
1414 dbus_message_iter_recurse(&iter, &sub);
1416 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1417 log_error("Failed to parse reply.");
1421 dbus_message_iter_get_basic(&sub, &state);
1426 return strv_find(check_states, state) ? 1 : 0;
1429 static void check_triggering_units(
1430 DBusConnection *bus,
1431 const char *unit_name) {
1433 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1434 DBusMessageIter iter, sub;
1435 const char *interface = "org.freedesktop.systemd1.Unit",
1436 *triggered_by_property = "TriggeredBy";
1438 char _cleanup_free_ *unit_path = NULL, *n = NULL;
1439 bool print_warning_label = true;
1442 n = unit_name_mangle(unit_name);
1448 unit_path = unit_dbus_path_from_name(n);
1454 r = bus_method_call_with_reply(
1456 "org.freedesktop.systemd1",
1458 "org.freedesktop.DBus.Properties",
1462 DBUS_TYPE_STRING, &interface,
1463 DBUS_TYPE_STRING, &triggered_by_property,
1468 if (!dbus_message_iter_init(reply, &iter) ||
1469 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1470 log_error("Failed to parse reply.");
1474 dbus_message_iter_recurse(&iter, &sub);
1475 dbus_message_iter_recurse(&sub, &iter);
1478 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1479 const char * const check_states[] = {
1484 const char *service_trigger;
1486 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1487 log_error("Failed to parse reply.");
1491 dbus_message_iter_get_basic(&sub, &service_trigger);
1493 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1497 if (print_warning_label) {
1498 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1499 print_warning_label = false;
1502 log_warning(" %s", service_trigger);
1505 dbus_message_iter_next(&sub);
1509 static int start_unit_one(
1510 DBusConnection *bus,
1517 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1520 _cleanup_free_ char *n, *p = NULL;
1527 n = unit_name_mangle(name);
1531 r = bus_method_call_with_reply(
1533 "org.freedesktop.systemd1",
1534 "/org/freedesktop/systemd1",
1535 "org.freedesktop.systemd1.Manager",
1539 DBUS_TYPE_STRING, &n,
1540 DBUS_TYPE_STRING, &mode,
1543 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1544 /* There's always a fallback possible for
1545 * legacy actions. */
1548 log_error("Failed to issue method call: %s", bus_error_message(error));
1553 if (!dbus_message_get_args(reply, error,
1554 DBUS_TYPE_OBJECT_PATH, &path,
1555 DBUS_TYPE_INVALID)) {
1556 log_error("Failed to parse reply: %s", bus_error_message(error));
1560 if (need_daemon_reload(bus, n))
1561 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1562 n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1571 log_error("Failed to add path to set.");
1581 static enum action verb_to_action(const char *verb) {
1582 if (streq(verb, "halt"))
1584 else if (streq(verb, "poweroff"))
1585 return ACTION_POWEROFF;
1586 else if (streq(verb, "reboot"))
1587 return ACTION_REBOOT;
1588 else if (streq(verb, "kexec"))
1589 return ACTION_KEXEC;
1590 else if (streq(verb, "rescue"))
1591 return ACTION_RESCUE;
1592 else if (streq(verb, "emergency"))
1593 return ACTION_EMERGENCY;
1594 else if (streq(verb, "default"))
1595 return ACTION_DEFAULT;
1596 else if (streq(verb, "exit"))
1598 else if (streq(verb, "suspend"))
1599 return ACTION_SUSPEND;
1600 else if (streq(verb, "hibernate"))
1601 return ACTION_HIBERNATE;
1602 else if (streq(verb, "hybrid-sleep"))
1603 return ACTION_HYBRID_SLEEP;
1605 return ACTION_INVALID;
1608 static int start_unit(DBusConnection *bus, char **args) {
1610 static const char * const table[_ACTION_MAX] = {
1611 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1612 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1613 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1614 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1615 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1616 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1617 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1618 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1619 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1620 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1621 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1622 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1623 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1624 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
1625 [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
1629 const char *method, *mode, *one_name;
1634 dbus_error_init(&error);
1638 ask_password_agent_open_if_enabled();
1640 if (arg_action == ACTION_SYSTEMCTL) {
1642 streq(args[0], "stop") ||
1643 streq(args[0], "condstop") ? "StopUnit" :
1644 streq(args[0], "reload") ? "ReloadUnit" :
1645 streq(args[0], "restart") ? "RestartUnit" :
1647 streq(args[0], "try-restart") ||
1648 streq(args[0], "condrestart") ? "TryRestartUnit" :
1650 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1652 streq(args[0], "reload-or-try-restart") ||
1653 streq(args[0], "condreload") ||
1655 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1659 (streq(args[0], "isolate") ||
1660 streq(args[0], "rescue") ||
1661 streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1663 one_name = table[verb_to_action(args[0])];
1666 assert(arg_action < ELEMENTSOF(table));
1667 assert(table[arg_action]);
1669 method = "StartUnit";
1671 mode = (arg_action == ACTION_EMERGENCY ||
1672 arg_action == ACTION_RESCUE ||
1673 arg_action == ACTION_RUNLEVEL2 ||
1674 arg_action == ACTION_RUNLEVEL3 ||
1675 arg_action == ACTION_RUNLEVEL4 ||
1676 arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1678 one_name = table[arg_action];
1681 if (!arg_no_block) {
1682 ret = enable_wait_for_jobs(bus);
1684 log_error("Could not watch jobs: %s", strerror(-ret));
1688 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);
1716 /* When stopping units, warn if they can still be triggered by
1717 * another active unit (socket, path, timer) */
1718 if (!arg_quiet && streq(method, "StopUnit")) {
1720 check_triggering_units(bus, one_name);
1722 STRV_FOREACH(name, args+1)
1723 check_triggering_units(bus, *name);
1729 dbus_error_free(&error);
1734 /* Ask systemd-logind, which might grant access to unprivileged users
1735 * through PolicyKit */
1736 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1739 dbus_bool_t interactive = true;
1744 polkit_agent_open_if_enabled();
1752 case ACTION_POWEROFF:
1753 method = "PowerOff";
1756 case ACTION_SUSPEND:
1760 case ACTION_HIBERNATE:
1761 method = "Hibernate";
1764 case ACTION_HYBRID_SLEEP:
1765 method = "HybridSleep";
1772 return bus_method_call_with_reply (
1774 "org.freedesktop.login1",
1775 "/org/freedesktop/login1",
1776 "org.freedesktop.login1.Manager",
1780 DBUS_TYPE_BOOLEAN, &interactive,
1787 static int check_inhibitors(DBusConnection *bus, enum action a) {
1789 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1790 DBusMessageIter iter, sub, sub2;
1797 if (arg_ignore_inhibitors || arg_force > 0)
1809 r = bus_method_call_with_reply(
1811 "org.freedesktop.login1",
1812 "/org/freedesktop/login1",
1813 "org.freedesktop.login1.Manager",
1819 /* If logind is not around, then there are no inhibitors... */
1822 if (!dbus_message_iter_init(reply, &iter) ||
1823 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1824 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1825 log_error("Failed to parse reply.");
1829 dbus_message_iter_recurse(&iter, &sub);
1830 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1831 const char *what, *who, *why, *mode;
1833 _cleanup_strv_free_ char **sv = NULL;
1834 _cleanup_free_ char *comm = NULL;
1836 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1837 log_error("Failed to parse reply.");
1841 dbus_message_iter_recurse(&sub, &sub2);
1843 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1844 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1845 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1846 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1847 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1848 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1849 log_error("Failed to parse reply.");
1853 if (!streq(mode, "block"))
1856 sv = strv_split(what, ":");
1860 if (!strv_contains(sv,
1862 a == ACTION_POWEROFF ||
1863 a == ACTION_REBOOT ||
1864 a == ACTION_KEXEC ? "shutdown" : "sleep"))
1867 get_process_comm(pid, &comm);
1868 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", UID %lu), reason is \"%s\".", who, (unsigned long) pid, strna(comm), (unsigned long) uid, why);
1872 dbus_message_iter_next(&sub);
1875 dbus_message_iter_recurse(&iter, &sub);
1880 log_error("Please try again after closing inhibitors or ignore them with 'systemctl %s -i'.",
1881 a == ACTION_HALT ? "halt" :
1882 a == ACTION_POWEROFF ? "poweroff" :
1883 a == ACTION_REBOOT ? "reboot" :
1884 a == ACTION_KEXEC ? "kexec" :
1885 a == ACTION_SUSPEND ? "suspend" :
1886 a == ACTION_HIBERNATE ? "hibernate" : "hybrid-sleep");
1894 static int start_special(DBusConnection *bus, char **args) {
1900 a = verb_to_action(args[0]);
1902 r = check_inhibitors(bus, a);
1906 if (arg_force >= 2 && geteuid() != 0) {
1907 log_error("Must be root.");
1911 if (arg_force >= 2 &&
1912 (a == ACTION_HALT ||
1913 a == ACTION_POWEROFF ||
1914 a == ACTION_REBOOT))
1917 if (arg_force >= 1 &&
1918 (a == ACTION_HALT ||
1919 a == ACTION_POWEROFF ||
1920 a == ACTION_REBOOT ||
1921 a == ACTION_KEXEC ||
1923 return daemon_reload(bus, args);
1925 /* first try logind, to allow authentication with polkit */
1926 if (geteuid() != 0 &&
1927 (a == ACTION_POWEROFF ||
1928 a == ACTION_REBOOT ||
1929 a == ACTION_SUSPEND ||
1930 a == ACTION_HIBERNATE ||
1931 a == ACTION_HYBRID_SLEEP)) {
1932 r = reboot_with_logind(bus, a);
1937 r = start_unit(bus, args);
1944 static int check_unit_active(DBusConnection *bus, char **args) {
1945 const char * const check_states[] = {
1952 int r = 3; /* According to LSB: "program is not running" */
1957 STRV_FOREACH(name, args+1) {
1960 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1970 static int check_unit_failed(DBusConnection *bus, char **args) {
1971 const char * const check_states[] = {
1982 STRV_FOREACH(name, args+1) {
1985 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1995 static int kill_unit(DBusConnection *bus, char **args) {
2003 arg_kill_who = "all";
2005 STRV_FOREACH(name, args+1) {
2006 _cleanup_free_ char *n = NULL;
2008 n = unit_name_mangle(*name);
2010 r = bus_method_call_with_reply(
2012 "org.freedesktop.systemd1",
2013 "/org/freedesktop/systemd1",
2014 "org.freedesktop.systemd1.Manager",
2018 DBUS_TYPE_STRING, n ? &n : name,
2019 DBUS_TYPE_STRING, &arg_kill_who,
2020 DBUS_TYPE_INT32, &arg_signal,
2028 static int set_cgroup(DBusConnection *bus, char **args) {
2029 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2032 DBusMessageIter iter;
2034 _cleanup_free_ char *n = NULL;
2039 dbus_error_init(&error);
2042 streq(args[0], "set-cgroup") ? "SetUnitControlGroups" :
2043 streq(args[0], "unset-group") ? "UnsetUnitControlGroups"
2044 : "UnsetUnitControlGroupAttributes";
2046 n = unit_name_mangle(args[1]);
2050 m = dbus_message_new_method_call(
2051 "org.freedesktop.systemd1",
2052 "/org/freedesktop/systemd1",
2053 "org.freedesktop.systemd1.Manager",
2058 dbus_message_iter_init_append(m, &iter);
2059 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2062 r = bus_append_strv_iter(&iter, args + 2);
2066 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2068 log_error("Failed to issue method call: %s", bus_error_message(&error));
2069 dbus_error_free(&error);
2076 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2077 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2079 DBusMessageIter iter, sub, sub2;
2082 _cleanup_free_ char *n = NULL;
2087 dbus_error_init(&error);
2089 if (strv_length(args) % 2 != 0) {
2090 log_error("Expecting an uneven number of arguments!");
2094 n = unit_name_mangle(args[1]);
2098 m = dbus_message_new_method_call(
2099 "org.freedesktop.systemd1",
2100 "/org/freedesktop/systemd1",
2101 "org.freedesktop.systemd1.Manager",
2102 "SetUnitControlGroupAttributes");
2106 dbus_message_iter_init_append(m, &iter);
2107 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2108 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub))
2111 STRV_FOREACH_PAIR(x, y, args + 2) {
2112 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2113 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) ||
2114 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) ||
2115 !dbus_message_iter_close_container(&sub, &sub2))
2119 if (!dbus_message_iter_close_container(&iter, &sub))
2122 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2124 log_error("Failed to issue method call: %s", bus_error_message(&error));
2125 dbus_error_free(&error);
2132 typedef struct ExecStatusInfo {
2140 usec_t start_timestamp;
2141 usec_t exit_timestamp;
2146 LIST_FIELDS(struct ExecStatusInfo, exec);
2149 static void exec_status_info_free(ExecStatusInfo *i) {
2158 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2159 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2160 DBusMessageIter sub2, sub3;
2164 int32_t code, status;
2170 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2173 dbus_message_iter_recurse(sub, &sub2);
2175 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2178 if (!(i->path = strdup(path)))
2181 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2182 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2186 dbus_message_iter_recurse(&sub2, &sub3);
2187 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2188 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2189 dbus_message_iter_next(&sub3);
2194 if (!(i->argv = new0(char*, n+1)))
2198 dbus_message_iter_recurse(&sub2, &sub3);
2199 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2202 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2203 dbus_message_iter_get_basic(&sub3, &s);
2204 dbus_message_iter_next(&sub3);
2206 if (!(i->argv[n++] = strdup(s)))
2210 if (!dbus_message_iter_next(&sub2) ||
2211 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2212 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2213 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2214 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2215 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2216 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2217 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2218 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2222 i->start_timestamp = (usec_t) start_timestamp;
2223 i->exit_timestamp = (usec_t) exit_timestamp;
2224 i->pid = (pid_t) pid;
2231 typedef struct UnitStatusInfo {
2233 const char *load_state;
2234 const char *active_state;
2235 const char *sub_state;
2236 const char *unit_file_state;
2238 const char *description;
2239 const char *following;
2241 char **documentation;
2243 const char *fragment_path;
2244 const char *source_path;
2245 const char *default_control_group;
2247 const char *load_error;
2250 usec_t inactive_exit_timestamp;
2251 usec_t inactive_exit_timestamp_monotonic;
2252 usec_t active_enter_timestamp;
2253 usec_t active_exit_timestamp;
2254 usec_t inactive_enter_timestamp;
2256 bool need_daemon_reload;
2261 const char *status_text;
2264 usec_t start_timestamp;
2265 usec_t exit_timestamp;
2267 int exit_code, exit_status;
2269 usec_t condition_timestamp;
2270 bool condition_result;
2273 unsigned n_accepted;
2274 unsigned n_connections;
2278 const char *sysfs_path;
2280 /* Mount, Automount */
2286 LIST_HEAD(ExecStatusInfo, exec);
2289 static void print_status_info(UnitStatusInfo *i) {
2291 const char *on, *off, *ss;
2293 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2294 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2299 /* This shows pretty information about a unit. See
2300 * print_property() for a low-level property printer */
2302 printf("%s", strna(i->id));
2304 if (i->description && !streq_ptr(i->id, i->description))
2305 printf(" - %s", i->description);
2310 printf("\t Follow: unit currently follows state of %s\n", i->following);
2312 if (streq_ptr(i->load_state, "error")) {
2313 on = ansi_highlight_red(true);
2314 off = ansi_highlight_red(false);
2318 path = i->source_path ? i->source_path : i->fragment_path;
2321 printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2322 else if (path && i->unit_file_state)
2323 printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2325 printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2327 printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off);
2329 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2331 if (streq_ptr(i->active_state, "failed")) {
2332 on = ansi_highlight_red(true);
2333 off = ansi_highlight_red(false);
2334 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2335 on = ansi_highlight_green(true);
2336 off = ansi_highlight_green(false);
2341 printf("\t Active: %s%s (%s)%s",
2343 strna(i->active_state),
2347 printf("\t Active: %s%s%s",
2349 strna(i->active_state),
2352 if (!isempty(i->result) && !streq(i->result, "success"))
2353 printf(" (Result: %s)", i->result);
2355 timestamp = (streq_ptr(i->active_state, "active") ||
2356 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2357 (streq_ptr(i->active_state, "inactive") ||
2358 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2359 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2360 i->active_exit_timestamp;
2362 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2363 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2366 printf(" since %s; %s\n", s2, s1);
2368 printf(" since %s\n", s2);
2372 if (!i->condition_result && i->condition_timestamp > 0) {
2373 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2374 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2377 printf("\t start condition failed at %s; %s\n", s2, s1);
2379 printf("\t start condition failed at %s\n", s2);
2383 printf("\t Device: %s\n", i->sysfs_path);
2385 printf("\t Where: %s\n", i->where);
2387 printf("\t What: %s\n", i->what);
2389 if (!strv_isempty(i->documentation)) {
2393 STRV_FOREACH(t, i->documentation) {
2395 printf("\t Docs: %s\n", *t);
2398 printf("\t %s\n", *t);
2403 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2405 LIST_FOREACH(exec, p, i->exec) {
2409 /* Only show exited processes here */
2413 t = strv_join(p->argv, " ");
2414 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2417 good = is_clean_exit_lsb(p->code, p->status, NULL);
2419 on = ansi_highlight_red(true);
2420 off = ansi_highlight_red(false);
2424 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2426 if (p->code == CLD_EXITED) {
2429 printf("status=%i", p->status);
2431 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2436 printf("signal=%s", signal_to_string(p->status));
2438 printf(")%s\n", off);
2440 if (i->main_pid == p->pid &&
2441 i->start_timestamp == p->start_timestamp &&
2442 i->exit_timestamp == p->start_timestamp)
2443 /* Let's not show this twice */
2446 if (p->pid == i->control_pid)
2450 if (i->main_pid > 0 || i->control_pid > 0) {
2453 if (i->main_pid > 0) {
2454 printf("Main PID: %u", (unsigned) i->main_pid);
2458 get_process_comm(i->main_pid, &t);
2463 } else if (i->exit_code > 0) {
2464 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2466 if (i->exit_code == CLD_EXITED) {
2469 printf("status=%i", i->exit_status);
2471 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2476 printf("signal=%s", signal_to_string(i->exit_status));
2481 if (i->main_pid > 0 && i->control_pid > 0)
2484 if (i->control_pid > 0) {
2487 printf(" Control: %u", (unsigned) i->control_pid);
2489 get_process_comm(i->control_pid, &t);
2500 printf("\t Status: \"%s\"\n", i->status_text);
2502 if (i->default_control_group &&
2503 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2506 printf("\t CGroup: %s\n", i->default_control_group);
2508 if (arg_transport != TRANSPORT_SSH) {
2518 if (i->main_pid > 0)
2519 extra[k++] = i->main_pid;
2521 if (i->control_pid > 0)
2522 extra[k++] = i->control_pid;
2524 show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, extra, k);
2528 if (i->id && arg_transport != TRANSPORT_SSH) {
2530 arg_all * OUTPUT_SHOW_ALL |
2531 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2532 on_tty() * OUTPUT_COLOR |
2533 !arg_quiet * OUTPUT_WARN_CUTOFF;
2536 show_journal_by_unit(stdout,
2540 i->inactive_exit_timestamp_monotonic,
2545 if (i->need_daemon_reload)
2546 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2547 ansi_highlight_red(true),
2548 ansi_highlight_red(false),
2549 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2552 static void show_unit_help(UnitStatusInfo *i) {
2557 if (!i->documentation) {
2558 log_info("Documentation for %s not known.", i->id);
2562 STRV_FOREACH(p, i->documentation) {
2564 if (startswith(*p, "man:")) {
2567 char *page = NULL, *section = NULL;
2568 const char *args[4] = { "man", NULL, NULL, NULL };
2573 if ((*p)[k-1] == ')')
2574 e = strrchr(*p, '(');
2577 page = strndup((*p) + 4, e - *p - 4);
2583 section = strndup(e + 1, *p + k - e - 2);
2597 log_error("Failed to fork: %m");
2605 execvp(args[0], (char**) args);
2606 log_error("Failed to execute man: %m");
2607 _exit(EXIT_FAILURE);
2613 wait_for_terminate(pid, NULL);
2615 log_info("Can't show: %s", *p);
2619 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2625 switch (dbus_message_iter_get_arg_type(iter)) {
2627 case DBUS_TYPE_STRING: {
2630 dbus_message_iter_get_basic(iter, &s);
2633 if (streq(name, "Id"))
2635 else if (streq(name, "LoadState"))
2637 else if (streq(name, "ActiveState"))
2638 i->active_state = s;
2639 else if (streq(name, "SubState"))
2641 else if (streq(name, "Description"))
2643 else if (streq(name, "FragmentPath"))
2644 i->fragment_path = s;
2645 else if (streq(name, "SourcePath"))
2647 else if (streq(name, "DefaultControlGroup"))
2648 i->default_control_group = s;
2649 else if (streq(name, "StatusText"))
2651 else if (streq(name, "SysFSPath"))
2653 else if (streq(name, "Where"))
2655 else if (streq(name, "What"))
2657 else if (streq(name, "Following"))
2659 else if (streq(name, "UnitFileState"))
2660 i->unit_file_state = s;
2661 else if (streq(name, "Result"))
2668 case DBUS_TYPE_BOOLEAN: {
2671 dbus_message_iter_get_basic(iter, &b);
2673 if (streq(name, "Accept"))
2675 else if (streq(name, "NeedDaemonReload"))
2676 i->need_daemon_reload = b;
2677 else if (streq(name, "ConditionResult"))
2678 i->condition_result = b;
2683 case DBUS_TYPE_UINT32: {
2686 dbus_message_iter_get_basic(iter, &u);
2688 if (streq(name, "MainPID")) {
2690 i->main_pid = (pid_t) u;
2693 } else if (streq(name, "ControlPID"))
2694 i->control_pid = (pid_t) u;
2695 else if (streq(name, "ExecMainPID")) {
2697 i->main_pid = (pid_t) u;
2698 } else if (streq(name, "NAccepted"))
2700 else if (streq(name, "NConnections"))
2701 i->n_connections = u;
2706 case DBUS_TYPE_INT32: {
2709 dbus_message_iter_get_basic(iter, &j);
2711 if (streq(name, "ExecMainCode"))
2712 i->exit_code = (int) j;
2713 else if (streq(name, "ExecMainStatus"))
2714 i->exit_status = (int) j;
2719 case DBUS_TYPE_UINT64: {
2722 dbus_message_iter_get_basic(iter, &u);
2724 if (streq(name, "ExecMainStartTimestamp"))
2725 i->start_timestamp = (usec_t) u;
2726 else if (streq(name, "ExecMainExitTimestamp"))
2727 i->exit_timestamp = (usec_t) u;
2728 else if (streq(name, "ActiveEnterTimestamp"))
2729 i->active_enter_timestamp = (usec_t) u;
2730 else if (streq(name, "InactiveEnterTimestamp"))
2731 i->inactive_enter_timestamp = (usec_t) u;
2732 else if (streq(name, "InactiveExitTimestamp"))
2733 i->inactive_exit_timestamp = (usec_t) u;
2734 else if (streq(name, "InactiveExitTimestampMonotonic"))
2735 i->inactive_exit_timestamp_monotonic = (usec_t) u;
2736 else if (streq(name, "ActiveExitTimestamp"))
2737 i->active_exit_timestamp = (usec_t) u;
2738 else if (streq(name, "ConditionTimestamp"))
2739 i->condition_timestamp = (usec_t) u;
2744 case DBUS_TYPE_ARRAY: {
2746 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2747 startswith(name, "Exec")) {
2748 DBusMessageIter sub;
2750 dbus_message_iter_recurse(iter, &sub);
2751 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2752 ExecStatusInfo *info;
2755 if (!(info = new0(ExecStatusInfo, 1)))
2758 if (!(info->name = strdup(name))) {
2763 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2768 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2770 dbus_message_iter_next(&sub);
2772 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2773 streq(name, "Documentation")) {
2775 DBusMessageIter sub;
2777 dbus_message_iter_recurse(iter, &sub);
2778 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2782 dbus_message_iter_get_basic(&sub, &s);
2784 l = strv_append(i->documentation, s);
2788 strv_free(i->documentation);
2789 i->documentation = l;
2791 dbus_message_iter_next(&sub);
2798 case DBUS_TYPE_STRUCT: {
2800 if (streq(name, "LoadError")) {
2801 DBusMessageIter sub;
2802 const char *n, *message;
2805 dbus_message_iter_recurse(iter, &sub);
2807 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2811 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2815 if (!isempty(message))
2816 i->load_error = message;
2826 static int print_property(const char *name, DBusMessageIter *iter) {
2830 /* This is a low-level property printer, see
2831 * print_status_info() for the nicer output */
2833 if (arg_property && !strv_find(arg_property, name))
2836 switch (dbus_message_iter_get_arg_type(iter)) {
2838 case DBUS_TYPE_STRUCT: {
2839 DBusMessageIter sub;
2840 dbus_message_iter_recurse(iter, &sub);
2842 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2845 dbus_message_iter_get_basic(&sub, &u);
2848 printf("%s=%u\n", name, (unsigned) u);
2850 printf("%s=\n", name);
2853 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2856 dbus_message_iter_get_basic(&sub, &s);
2858 if (arg_all || s[0])
2859 printf("%s=%s\n", name, s);
2862 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2863 const char *a = NULL, *b = NULL;
2865 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2866 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2868 if (arg_all || !isempty(a) || !isempty(b))
2869 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2877 case DBUS_TYPE_ARRAY:
2879 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2880 DBusMessageIter sub, sub2;
2882 dbus_message_iter_recurse(iter, &sub);
2883 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2887 dbus_message_iter_recurse(&sub, &sub2);
2889 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2890 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2891 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2893 dbus_message_iter_next(&sub);
2898 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2899 DBusMessageIter sub, sub2;
2901 dbus_message_iter_recurse(iter, &sub);
2902 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2903 const char *type, *path;
2905 dbus_message_iter_recurse(&sub, &sub2);
2907 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2908 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2909 printf("%s=%s\n", type, path);
2911 dbus_message_iter_next(&sub);
2916 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2917 DBusMessageIter sub, sub2;
2919 dbus_message_iter_recurse(iter, &sub);
2920 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2922 uint64_t value, next_elapse;
2924 dbus_message_iter_recurse(&sub, &sub2);
2926 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2927 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2928 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2929 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2931 printf("%s={ value=%s ; next_elapse=%s }\n",
2933 format_timespan(timespan1, sizeof(timespan1), value),
2934 format_timespan(timespan2, sizeof(timespan2), next_elapse));
2937 dbus_message_iter_next(&sub);
2942 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2943 DBusMessageIter sub, sub2;
2945 dbus_message_iter_recurse(iter, &sub);
2946 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2947 const char *controller, *attr, *value;
2949 dbus_message_iter_recurse(&sub, &sub2);
2951 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2952 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2953 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2955 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2961 dbus_message_iter_next(&sub);
2966 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2967 DBusMessageIter sub;
2969 dbus_message_iter_recurse(iter, &sub);
2970 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2971 ExecStatusInfo info;
2974 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2975 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2978 t = strv_join(info.argv, " ");
2980 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2984 yes_no(info.ignore),
2985 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2986 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2987 (unsigned) info. pid,
2988 sigchld_code_to_string(info.code),
2990 info.code == CLD_EXITED ? "" : "/",
2991 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2997 strv_free(info.argv);
2999 dbus_message_iter_next(&sub);
3008 if (generic_print_property(name, iter, arg_all) > 0)
3012 printf("%s=[unprintable]\n", name);
3017 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3018 DBusMessage *reply = NULL;
3019 const char *interface = "";
3021 DBusMessageIter iter, sub, sub2, sub3;
3022 UnitStatusInfo info;
3030 r = bus_method_call_with_reply (
3032 "org.freedesktop.systemd1",
3034 "org.freedesktop.DBus.Properties",
3038 DBUS_TYPE_STRING, &interface,
3043 if (!dbus_message_iter_init(reply, &iter) ||
3044 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3045 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
3046 log_error("Failed to parse reply.");
3051 dbus_message_iter_recurse(&iter, &sub);
3058 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3061 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
3062 log_error("Failed to parse reply.");
3067 dbus_message_iter_recurse(&sub, &sub2);
3069 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
3070 log_error("Failed to parse reply.");