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 typedef struct ExecStatusInfo {
2036 usec_t start_timestamp;
2037 usec_t exit_timestamp;
2042 LIST_FIELDS(struct ExecStatusInfo, exec);
2045 static void exec_status_info_free(ExecStatusInfo *i) {
2054 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2055 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2056 DBusMessageIter sub2, sub3;
2060 int32_t code, status;
2066 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2069 dbus_message_iter_recurse(sub, &sub2);
2071 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2074 if (!(i->path = strdup(path)))
2077 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2078 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2082 dbus_message_iter_recurse(&sub2, &sub3);
2083 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2084 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2085 dbus_message_iter_next(&sub3);
2090 if (!(i->argv = new0(char*, n+1)))
2094 dbus_message_iter_recurse(&sub2, &sub3);
2095 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2098 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2099 dbus_message_iter_get_basic(&sub3, &s);
2100 dbus_message_iter_next(&sub3);
2102 if (!(i->argv[n++] = strdup(s)))
2106 if (!dbus_message_iter_next(&sub2) ||
2107 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2108 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2109 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2110 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2111 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2112 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2113 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2114 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2118 i->start_timestamp = (usec_t) start_timestamp;
2119 i->exit_timestamp = (usec_t) exit_timestamp;
2120 i->pid = (pid_t) pid;
2127 typedef struct UnitStatusInfo {
2129 const char *load_state;
2130 const char *active_state;
2131 const char *sub_state;
2132 const char *unit_file_state;
2134 const char *description;
2135 const char *following;
2137 char **documentation;
2139 const char *fragment_path;
2140 const char *source_path;
2141 const char *default_control_group;
2143 const char *load_error;
2146 usec_t inactive_exit_timestamp;
2147 usec_t inactive_exit_timestamp_monotonic;
2148 usec_t active_enter_timestamp;
2149 usec_t active_exit_timestamp;
2150 usec_t inactive_enter_timestamp;
2152 bool need_daemon_reload;
2157 const char *status_text;
2160 usec_t start_timestamp;
2161 usec_t exit_timestamp;
2163 int exit_code, exit_status;
2165 usec_t condition_timestamp;
2166 bool condition_result;
2169 unsigned n_accepted;
2170 unsigned n_connections;
2174 const char *sysfs_path;
2176 /* Mount, Automount */
2182 LIST_HEAD(ExecStatusInfo, exec);
2185 static void print_status_info(UnitStatusInfo *i) {
2187 const char *on, *off, *ss;
2189 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2190 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2195 /* This shows pretty information about a unit. See
2196 * print_property() for a low-level property printer */
2198 printf("%s", strna(i->id));
2200 if (i->description && !streq_ptr(i->id, i->description))
2201 printf(" - %s", i->description);
2206 printf("\t Follow: unit currently follows state of %s\n", i->following);
2208 if (streq_ptr(i->load_state, "error")) {
2209 on = ansi_highlight_red(true);
2210 off = ansi_highlight_red(false);
2214 path = i->source_path ? i->source_path : i->fragment_path;
2217 printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2218 else if (path && i->unit_file_state)
2219 printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2221 printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2223 printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off);
2225 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2227 if (streq_ptr(i->active_state, "failed")) {
2228 on = ansi_highlight_red(true);
2229 off = ansi_highlight_red(false);
2230 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2231 on = ansi_highlight_green(true);
2232 off = ansi_highlight_green(false);
2237 printf("\t Active: %s%s (%s)%s",
2239 strna(i->active_state),
2243 printf("\t Active: %s%s%s",
2245 strna(i->active_state),
2248 if (!isempty(i->result) && !streq(i->result, "success"))
2249 printf(" (Result: %s)", i->result);
2251 timestamp = (streq_ptr(i->active_state, "active") ||
2252 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2253 (streq_ptr(i->active_state, "inactive") ||
2254 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2255 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2256 i->active_exit_timestamp;
2258 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2259 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2262 printf(" since %s; %s\n", s2, s1);
2264 printf(" since %s\n", s2);
2268 if (!i->condition_result && i->condition_timestamp > 0) {
2269 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2270 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2273 printf("\t start condition failed at %s; %s\n", s2, s1);
2275 printf("\t start condition failed at %s\n", s2);
2279 printf("\t Device: %s\n", i->sysfs_path);
2281 printf("\t Where: %s\n", i->where);
2283 printf("\t What: %s\n", i->what);
2285 if (!strv_isempty(i->documentation)) {
2289 STRV_FOREACH(t, i->documentation) {
2291 printf("\t Docs: %s\n", *t);
2294 printf("\t %s\n", *t);
2299 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2301 LIST_FOREACH(exec, p, i->exec) {
2305 /* Only show exited processes here */
2309 t = strv_join(p->argv, " ");
2310 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2313 good = is_clean_exit_lsb(p->code, p->status, NULL);
2315 on = ansi_highlight_red(true);
2316 off = ansi_highlight_red(false);
2320 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2322 if (p->code == CLD_EXITED) {
2325 printf("status=%i", p->status);
2327 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2332 printf("signal=%s", signal_to_string(p->status));
2334 printf(")%s\n", off);
2336 if (i->main_pid == p->pid &&
2337 i->start_timestamp == p->start_timestamp &&
2338 i->exit_timestamp == p->start_timestamp)
2339 /* Let's not show this twice */
2342 if (p->pid == i->control_pid)
2346 if (i->main_pid > 0 || i->control_pid > 0) {
2349 if (i->main_pid > 0) {
2350 printf("Main PID: %u", (unsigned) i->main_pid);
2354 get_process_comm(i->main_pid, &t);
2359 } else if (i->exit_code > 0) {
2360 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2362 if (i->exit_code == CLD_EXITED) {
2365 printf("status=%i", i->exit_status);
2367 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2372 printf("signal=%s", signal_to_string(i->exit_status));
2377 if (i->main_pid > 0 && i->control_pid > 0)
2380 if (i->control_pid > 0) {
2383 printf(" Control: %u", (unsigned) i->control_pid);
2385 get_process_comm(i->control_pid, &t);
2396 printf("\t Status: \"%s\"\n", i->status_text);
2398 if (i->default_control_group &&
2399 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2402 printf("\t CGroup: %s\n", i->default_control_group);
2404 if (arg_transport != TRANSPORT_SSH) {
2414 if (i->main_pid > 0)
2415 extra[k++] = i->main_pid;
2417 if (i->control_pid > 0)
2418 extra[k++] = i->control_pid;
2420 show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, extra, k);
2424 if (i->id && arg_transport != TRANSPORT_SSH) {
2426 arg_all * OUTPUT_SHOW_ALL |
2427 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2428 on_tty() * OUTPUT_COLOR |
2429 !arg_quiet * OUTPUT_WARN_CUTOFF;
2432 show_journal_by_unit(stdout,
2436 i->inactive_exit_timestamp_monotonic,
2441 if (i->need_daemon_reload)
2442 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2443 ansi_highlight_red(true),
2444 ansi_highlight_red(false),
2445 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2448 static void show_unit_help(UnitStatusInfo *i) {
2453 if (!i->documentation) {
2454 log_info("Documentation for %s not known.", i->id);
2458 STRV_FOREACH(p, i->documentation) {
2460 if (startswith(*p, "man:")) {
2463 char *page = NULL, *section = NULL;
2464 const char *args[4] = { "man", NULL, NULL, NULL };
2469 if ((*p)[k-1] == ')')
2470 e = strrchr(*p, '(');
2473 page = strndup((*p) + 4, e - *p - 4);
2479 section = strndup(e + 1, *p + k - e - 2);
2493 log_error("Failed to fork: %m");
2501 execvp(args[0], (char**) args);
2502 log_error("Failed to execute man: %m");
2503 _exit(EXIT_FAILURE);
2509 wait_for_terminate(pid, NULL);
2511 log_info("Can't show: %s", *p);
2515 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2521 switch (dbus_message_iter_get_arg_type(iter)) {
2523 case DBUS_TYPE_STRING: {
2526 dbus_message_iter_get_basic(iter, &s);
2529 if (streq(name, "Id"))
2531 else if (streq(name, "LoadState"))
2533 else if (streq(name, "ActiveState"))
2534 i->active_state = s;
2535 else if (streq(name, "SubState"))
2537 else if (streq(name, "Description"))
2539 else if (streq(name, "FragmentPath"))
2540 i->fragment_path = s;
2541 else if (streq(name, "SourcePath"))
2543 else if (streq(name, "DefaultControlGroup"))
2544 i->default_control_group = s;
2545 else if (streq(name, "StatusText"))
2547 else if (streq(name, "SysFSPath"))
2549 else if (streq(name, "Where"))
2551 else if (streq(name, "What"))
2553 else if (streq(name, "Following"))
2555 else if (streq(name, "UnitFileState"))
2556 i->unit_file_state = s;
2557 else if (streq(name, "Result"))
2564 case DBUS_TYPE_BOOLEAN: {
2567 dbus_message_iter_get_basic(iter, &b);
2569 if (streq(name, "Accept"))
2571 else if (streq(name, "NeedDaemonReload"))
2572 i->need_daemon_reload = b;
2573 else if (streq(name, "ConditionResult"))
2574 i->condition_result = b;
2579 case DBUS_TYPE_UINT32: {
2582 dbus_message_iter_get_basic(iter, &u);
2584 if (streq(name, "MainPID")) {
2586 i->main_pid = (pid_t) u;
2589 } else if (streq(name, "ControlPID"))
2590 i->control_pid = (pid_t) u;
2591 else if (streq(name, "ExecMainPID")) {
2593 i->main_pid = (pid_t) u;
2594 } else if (streq(name, "NAccepted"))
2596 else if (streq(name, "NConnections"))
2597 i->n_connections = u;
2602 case DBUS_TYPE_INT32: {
2605 dbus_message_iter_get_basic(iter, &j);
2607 if (streq(name, "ExecMainCode"))
2608 i->exit_code = (int) j;
2609 else if (streq(name, "ExecMainStatus"))
2610 i->exit_status = (int) j;
2615 case DBUS_TYPE_UINT64: {
2618 dbus_message_iter_get_basic(iter, &u);
2620 if (streq(name, "ExecMainStartTimestamp"))
2621 i->start_timestamp = (usec_t) u;
2622 else if (streq(name, "ExecMainExitTimestamp"))
2623 i->exit_timestamp = (usec_t) u;
2624 else if (streq(name, "ActiveEnterTimestamp"))
2625 i->active_enter_timestamp = (usec_t) u;
2626 else if (streq(name, "InactiveEnterTimestamp"))
2627 i->inactive_enter_timestamp = (usec_t) u;
2628 else if (streq(name, "InactiveExitTimestamp"))
2629 i->inactive_exit_timestamp = (usec_t) u;
2630 else if (streq(name, "InactiveExitTimestampMonotonic"))
2631 i->inactive_exit_timestamp_monotonic = (usec_t) u;
2632 else if (streq(name, "ActiveExitTimestamp"))
2633 i->active_exit_timestamp = (usec_t) u;
2634 else if (streq(name, "ConditionTimestamp"))
2635 i->condition_timestamp = (usec_t) u;
2640 case DBUS_TYPE_ARRAY: {
2642 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2643 startswith(name, "Exec")) {
2644 DBusMessageIter sub;
2646 dbus_message_iter_recurse(iter, &sub);
2647 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2648 ExecStatusInfo *info;
2651 if (!(info = new0(ExecStatusInfo, 1)))
2654 if (!(info->name = strdup(name))) {
2659 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2664 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2666 dbus_message_iter_next(&sub);
2668 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2669 streq(name, "Documentation")) {
2671 DBusMessageIter sub;
2673 dbus_message_iter_recurse(iter, &sub);
2674 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2678 dbus_message_iter_get_basic(&sub, &s);
2680 l = strv_append(i->documentation, s);
2684 strv_free(i->documentation);
2685 i->documentation = l;
2687 dbus_message_iter_next(&sub);
2694 case DBUS_TYPE_STRUCT: {
2696 if (streq(name, "LoadError")) {
2697 DBusMessageIter sub;
2698 const char *n, *message;
2701 dbus_message_iter_recurse(iter, &sub);
2703 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2707 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2711 if (!isempty(message))
2712 i->load_error = message;
2722 static int print_property(const char *name, DBusMessageIter *iter) {
2726 /* This is a low-level property printer, see
2727 * print_status_info() for the nicer output */
2729 if (arg_property && !strv_find(arg_property, name))
2732 switch (dbus_message_iter_get_arg_type(iter)) {
2734 case DBUS_TYPE_STRUCT: {
2735 DBusMessageIter sub;
2736 dbus_message_iter_recurse(iter, &sub);
2738 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2741 dbus_message_iter_get_basic(&sub, &u);
2744 printf("%s=%u\n", name, (unsigned) u);
2746 printf("%s=\n", name);
2749 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2752 dbus_message_iter_get_basic(&sub, &s);
2754 if (arg_all || s[0])
2755 printf("%s=%s\n", name, s);
2758 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2759 const char *a = NULL, *b = NULL;
2761 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2762 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2764 if (arg_all || !isempty(a) || !isempty(b))
2765 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2773 case DBUS_TYPE_ARRAY:
2775 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2776 DBusMessageIter sub, sub2;
2778 dbus_message_iter_recurse(iter, &sub);
2779 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2783 dbus_message_iter_recurse(&sub, &sub2);
2785 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2786 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2787 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2789 dbus_message_iter_next(&sub);
2794 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2795 DBusMessageIter sub, sub2;
2797 dbus_message_iter_recurse(iter, &sub);
2798 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2799 const char *type, *path;
2801 dbus_message_iter_recurse(&sub, &sub2);
2803 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2804 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2805 printf("%s=%s\n", type, path);
2807 dbus_message_iter_next(&sub);
2812 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2813 DBusMessageIter sub, sub2;
2815 dbus_message_iter_recurse(iter, &sub);
2816 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2818 uint64_t value, next_elapse;
2820 dbus_message_iter_recurse(&sub, &sub2);
2822 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2823 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2824 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2825 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2827 printf("%s={ value=%s ; next_elapse=%s }\n",
2829 format_timespan(timespan1, sizeof(timespan1), value),
2830 format_timespan(timespan2, sizeof(timespan2), next_elapse));
2833 dbus_message_iter_next(&sub);
2838 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2839 DBusMessageIter sub, sub2;
2841 dbus_message_iter_recurse(iter, &sub);
2842 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2843 const char *controller, *attr, *value;
2845 dbus_message_iter_recurse(&sub, &sub2);
2847 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2848 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2849 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2851 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2857 dbus_message_iter_next(&sub);
2862 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2863 DBusMessageIter sub;
2865 dbus_message_iter_recurse(iter, &sub);
2866 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2867 ExecStatusInfo info;
2870 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2871 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2874 t = strv_join(info.argv, " ");
2876 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2880 yes_no(info.ignore),
2881 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2882 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2883 (unsigned) info. pid,
2884 sigchld_code_to_string(info.code),
2886 info.code == CLD_EXITED ? "" : "/",
2887 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2893 strv_free(info.argv);
2895 dbus_message_iter_next(&sub);
2904 if (generic_print_property(name, iter, arg_all) > 0)
2908 printf("%s=[unprintable]\n", name);
2913 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2914 DBusMessage *reply = NULL;
2915 const char *interface = "";
2917 DBusMessageIter iter, sub, sub2, sub3;
2918 UnitStatusInfo info;
2926 r = bus_method_call_with_reply (
2928 "org.freedesktop.systemd1",
2930 "org.freedesktop.DBus.Properties",
2934 DBUS_TYPE_STRING, &interface,
2939 if (!dbus_message_iter_init(reply, &iter) ||
2940 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2941 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
2942 log_error("Failed to parse reply.");
2947 dbus_message_iter_recurse(&iter, &sub);
2954 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2957 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2958 log_error("Failed to parse reply.");
2963 dbus_message_iter_recurse(&sub, &sub2);
2965 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2966 log_error("Failed to parse reply.");
2971 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
2972 log_error("Failed to parse reply.");
2977 dbus_message_iter_recurse(&sub2, &sub3);
2979 if (show_properties)
2980 r = print_property(name, &sub3);
2982 r = status_property(name, &sub3, &info);
2985 log_error("Failed to parse reply.");
2990 dbus_message_iter_next(&sub);
2995 if (!show_properties) {
2996 if (streq(verb, "help"))
2997 show_unit_help(&info);
2999 print_status_info(&info);
3002 strv_free(info.documentation);
3004 if (!streq_ptr(info.active_state, "active") &&
3005 !streq_ptr(info.active_state, "reloading") &&
3006 streq(verb, "status"))
3007 /* According to LSB: "program not running" */
3010 while ((p = info.exec)) {
3011 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3012 exec_status_info_free(p);
3017 dbus_message_unref(reply);
3022 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3023 DBusMessage *reply = NULL;
3024 const char *path = NULL;
3028 dbus_error_init(&error);
3030 r = bus_method_call_with_reply (
3032 "org.freedesktop.systemd1",
3033 "/org/freedesktop/systemd1",
3034 "org.freedesktop.systemd1.Manager",
3038 DBUS_TYPE_UINT32, &pid,
3043 if (!dbus_message_get_args(reply, &error,
3044 DBUS_TYPE_OBJECT_PATH, &path,
3045 DBUS_TYPE_INVALID)) {
3046 log_error("Failed to parse reply: %s", bus_error_message(&error));
3051 r = show_one(verb, bus, path, false, new_line);
3055 dbus_message_unref(reply);
3057 dbus_error_free(&error);
3062 static int show(DBusConnection *bus, char **args) {
3064 bool show_properties, new_line = false;
3070 show_properties = streq(args[0], "show");
3072 if (show_properties)
3073 pager_open_if_enabled();