1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/reboot.h>
29 #include <sys/ioctl.h>
33 #include <sys/socket.h>
36 #include <sys/prctl.h>
37 #include <dbus/dbus.h>
39 #include <systemd/sd-daemon.h>
40 #include <systemd/sd-shutdown.h>
41 #include <systemd/sd-login.h>
47 #include "utmp-wtmp.h"
50 #include "path-util.h"
52 #include "dbus-common.h"
53 #include "cgroup-show.h"
54 #include "cgroup-util.h"
56 #include "path-lookup.h"
57 #include "conf-parser.h"
58 #include "exit-status.h"
59 #include "bus-errors.h"
61 #include "unit-name.h"
63 #include "spawn-ask-password-agent.h"
64 #include "spawn-polkit-agent.h"
66 #include "logs-show.h"
67 #include "path-util.h"
68 #include "socket-util.h"
71 static char **arg_types = NULL;
72 static char **arg_load_states = NULL;
73 static char **arg_properties = NULL;
74 static bool arg_all = false;
75 static enum dependency {
80 } arg_dependency = DEPENDENCY_FORWARD;
81 static const char *arg_job_mode = "replace";
82 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
83 static bool arg_no_block = false;
84 static bool arg_no_legend = false;
85 static bool arg_no_pager = false;
86 static bool arg_no_wtmp = false;
87 static bool arg_no_wall = false;
88 static bool arg_no_reload = false;
89 static bool arg_show_types = false;
90 static bool arg_ignore_inhibitors = false;
91 static bool arg_dry = false;
92 static bool arg_quiet = false;
93 static bool arg_full = false;
94 static int arg_force = 0;
95 static bool arg_ask_password = true;
96 static bool arg_failed = false;
97 static bool arg_runtime = false;
98 static char **arg_wall = NULL;
99 static const char *arg_kill_who = NULL;
100 static int arg_signal = SIGTERM;
101 static const char *arg_root = NULL;
102 static usec_t arg_when = 0;
124 ACTION_CANCEL_SHUTDOWN,
126 } arg_action = ACTION_SYSTEMCTL;
127 static enum transport {
131 } arg_transport = TRANSPORT_NORMAL;
132 static const char *arg_host = NULL;
133 static unsigned arg_lines = 10;
134 static OutputMode arg_output = OUTPUT_SHORT;
135 static bool arg_plain = false;
137 static bool private_bus = false;
139 static int daemon_reload(DBusConnection *bus, char **args);
140 static void halt_now(enum action a);
142 static void pager_open_if_enabled(void) {
150 static void ask_password_agent_open_if_enabled(void) {
152 /* Open the password agent as a child process if necessary */
154 if (!arg_ask_password)
157 if (arg_scope != UNIT_FILE_SYSTEM)
160 ask_password_agent_open();
164 static void polkit_agent_open_if_enabled(void) {
166 /* Open the polkit agent as a child process if necessary */
168 if (!arg_ask_password)
171 if (arg_scope != UNIT_FILE_SYSTEM)
178 static const char *ansi_highlight(bool b) {
183 return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
186 static const char *ansi_highlight_red(bool b) {
191 return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
194 static const char *ansi_highlight_green(bool b) {
199 return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
202 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
205 if (!dbus_error_is_set(error))
208 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
209 dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
210 dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
211 dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
212 return EXIT_NOPERMISSION;
214 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
215 return EXIT_NOTINSTALLED;
217 if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
218 dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
219 return EXIT_NOTIMPLEMENTED;
221 if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
222 return EXIT_NOTCONFIGURED;
230 static void warn_wall(enum action a) {
231 static const char *table[_ACTION_MAX] = {
232 [ACTION_HALT] = "The system is going down for system halt NOW!",
233 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
234 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
235 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
236 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
237 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
238 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
245 _cleanup_free_ char *p;
247 p = strv_join(arg_wall, " ");
262 utmp_wall(table[a], NULL);
265 static bool avoid_bus(void) {
267 if (running_in_chroot() > 0)
270 if (sd_booted() <= 0)
273 if (!isempty(arg_root))
276 if (arg_scope == UNIT_FILE_GLOBAL)
282 static int compare_unit_info(const void *a, const void *b) {
284 const struct unit_info *u = a, *v = b;
286 d1 = strrchr(u->id, '.');
287 d2 = strrchr(v->id, '.');
292 r = strcasecmp(d1, d2);
297 return strcasecmp(u->id, v->id);
300 static bool output_show_unit(const struct unit_info *u) {
304 return streq(u->active_state, "failed");
306 return (!arg_types || ((dot = strrchr(u->id, '.')) &&
307 strv_find(arg_types, dot+1))) &&
308 (!arg_load_states || strv_find(arg_load_states, u->load_state)) &&
309 (arg_all || !(streq(u->active_state, "inactive")
310 || u->following[0]) || u->job_id > 0);
313 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
314 unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
315 const struct unit_info *u;
318 max_id_len = sizeof("UNIT")-1;
319 active_len = sizeof("ACTIVE")-1;
320 sub_len = sizeof("SUB")-1;
321 job_len = sizeof("JOB")-1;
324 for (u = unit_infos; u < unit_infos + c; u++) {
325 if (!output_show_unit(u))
328 max_id_len = MAX(max_id_len, strlen(u->id));
329 active_len = MAX(active_len, strlen(u->active_state));
330 sub_len = MAX(sub_len, strlen(u->sub_state));
331 if (u->job_id != 0) {
332 job_len = MAX(job_len, strlen(u->job_type));
339 id_len = MIN(max_id_len, 25u);
340 basic_len = 5 + id_len + 5 + active_len + sub_len;
342 basic_len += job_len + 1;
343 if (basic_len < (unsigned) columns()) {
344 unsigned extra_len, incr;
345 extra_len = columns() - basic_len;
346 /* Either UNIT already got 25, or is fully satisfied.
347 * Grant up to 25 to DESC now. */
348 incr = MIN(extra_len, 25u);
351 /* split the remaining space between UNIT and DESC,
352 * but do not give UNIT more than it needs. */
354 incr = MIN(extra_len / 2, max_id_len - id_len);
356 desc_len += extra_len - incr;
362 for (u = unit_infos; u < unit_infos + c; u++) {
363 _cleanup_free_ char *e = NULL;
364 const char *on_loaded, *off_loaded, *on = "";
365 const char *on_active, *off_active, *off = "";
367 if (!output_show_unit(u))
370 if (!n_shown && !arg_no_legend) {
371 printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
372 active_len, "ACTIVE", sub_len, "SUB");
374 printf("%-*s ", job_len, "JOB");
375 if (!arg_full && arg_no_pager)
376 printf("%.*s\n", desc_len, "DESCRIPTION");
378 printf("%s\n", "DESCRIPTION");
383 if (streq(u->load_state, "error")) {
384 on_loaded = on = ansi_highlight_red(true);
385 off_loaded = off = ansi_highlight_red(false);
387 on_loaded = off_loaded = "";
389 if (streq(u->active_state, "failed")) {
390 on_active = on = ansi_highlight_red(true);
391 off_active = off = ansi_highlight_red(false);
393 on_active = off_active = "";
395 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
397 printf("%s%-*s%s %s%-6s%s %s%-*s %-*s%s %-*s",
398 on, id_len, e ? e : u->id, off,
399 on_loaded, u->load_state, off_loaded,
400 on_active, active_len, u->active_state,
401 sub_len, u->sub_state, off_active,
402 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
403 if (!arg_full && arg_no_pager)
404 printf("%.*s\n", desc_len, u->description);
406 printf("%s\n", u->description);
409 if (!arg_no_legend) {
410 const char *on, *off;
413 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
414 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
415 "SUB = The low-level unit activation state, values depend on unit type.\n");
417 printf("JOB = Pending job for the unit.\n");
419 on = ansi_highlight(true);
420 off = ansi_highlight(false);
422 on = ansi_highlight_red(true);
423 off = ansi_highlight_red(false);
427 printf("%s%u loaded units listed.%s\n"
428 "To show all installed unit files use 'systemctl list-unit-files'.\n",
431 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
432 "To show all installed unit files use 'systemctl list-unit-files'.\n",
437 static int get_unit_list(DBusConnection *bus, DBusMessage **reply,
438 struct unit_info **unit_infos, unsigned *c) {
439 DBusMessageIter iter, sub;
447 r = bus_method_call_with_reply(
449 "org.freedesktop.systemd1",
450 "/org/freedesktop/systemd1",
451 "org.freedesktop.systemd1.Manager",
459 if (!dbus_message_iter_init(*reply, &iter) ||
460 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
461 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
462 log_error("Failed to parse reply.");
466 dbus_message_iter_recurse(&iter, &sub);
468 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
469 if (!GREEDY_REALLOC(*unit_infos, size, *c + 1))
472 bus_parse_unit_info(&sub, *unit_infos + *c);
475 dbus_message_iter_next(&sub);
481 static int list_units(DBusConnection *bus, char **args) {
482 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
483 _cleanup_free_ struct unit_info *unit_infos = NULL;
487 pager_open_if_enabled();
489 r = get_unit_list(bus, &reply, &unit_infos, &c);
493 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
495 output_units_list(unit_infos, c);
500 static int get_triggered_units(DBusConnection *bus, const char* unit_path,
503 const char *interface = "org.freedesktop.systemd1.Unit",
504 *triggers_property = "Triggers";
505 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
506 DBusMessageIter iter, sub;
509 r = bus_method_call_with_reply(bus,
510 "org.freedesktop.systemd1",
512 "org.freedesktop.DBus.Properties",
516 DBUS_TYPE_STRING, &interface,
517 DBUS_TYPE_STRING, &triggers_property,
522 if (!dbus_message_iter_init(reply, &iter) ||
523 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
524 log_error("Failed to parse reply.");
528 dbus_message_iter_recurse(&iter, &sub);
529 dbus_message_iter_recurse(&sub, &iter);
532 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
535 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
536 log_error("Failed to parse reply.");
540 dbus_message_iter_get_basic(&sub, &unit);
541 r = strv_extend(triggered, unit);
545 dbus_message_iter_next(&sub);
551 static int get_listening(DBusConnection *bus, const char* unit_path,
552 char*** listen, unsigned *c)
554 const char *interface = "org.freedesktop.systemd1.Socket",
555 *listen_property = "Listen";
556 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
557 DBusMessageIter iter, sub;
560 r = bus_method_call_with_reply(bus,
561 "org.freedesktop.systemd1",
563 "org.freedesktop.DBus.Properties",
567 DBUS_TYPE_STRING, &interface,
568 DBUS_TYPE_STRING, &listen_property,
573 if (!dbus_message_iter_init(reply, &iter) ||
574 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
575 log_error("Failed to parse reply.");
579 dbus_message_iter_recurse(&iter, &sub);
580 dbus_message_iter_recurse(&sub, &iter);
583 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
584 DBusMessageIter sub2;
585 const char *type, *path;
587 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
588 log_error("Failed to parse reply.");
592 dbus_message_iter_recurse(&sub, &sub2);
594 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
595 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
596 r = strv_extend(listen, type);
600 r = strv_extend(listen, path);
607 dbus_message_iter_next(&sub);
619 /* Note: triggered is a list here, although it almost certainly
620 * will always be one unit. Nevertheless, dbus API allows for multiple
621 * values, so let's follow that.*/
624 /* The strv above is shared. free is set only in the first one. */
628 static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
629 int o = strcmp(a->path, b->path);
631 o = strcmp(a->type, b->type);
635 static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
636 struct socket_info *s;
637 unsigned pathlen = sizeof("LISTEN") - 1,
638 typelen = (sizeof("TYPE") - 1) * arg_show_types,
639 socklen = sizeof("UNIT") - 1,
640 servlen = sizeof("ACTIVATES") - 1;
641 const char *on, *off;
643 for (s = socket_infos; s < socket_infos + cs; s++) {
647 socklen = MAX(socklen, strlen(s->id));
649 typelen = MAX(typelen, strlen(s->type));
650 pathlen = MAX(pathlen, strlen(s->path));
652 STRV_FOREACH(a, s->triggered)
653 tmp += strlen(*a) + 2*(a != s->triggered);
654 servlen = MAX(servlen, tmp);
659 printf("%-*s %-*.*s%-*s %s\n",
661 typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
665 for (s = socket_infos; s < socket_infos + cs; s++) {
669 printf("%-*s %-*s %-*s",
670 pathlen, s->path, typelen, s->type, socklen, s->id);
673 pathlen, s->path, socklen, s->id);
674 STRV_FOREACH(a, s->triggered)
676 a == s->triggered ? "" : ",", *a);
680 on = ansi_highlight(true);
681 off = ansi_highlight(false);
685 on = ansi_highlight_red(true);
686 off = ansi_highlight_red(false);
689 if (!arg_no_legend) {
690 printf("%s%u sockets listed.%s\n", on, cs, off);
692 printf("Pass --all to see loaded but inactive sockets, too.\n");
698 static int list_sockets(DBusConnection *bus, char **args) {
699 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
700 _cleanup_free_ struct unit_info *unit_infos = NULL;
701 struct socket_info *socket_infos = NULL;
702 const struct unit_info *u;
703 struct socket_info *s;
704 unsigned cu = 0, cs = 0;
708 pager_open_if_enabled();
710 r = get_unit_list(bus, &reply, &unit_infos, &cu);
714 for (u = unit_infos; u < unit_infos + cu; u++) {
716 _cleanup_strv_free_ char **listen = NULL, **triggered = NULL;
719 if (!output_show_unit(u))
722 if ((dot = strrchr(u->id, '.')) && !streq(dot+1, "socket"))
725 r = get_triggered_units(bus, u->unit_path, &triggered);
729 r = get_listening(bus, u->unit_path, &listen, &c);
733 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
738 for (i = 0; i < c; i++)
739 socket_infos[cs + i] = (struct socket_info) {
742 .path = listen[i*2 + 1],
743 .triggered = triggered,
744 .own_triggered = i==0,
747 /* from this point on we will cleanup those socket_infos */
750 listen = triggered = NULL; /* avoid cleanup */
753 qsort(socket_infos, cs, sizeof(struct socket_info),
754 (__compar_fn_t) socket_info_compare);
756 output_sockets_list(socket_infos, cs);
759 assert(cs == 0 || socket_infos);
760 for (s = socket_infos; s < socket_infos + cs; s++) {
763 if (s->own_triggered)
764 strv_free(s->triggered);
771 static int compare_unit_file_list(const void *a, const void *b) {
773 const UnitFileList *u = a, *v = b;
775 d1 = strrchr(u->path, '.');
776 d2 = strrchr(v->path, '.');
781 r = strcasecmp(d1, d2);
786 return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
789 static bool output_show_unit_file(const UnitFileList *u) {
792 return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
795 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
796 unsigned max_id_len, id_cols, state_cols, n_shown = 0;
797 const UnitFileList *u;
799 max_id_len = sizeof("UNIT FILE")-1;
800 state_cols = sizeof("STATE")-1;
801 for (u = units; u < units + c; u++) {
802 if (!output_show_unit_file(u))
805 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
806 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
811 id_cols = MIN(max_id_len, 25u);
812 basic_cols = 1 + id_cols + state_cols;
813 if (basic_cols < (unsigned) columns())
814 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
816 id_cols = max_id_len;
819 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
821 for (u = units; u < units + c; u++) {
822 _cleanup_free_ char *e = NULL;
823 const char *on, *off;
826 if (!output_show_unit_file(u))
831 if (u->state == UNIT_FILE_MASKED ||
832 u->state == UNIT_FILE_MASKED_RUNTIME ||
833 u->state == UNIT_FILE_DISABLED ||
834 u->state == UNIT_FILE_INVALID) {
835 on = ansi_highlight_red(true);
836 off = ansi_highlight_red(false);
837 } else if (u->state == UNIT_FILE_ENABLED) {
838 on = ansi_highlight_green(true);
839 off = ansi_highlight_green(false);
843 id = path_get_file_name(u->path);
845 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
847 printf("%-*s %s%-*s%s\n",
849 on, state_cols, unit_file_state_to_string(u->state), off);
853 printf("\n%u unit files listed.\n", n_shown);
856 static int list_unit_files(DBusConnection *bus, char **args) {
857 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
858 _cleanup_free_ UnitFileList *units = NULL;
859 DBusMessageIter iter, sub, sub2;
860 unsigned c = 0, n_units = 0;
863 pager_open_if_enabled();
870 h = hashmap_new(string_hash_func, string_compare_func);
874 r = unit_file_get_list(arg_scope, arg_root, h);
876 unit_file_list_free(h);
877 log_error("Failed to get unit file list: %s", strerror(-r));
881 n_units = hashmap_size(h);
882 units = new(UnitFileList, n_units);
884 unit_file_list_free(h);
888 HASHMAP_FOREACH(u, h, i) {
889 memcpy(units + c++, u, sizeof(UnitFileList));
895 r = bus_method_call_with_reply(
897 "org.freedesktop.systemd1",
898 "/org/freedesktop/systemd1",
899 "org.freedesktop.systemd1.Manager",
907 if (!dbus_message_iter_init(reply, &iter) ||
908 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
909 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
910 log_error("Failed to parse reply.");
914 dbus_message_iter_recurse(&iter, &sub);
916 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
920 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
925 n_units = MAX(2*c, 16u);
926 w = realloc(units, sizeof(struct UnitFileList) * n_units);
935 dbus_message_iter_recurse(&sub, &sub2);
937 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
938 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
939 log_error("Failed to parse reply.");
943 u->state = unit_file_state_from_string(state);
945 dbus_message_iter_next(&sub);
951 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
952 output_unit_file_list(units, c);
958 static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
960 _cleanup_free_ char *n = NULL;
962 size_t max_len = MAX(columns(),20u);
965 for (i = level - 1; i >= 0; i--) {
967 if(len > max_len - 3 && !arg_full) {
968 printf("%s...\n",max_len % 2 ? "" : " ");
971 printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
974 if(len > max_len - 3 && !arg_full) {
975 printf("%s...\n",max_len % 2 ? "" : " ");
978 printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
982 printf("%s\n", name);
986 n = ellipsize(name, max_len-len, 100);
994 static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
995 static const char *dependencies[] = {
996 [DEPENDENCY_FORWARD] = "Requires\0"
997 "RequiresOverridable\0"
999 "RequisiteOverridable\0"
1001 [DEPENDENCY_REVERSE] = "RequiredBy\0"
1002 "RequiredByOverridable\0"
1005 [DEPENDENCY_AFTER] = "After\0",
1006 [DEPENDENCY_BEFORE] = "Before\0",
1009 _cleanup_free_ char *path;
1010 const char *interface = "org.freedesktop.systemd1.Unit";
1012 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1013 DBusMessageIter iter, sub, sub2, sub3;
1022 path = unit_dbus_path_from_name(name);
1028 r = bus_method_call_with_reply(
1030 "org.freedesktop.systemd1",
1032 "org.freedesktop.DBus.Properties",
1036 DBUS_TYPE_STRING, &interface,
1041 if (!dbus_message_iter_init(reply, &iter) ||
1042 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1043 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
1044 log_error("Failed to parse reply.");
1049 dbus_message_iter_recurse(&iter, &sub);
1051 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1054 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
1055 dbus_message_iter_recurse(&sub, &sub2);
1057 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
1058 log_error("Failed to parse reply.");
1063 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
1064 log_error("Failed to parse reply.");
1069 dbus_message_iter_recurse(&sub2, &sub3);
1070 dbus_message_iter_next(&sub);
1072 assert(arg_dependency < ELEMENTSOF(dependencies));
1073 if (!nulstr_contains(dependencies[arg_dependency], prop))
1076 if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
1077 if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
1078 DBusMessageIter sub4;
1079 dbus_message_iter_recurse(&sub3, &sub4);
1081 while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
1084 assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
1085 dbus_message_iter_get_basic(&sub4, &s);
1087 r = strv_extend(&ret, s);
1093 dbus_message_iter_next(&sub4);
1106 static int list_dependencies_compare(const void *_a, const void *_b) {
1107 const char **a = (const char**) _a, **b = (const char**) _b;
1108 if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
1110 if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
1112 return strcasecmp(*a, *b);
1115 static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char ***units, unsigned int branches) {
1116 _cleanup_strv_free_ char **deps = NULL, **u;
1120 u = strv_append(*units, name);
1124 r = list_dependencies_get_dependencies(bus, name, &deps);
1128 qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
1130 STRV_FOREACH(c, deps) {
1131 if (strv_contains(u, *c)) {
1133 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
1140 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
1144 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
1145 r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
1158 static int list_dependencies(DBusConnection *bus, char **args) {
1159 _cleanup_free_ char *unit = NULL;
1160 _cleanup_strv_free_ char **units = NULL;
1166 unit = unit_name_mangle(args[1]);
1171 u = SPECIAL_DEFAULT_TARGET;
1173 pager_open_if_enabled();
1177 return list_dependencies_one(bus, u, 0, &units, 0);
1180 static int get_default(DBusConnection *bus, char **args) {
1182 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
1184 _cleanup_dbus_error_free_ DBusError error;
1186 dbus_error_init(&error);
1188 if (!bus || avoid_bus()) {
1189 r = unit_file_get_default(arg_scope, arg_root, &path);
1192 log_error("Operation failed: %s", strerror(-r));
1198 r = bus_method_call_with_reply(
1200 "org.freedesktop.systemd1",
1201 "/org/freedesktop/systemd1",
1202 "org.freedesktop.systemd1.Manager",
1209 log_error("Operation failed: %s", strerror(-r));
1213 if (!dbus_message_get_args(reply, &error,
1214 DBUS_TYPE_STRING, &path,
1215 DBUS_TYPE_INVALID)) {
1216 log_error("Failed to parse reply: %s", bus_error_message(&error));
1217 dbus_error_free(&error);
1223 printf("%s\n", path);
1226 if ((!bus || avoid_bus()) && path)
1235 char *name, *type, *state;
1238 static void list_jobs_print(struct job_info* jobs, size_t n) {
1241 const char *on, *off;
1242 bool shorten = false;
1244 assert(n == 0 || jobs);
1247 on = ansi_highlight_green(true);
1248 off = ansi_highlight_green(false);
1250 printf("%sNo jobs running.%s\n", on, off);
1254 pager_open_if_enabled();
1257 /* JOB UNIT TYPE STATE */
1258 unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5;
1260 for (i = 0, j = jobs; i < n; i++, j++) {
1261 assert(j->name && j->type && j->state);
1262 l0 = MAX(l0, DECIMAL_STR_WIDTH(j->id));
1263 l1 = MAX(l1, strlen(j->name));
1264 l2 = MAX(l2, strlen(j->type));
1265 l3 = MAX(l3, strlen(j->state));
1268 if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) {
1269 l1 = MAX(33u, columns() - l0 - l2 - l3 - 3);
1274 printf("%*s %-*s %-*s %-*s\n",
1280 for (i = 0, j = jobs; i < n; i++, j++) {
1281 _cleanup_free_ char *e = NULL;
1283 if (streq(j->state, "running")) {
1284 on = ansi_highlight(true);
1285 off = ansi_highlight(false);
1289 e = shorten ? ellipsize(j->name, l1, 33) : NULL;
1290 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
1292 on, l1, e ? e : j->name, off,
1294 on, l3, j->state, off);
1298 on = ansi_highlight(true);
1299 off = ansi_highlight(false);
1302 printf("\n%s%zu jobs listed%s.\n", on, n, off);
1305 static int list_jobs(DBusConnection *bus, char **args) {
1306 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1307 DBusMessageIter iter, sub, sub2;
1309 struct job_info *jobs = NULL;
1310 size_t size = 0, used = 0;
1312 r = bus_method_call_with_reply(
1314 "org.freedesktop.systemd1",
1315 "/org/freedesktop/systemd1",
1316 "org.freedesktop.systemd1.Manager",
1324 if (!dbus_message_iter_init(reply, &iter) ||
1325 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1326 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1327 log_error("Failed to parse reply.");
1331 dbus_message_iter_recurse(&iter, &sub);
1333 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1334 const char *name, *type, *state, *job_path, *unit_path;
1337 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1338 log_error("Failed to parse reply.");
1342 dbus_message_iter_recurse(&sub, &sub2);
1344 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1345 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1346 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1347 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1348 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1349 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1350 log_error("Failed to parse reply.");
1355 if (!GREEDY_REALLOC(jobs, size, used + 1)) {
1360 jobs[used++] = (struct job_info) { id,
1364 if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) {
1369 dbus_message_iter_next(&sub);
1372 list_jobs_print(jobs, used);
1376 free(jobs[used].name);
1377 free(jobs[used].type);
1378 free(jobs[used].state);
1385 static int load_unit(DBusConnection *bus, char **args) {
1390 STRV_FOREACH(name, args+1) {
1391 _cleanup_free_ char *n = NULL;
1394 n = unit_name_mangle(*name);
1398 r = bus_method_call_with_reply(
1400 "org.freedesktop.systemd1",
1401 "/org/freedesktop/systemd1",
1402 "org.freedesktop.systemd1.Manager",
1406 DBUS_TYPE_STRING, &n,
1415 static int cancel_job(DBusConnection *bus, char **args) {
1420 if (strv_length(args) <= 1)
1421 return daemon_reload(bus, args);
1423 STRV_FOREACH(name, args+1) {
1427 r = safe_atou32(*name, &id);
1429 log_error("Failed to parse job id: %s", strerror(-r));
1433 r = bus_method_call_with_reply(
1435 "org.freedesktop.systemd1",
1436 "/org/freedesktop/systemd1",
1437 "org.freedesktop.systemd1.Manager",
1441 DBUS_TYPE_UINT32, &id,
1450 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1451 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1452 dbus_bool_t b = FALSE;
1453 DBusMessageIter iter, sub;
1455 *interface = "org.freedesktop.systemd1.Unit",
1456 *property = "NeedDaemonReload",
1458 _cleanup_free_ char *n = NULL;
1461 /* We ignore all errors here, since this is used to show a warning only */
1463 n = unit_name_mangle(unit);
1467 r = bus_method_call_with_reply(
1469 "org.freedesktop.systemd1",
1470 "/org/freedesktop/systemd1",
1471 "org.freedesktop.systemd1.Manager",
1475 DBUS_TYPE_STRING, &n,
1480 if (!dbus_message_get_args(reply, NULL,
1481 DBUS_TYPE_OBJECT_PATH, &path,
1485 dbus_message_unref(reply);
1488 r = bus_method_call_with_reply(
1490 "org.freedesktop.systemd1",
1492 "org.freedesktop.DBus.Properties",
1496 DBUS_TYPE_STRING, &interface,
1497 DBUS_TYPE_STRING, &property,
1502 if (!dbus_message_iter_init(reply, &iter) ||
1503 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1506 dbus_message_iter_recurse(&iter, &sub);
1507 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1510 dbus_message_iter_get_basic(&sub, &b);
1514 typedef struct WaitData {
1521 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1522 _cleanup_dbus_error_free_ DBusError error;
1525 dbus_error_init(&error);
1531 log_debug("Got D-Bus request: %s.%s() on %s",
1532 dbus_message_get_interface(message),
1533 dbus_message_get_member(message),
1534 dbus_message_get_path(message));
1536 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1537 log_error("Warning! D-Bus connection terminated.");
1538 dbus_connection_close(connection);
1540 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1542 const char *path, *result, *unit;
1544 if (dbus_message_get_args(message, &error,
1545 DBUS_TYPE_UINT32, &id,
1546 DBUS_TYPE_OBJECT_PATH, &path,
1547 DBUS_TYPE_STRING, &unit,
1548 DBUS_TYPE_STRING, &result,
1549 DBUS_TYPE_INVALID)) {
1551 free(set_remove(d->set, (char*) path));
1553 if (!isempty(result))
1554 d->result = strdup(result);
1557 d->name = strdup(unit);
1559 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1562 dbus_error_free(&error);
1563 if (dbus_message_get_args(message, &error,
1564 DBUS_TYPE_UINT32, &id,
1565 DBUS_TYPE_OBJECT_PATH, &path,
1566 DBUS_TYPE_STRING, &result,
1567 DBUS_TYPE_INVALID)) {
1568 /* Compatibility with older systemd versions <
1569 * 183 during upgrades. This should be dropped
1571 free(set_remove(d->set, (char*) path));
1574 d->result = strdup(result);
1576 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1580 log_error("Failed to parse message: %s", bus_error_message(&error));
1583 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1586 static int enable_wait_for_jobs(DBusConnection *bus) {
1594 dbus_error_init(&error);
1595 dbus_bus_add_match(bus,
1597 "sender='org.freedesktop.systemd1',"
1598 "interface='org.freedesktop.systemd1.Manager',"
1599 "member='JobRemoved',"
1600 "path='/org/freedesktop/systemd1'",
1603 if (dbus_error_is_set(&error)) {
1604 log_error("Failed to add match: %s", bus_error_message(&error));
1605 dbus_error_free(&error);
1609 /* This is slightly dirty, since we don't undo the match registrations. */
1613 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1615 WaitData d = { .set = s };
1620 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1623 while (!set_isempty(s)) {
1625 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1626 log_error("Disconnected from bus.");
1627 return -ECONNREFUSED;
1634 if (streq(d.result, "timeout"))
1635 log_error("Job for %s timed out.", strna(d.name));
1636 else if (streq(d.result, "canceled"))
1637 log_error("Job for %s canceled.", strna(d.name));
1638 else if (streq(d.result, "dependency"))
1639 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1640 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1641 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1644 if (streq_ptr(d.result, "timeout"))
1646 else if (streq_ptr(d.result, "canceled"))
1648 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1659 dbus_connection_remove_filter(bus, wait_filter, &d);
1663 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1664 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1665 _cleanup_free_ char *n = NULL;
1666 DBusMessageIter iter, sub;
1668 *interface = "org.freedesktop.systemd1.Unit",
1669 *property = "ActiveState";
1670 const char *state, *path;
1676 dbus_error_init(&error);
1678 n = unit_name_mangle(name);
1682 r = bus_method_call_with_reply (
1684 "org.freedesktop.systemd1",
1685 "/org/freedesktop/systemd1",
1686 "org.freedesktop.systemd1.Manager",
1690 DBUS_TYPE_STRING, &n,
1693 dbus_error_free(&error);
1700 if (!dbus_message_get_args(reply, NULL,
1701 DBUS_TYPE_OBJECT_PATH, &path,
1702 DBUS_TYPE_INVALID)) {
1703 log_error("Failed to parse reply.");
1707 dbus_message_unref(reply);
1710 r = bus_method_call_with_reply(
1712 "org.freedesktop.systemd1",
1714 "org.freedesktop.DBus.Properties",
1718 DBUS_TYPE_STRING, &interface,
1719 DBUS_TYPE_STRING, &property,
1727 if (!dbus_message_iter_init(reply, &iter) ||
1728 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1729 log_error("Failed to parse reply.");
1733 dbus_message_iter_recurse(&iter, &sub);
1735 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1736 log_error("Failed to parse reply.");
1740 dbus_message_iter_get_basic(&sub, &state);
1745 return strv_find(check_states, state) ? 1 : 0;
1748 static void check_triggering_units(
1749 DBusConnection *bus,
1750 const char *unit_name) {
1752 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1753 DBusMessageIter iter, sub;
1754 const char *interface = "org.freedesktop.systemd1.Unit",
1755 *load_state_property = "LoadState",
1756 *triggered_by_property = "TriggeredBy",
1758 _cleanup_free_ char *unit_path = NULL, *n = NULL;
1759 bool print_warning_label = true;
1762 n = unit_name_mangle(unit_name);
1768 unit_path = unit_dbus_path_from_name(n);
1774 r = bus_method_call_with_reply(
1776 "org.freedesktop.systemd1",
1778 "org.freedesktop.DBus.Properties",
1782 DBUS_TYPE_STRING, &interface,
1783 DBUS_TYPE_STRING, &load_state_property,
1788 if (!dbus_message_iter_init(reply, &iter) ||
1789 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1790 log_error("Failed to parse reply.");
1794 dbus_message_iter_recurse(&iter, &sub);
1796 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1797 log_error("Failed to parse reply.");
1801 dbus_message_iter_get_basic(&sub, &state);
1803 if (streq(state, "masked"))
1806 dbus_message_unref(reply);
1809 r = bus_method_call_with_reply(
1811 "org.freedesktop.systemd1",
1813 "org.freedesktop.DBus.Properties",
1817 DBUS_TYPE_STRING, &interface,
1818 DBUS_TYPE_STRING, &triggered_by_property,
1823 if (!dbus_message_iter_init(reply, &iter) ||
1824 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1825 log_error("Failed to parse reply.");
1829 dbus_message_iter_recurse(&iter, &sub);
1830 dbus_message_iter_recurse(&sub, &iter);
1833 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1834 const char * const check_states[] = {
1839 const char *service_trigger;
1841 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1842 log_error("Failed to parse reply.");
1846 dbus_message_iter_get_basic(&sub, &service_trigger);
1848 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1852 if (print_warning_label) {
1853 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1854 print_warning_label = false;
1857 log_warning(" %s", service_trigger);
1860 dbus_message_iter_next(&sub);
1864 static int start_unit_one(
1865 DBusConnection *bus,
1872 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1873 _cleanup_free_ char *n;
1882 n = unit_name_mangle(name);
1886 r = bus_method_call_with_reply(
1888 "org.freedesktop.systemd1",
1889 "/org/freedesktop/systemd1",
1890 "org.freedesktop.systemd1.Manager",
1894 DBUS_TYPE_STRING, &n,
1895 DBUS_TYPE_STRING, &mode,
1898 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1899 /* There's always a fallback possible for
1900 * legacy actions. */
1903 log_error("Failed to issue method call: %s", bus_error_message(error));
1908 if (!dbus_message_get_args(reply, error,
1909 DBUS_TYPE_OBJECT_PATH, &path,
1910 DBUS_TYPE_INVALID)) {
1911 log_error("Failed to parse reply: %s", bus_error_message(error));
1915 if (need_daemon_reload(bus, n))
1916 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1917 n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1926 r = set_consume(s, p);
1928 log_error("Failed to add path to set.");
1936 static const struct {
1940 } action_table[_ACTION_MAX] = {
1941 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
1942 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
1943 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
1944 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
1945 [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
1946 [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
1947 [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
1948 [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
1949 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
1950 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
1951 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
1952 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
1953 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
1954 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
1955 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1958 static enum action verb_to_action(const char *verb) {
1961 for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1962 if (action_table[i].verb && streq(verb, action_table[i].verb))
1964 return ACTION_INVALID;
1967 static int start_unit(DBusConnection *bus, char **args) {
1970 const char *method, *mode, *one_name;
1971 _cleanup_set_free_free_ Set *s = NULL;
1972 _cleanup_dbus_error_free_ DBusError error;
1975 dbus_error_init(&error);
1979 ask_password_agent_open_if_enabled();
1981 if (arg_action == ACTION_SYSTEMCTL) {
1984 streq(args[0], "stop") ||
1985 streq(args[0], "condstop") ? "StopUnit" :
1986 streq(args[0], "reload") ? "ReloadUnit" :
1987 streq(args[0], "restart") ? "RestartUnit" :
1989 streq(args[0], "try-restart") ||
1990 streq(args[0], "condrestart") ? "TryRestartUnit" :
1992 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1994 streq(args[0], "reload-or-try-restart") ||
1995 streq(args[0], "condreload") ||
1997 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1999 action = verb_to_action(args[0]);
2001 mode = streq(args[0], "isolate") ? "isolate" :
2002 action_table[action].mode ?: arg_job_mode;
2004 one_name = action_table[action].target;
2007 assert(arg_action < ELEMENTSOF(action_table));
2008 assert(action_table[arg_action].target);
2010 method = "StartUnit";
2012 mode = action_table[arg_action].mode;
2013 one_name = action_table[arg_action].target;
2016 if (!arg_no_block) {
2017 ret = enable_wait_for_jobs(bus);
2019 log_error("Could not watch jobs: %s", strerror(-ret));
2023 s = set_new(string_hash_func, string_compare_func);
2029 ret = start_unit_one(bus, method, one_name, mode, &error, s);
2031 ret = translate_bus_error_to_exit_status(ret, &error);
2033 STRV_FOREACH(name, args+1) {
2034 r = start_unit_one(bus, method, *name, mode, &error, s);
2036 ret = translate_bus_error_to_exit_status(r, &error);
2037 dbus_error_free(&error);
2042 if (!arg_no_block) {
2043 r = wait_for_jobs(bus, s);
2047 /* When stopping units, warn if they can still be triggered by
2048 * another active unit (socket, path, timer) */
2049 if (!arg_quiet && streq(method, "StopUnit")) {
2051 check_triggering_units(bus, one_name);
2053 STRV_FOREACH(name, args+1)
2054 check_triggering_units(bus, *name);
2061 /* Ask systemd-logind, which might grant access to unprivileged users
2062 * through PolicyKit */
2063 static int reboot_with_logind(DBusConnection *bus, enum action a) {
2066 dbus_bool_t interactive = true;
2071 polkit_agent_open_if_enabled();
2079 case ACTION_POWEROFF:
2080 method = "PowerOff";
2083 case ACTION_SUSPEND:
2087 case ACTION_HIBERNATE:
2088 method = "Hibernate";
2091 case ACTION_HYBRID_SLEEP:
2092 method = "HybridSleep";
2099 return bus_method_call_with_reply(
2101 "org.freedesktop.login1",
2102 "/org/freedesktop/login1",
2103 "org.freedesktop.login1.Manager",
2107 DBUS_TYPE_BOOLEAN, &interactive,
2114 static int check_inhibitors(DBusConnection *bus, enum action a) {
2116 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2117 DBusMessageIter iter, sub, sub2;
2120 _cleanup_strv_free_ char **sessions = NULL;
2126 if (arg_ignore_inhibitors || arg_force > 0)
2138 r = bus_method_call_with_reply(
2140 "org.freedesktop.login1",
2141 "/org/freedesktop/login1",
2142 "org.freedesktop.login1.Manager",
2148 /* If logind is not around, then there are no inhibitors... */
2151 if (!dbus_message_iter_init(reply, &iter) ||
2152 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2153 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
2154 log_error("Failed to parse reply.");
2158 dbus_message_iter_recurse(&iter, &sub);
2159 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2160 const char *what, *who, *why, *mode;
2162 _cleanup_strv_free_ char **sv = NULL;
2163 _cleanup_free_ char *comm = NULL, *user = NULL;
2165 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
2166 log_error("Failed to parse reply.");
2170 dbus_message_iter_recurse(&sub, &sub2);
2172 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
2173 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
2174 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
2175 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
2176 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
2177 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
2178 log_error("Failed to parse reply.");
2182 if (!streq(mode, "block"))
2185 sv = strv_split(what, ":");
2189 if (!strv_contains(sv,
2191 a == ACTION_POWEROFF ||
2192 a == ACTION_REBOOT ||
2193 a == ACTION_KEXEC ? "shutdown" : "sleep"))
2196 get_process_comm(pid, &comm);
2197 user = uid_to_name(uid);
2198 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
2199 who, (unsigned long) pid, strna(comm), strna(user), why);
2203 dbus_message_iter_next(&sub);
2206 dbus_message_iter_recurse(&iter, &sub);
2208 /* Check for current sessions */
2209 sd_get_sessions(&sessions);
2210 STRV_FOREACH(s, sessions) {
2212 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2214 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2217 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2220 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2223 sd_session_get_tty(*s, &tty);
2224 sd_session_get_seat(*s, &seat);
2225 sd_session_get_service(*s, &service);
2226 user = uid_to_name(uid);
2228 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2235 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
2236 action_table[a].verb);
2244 static int start_special(DBusConnection *bus, char **args) {
2250 a = verb_to_action(args[0]);
2252 r = check_inhibitors(bus, a);
2256 if (arg_force >= 2 && geteuid() != 0) {
2257 log_error("Must be root.");
2261 if (arg_force >= 2 &&
2262 (a == ACTION_HALT ||
2263 a == ACTION_POWEROFF ||
2264 a == ACTION_REBOOT))
2267 if (arg_force >= 1 &&
2268 (a == ACTION_HALT ||
2269 a == ACTION_POWEROFF ||
2270 a == ACTION_REBOOT ||
2271 a == ACTION_KEXEC ||
2273 return daemon_reload(bus, args);
2275 /* first try logind, to allow authentication with polkit */
2276 if (geteuid() != 0 &&
2277 (a == ACTION_POWEROFF ||
2278 a == ACTION_REBOOT ||
2279 a == ACTION_SUSPEND ||
2280 a == ACTION_HIBERNATE ||
2281 a == ACTION_HYBRID_SLEEP)) {
2282 r = reboot_with_logind(bus, a);
2287 r = start_unit(bus, args);
2288 if (r == EXIT_SUCCESS)
2294 static int check_unit_active(DBusConnection *bus, char **args) {
2295 const char * const check_states[] = {
2302 int r = 3; /* According to LSB: "program is not running" */
2307 STRV_FOREACH(name, args+1) {
2310 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2320 static int check_unit_failed(DBusConnection *bus, char **args) {
2321 const char * const check_states[] = {
2332 STRV_FOREACH(name, args+1) {
2335 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2345 static int kill_unit(DBusConnection *bus, char **args) {
2353 arg_kill_who = "all";
2355 STRV_FOREACH(name, args+1) {
2356 _cleanup_free_ char *n = NULL;
2358 n = unit_name_mangle(*name);
2362 r = bus_method_call_with_reply(
2364 "org.freedesktop.systemd1",
2365 "/org/freedesktop/systemd1",
2366 "org.freedesktop.systemd1.Manager",
2370 DBUS_TYPE_STRING, &n,
2371 DBUS_TYPE_STRING, &arg_kill_who,
2372 DBUS_TYPE_INT32, &arg_signal,
2380 static int set_cgroup(DBusConnection *bus, char **args) {
2381 _cleanup_free_ char *n = NULL;
2382 const char *method, *runtime;
2390 streq(args[0], "set-cgroup") ? "SetUnitControlGroup" :
2391 streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
2392 : "UnsetUnitControlGroupAttribute";
2394 runtime = arg_runtime ? "runtime" : "persistent";
2396 n = unit_name_mangle(args[1]);
2400 STRV_FOREACH(argument, args + 2) {
2402 r = bus_method_call_with_reply(
2404 "org.freedesktop.systemd1",
2405 "/org/freedesktop/systemd1",
2406 "org.freedesktop.systemd1.Manager",
2410 DBUS_TYPE_STRING, &n,
2411 DBUS_TYPE_STRING, argument,
2412 DBUS_TYPE_STRING, &runtime,
2421 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2422 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2424 DBusMessageIter iter;
2425 _cleanup_free_ char *n = NULL;
2426 const char *runtime;
2432 dbus_error_init(&error);
2434 runtime = arg_runtime ? "runtime" : "persistent";
2436 n = unit_name_mangle(args[1]);
2440 m = dbus_message_new_method_call(
2441 "org.freedesktop.systemd1",
2442 "/org/freedesktop/systemd1",
2443 "org.freedesktop.systemd1.Manager",
2444 "SetUnitControlGroupAttribute");
2448 dbus_message_iter_init_append(m, &iter);
2449 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2450 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
2453 r = bus_append_strv_iter(&iter, args + 3);
2457 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2460 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2462 log_error("Failed to issue method call: %s", bus_error_message(&error));
2463 dbus_error_free(&error);
2470 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2471 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2472 _cleanup_free_ char *n = NULL;
2479 n = unit_name_mangle(args[1]);
2483 STRV_FOREACH(argument, args + 2) {
2484 _cleanup_strv_free_ char **list = NULL;
2485 DBusMessageIter iter;
2488 r = bus_method_call_with_reply(
2490 "org.freedesktop.systemd1",
2491 "/org/freedesktop/systemd1",
2492 "org.freedesktop.systemd1.Manager",
2493 "GetUnitControlGroupAttribute",
2496 DBUS_TYPE_STRING, &n,
2497 DBUS_TYPE_STRING, argument,
2502 if (!dbus_message_iter_init(reply, &iter)) {
2503 log_error("Failed to initialize iterator.");
2507 r = bus_parse_strv_iter(&iter, &list);
2509 log_error("Failed to parse value list.");
2513 STRV_FOREACH(a, list) {
2514 if (endswith(*a, "\n"))
2524 typedef struct ExecStatusInfo {
2532 usec_t start_timestamp;
2533 usec_t exit_timestamp;
2538 LIST_FIELDS(struct ExecStatusInfo, exec);
2541 static void exec_status_info_free(ExecStatusInfo *i) {
2550 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2551 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2552 DBusMessageIter sub2, sub3;
2556 int32_t code, status;
2562 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2565 dbus_message_iter_recurse(sub, &sub2);
2567 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2570 i->path = strdup(path);
2574 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2575 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2579 dbus_message_iter_recurse(&sub2, &sub3);
2580 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2581 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2582 dbus_message_iter_next(&sub3);
2586 i->argv = new0(char*, n+1);
2591 dbus_message_iter_recurse(&sub2, &sub3);
2592 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2595 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2596 dbus_message_iter_get_basic(&sub3, &s);
2597 dbus_message_iter_next(&sub3);
2599 i->argv[n] = strdup(s);
2606 if (!dbus_message_iter_next(&sub2) ||
2607 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2608 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2609 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2610 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2611 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2612 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2613 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2614 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2618 i->start_timestamp = (usec_t) start_timestamp;
2619 i->exit_timestamp = (usec_t) exit_timestamp;
2620 i->pid = (pid_t) pid;
2627 typedef struct UnitStatusInfo {
2629 const char *load_state;
2630 const char *active_state;
2631 const char *sub_state;
2632 const char *unit_file_state;
2634 const char *description;
2635 const char *following;
2637 char **documentation;
2639 const char *fragment_path;
2640 const char *source_path;
2641 const char *default_control_group;
2643 char **dropin_paths;
2645 const char *load_error;
2648 usec_t inactive_exit_timestamp;
2649 usec_t inactive_exit_timestamp_monotonic;
2650 usec_t active_enter_timestamp;
2651 usec_t active_exit_timestamp;
2652 usec_t inactive_enter_timestamp;
2654 bool need_daemon_reload;
2659 const char *status_text;
2662 usec_t start_timestamp;
2663 usec_t exit_timestamp;
2665 int exit_code, exit_status;
2667 usec_t condition_timestamp;
2668 bool condition_result;
2671 unsigned n_accepted;
2672 unsigned n_connections;
2675 /* Pairs of type, path */
2679 const char *sysfs_path;
2681 /* Mount, Automount */
2687 LIST_HEAD(ExecStatusInfo, exec);
2690 static void print_status_info(UnitStatusInfo *i) {
2692 const char *on, *off, *ss;
2694 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2695 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2698 arg_all * OUTPUT_SHOW_ALL |
2699 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2700 on_tty() * OUTPUT_COLOR |
2701 !arg_quiet * OUTPUT_WARN_CUTOFF |
2702 arg_full * OUTPUT_FULL_WIDTH;
2703 int maxlen = 8; /* a value that'll suffice most of the time */
2708 STRV_FOREACH_PAIR(t, t2, i->listen)
2709 maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
2711 maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
2712 if (i->main_pid > 0)
2713 maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
2714 else if (i->control_pid > 0)
2715 maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
2717 /* This shows pretty information about a unit. See
2718 * print_property() for a low-level property printer */
2720 printf("%s", strna(i->id));
2722 if (i->description && !streq_ptr(i->id, i->description))
2723 printf(" - %s", i->description);
2728 printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
2730 if (streq_ptr(i->load_state, "error")) {
2731 on = ansi_highlight_red(true);
2732 off = ansi_highlight_red(false);
2736 path = i->source_path ? i->source_path : i->fragment_path;
2739 printf(" %*s: %s%s%s (Reason: %s)\n",
2740 maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
2741 else if (path && i->unit_file_state)
2742 printf(" %*s: %s%s%s (%s; %s)\n",
2743 maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
2745 printf(" %*s: %s%s%s (%s)\n",
2746 maxlen, "Loaded", on, strna(i->load_state), off, path);
2748 printf(" %*s: %s%s%s\n",
2749 maxlen, "Loaded", on, strna(i->load_state), off);
2751 if (!strv_isempty(i->dropin_paths)) {
2756 STRV_FOREACH(dropin, i->dropin_paths) {
2757 if (! dir || last) {
2758 printf(" %*s ", maxlen, dir ? "" : "Drop-In:");
2762 if (path_get_parent(*dropin, &dir) < 0) {
2767 printf("%s\n %*s %s", dir, maxlen, "",
2768 draw_special_char(DRAW_TREE_RIGHT));
2771 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2773 printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2779 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2781 if (streq_ptr(i->active_state, "failed")) {
2782 on = ansi_highlight_red(true);
2783 off = ansi_highlight_red(false);
2784 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2785 on = ansi_highlight_green(true);
2786 off = ansi_highlight_green(false);
2791 printf(" %*s: %s%s (%s)%s",
2792 maxlen, "Active", on, strna(i->active_state), ss, off);
2794 printf(" %*s: %s%s%s",
2795 maxlen, "Active", on, strna(i->active_state), off);
2797 if (!isempty(i->result) && !streq(i->result, "success"))
2798 printf(" (Result: %s)", i->result);
2800 timestamp = (streq_ptr(i->active_state, "active") ||
2801 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2802 (streq_ptr(i->active_state, "inactive") ||
2803 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2804 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2805 i->active_exit_timestamp;
2807 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2808 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2811 printf(" since %s; %s\n", s2, s1);
2813 printf(" since %s\n", s2);
2817 if (!i->condition_result && i->condition_timestamp > 0) {
2818 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2819 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2822 printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
2824 printf(" %*s start condition failed at %s\n", maxlen, "", s2);
2828 printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
2830 printf(" %*s: %s\n", maxlen, "Where", i->where);
2832 printf(" %*s: %s\n", maxlen, "What", i->what);
2834 STRV_FOREACH(t, i->documentation)
2835 printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
2837 STRV_FOREACH_PAIR(t, t2, i->listen)
2838 printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
2841 printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
2843 LIST_FOREACH(exec, p, i->exec) {
2844 _cleanup_free_ char *argv = NULL;
2847 /* Only show exited processes here */
2851 argv = strv_join(p->argv, " ");
2852 printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
2854 good = is_clean_exit_lsb(p->code, p->status, NULL);
2856 on = ansi_highlight_red(true);
2857 off = ansi_highlight_red(false);
2861 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2863 if (p->code == CLD_EXITED) {
2866 printf("status=%i", p->status);
2868 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2873 printf("signal=%s", signal_to_string(p->status));
2875 printf(")%s\n", off);
2877 if (i->main_pid == p->pid &&
2878 i->start_timestamp == p->start_timestamp &&
2879 i->exit_timestamp == p->start_timestamp)
2880 /* Let's not show this twice */
2883 if (p->pid == i->control_pid)
2887 if (i->main_pid > 0 || i->control_pid > 0) {
2888 if (i->main_pid > 0) {
2889 printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
2892 _cleanup_free_ char *comm = NULL;
2893 get_process_comm(i->main_pid, &comm);
2895 printf(" (%s)", comm);
2896 } else if (i->exit_code > 0) {
2897 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2899 if (i->exit_code == CLD_EXITED) {
2902 printf("status=%i", i->exit_status);
2904 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2909 printf("signal=%s", signal_to_string(i->exit_status));
2913 if (i->control_pid > 0)
2917 if (i->control_pid > 0) {
2918 _cleanup_free_ char *c = NULL;
2920 printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
2922 get_process_comm(i->control_pid, &c);
2931 printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
2933 if (i->default_control_group &&
2934 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2937 printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
2939 if (arg_transport != TRANSPORT_SSH) {
2942 char prefix[maxlen + 4];
2943 memset(prefix, ' ', sizeof(prefix) - 1);
2944 prefix[sizeof(prefix) - 1] = '\0';
2947 if (c > sizeof(prefix) - 1)
2948 c -= sizeof(prefix) - 1;
2952 if (i->main_pid > 0)
2953 extra[k++] = i->main_pid;
2955 if (i->control_pid > 0)
2956 extra[k++] = i->control_pid;
2958 show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
2959 c, false, extra, k, flags);
2963 if (i->id && arg_transport != TRANSPORT_SSH) {
2965 show_journal_by_unit(stdout,
2969 i->inactive_exit_timestamp_monotonic,
2973 arg_scope == UNIT_FILE_SYSTEM);
2976 if (i->need_daemon_reload)
2977 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2978 ansi_highlight_red(true),
2979 ansi_highlight_red(false),
2980 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2983 static void show_unit_help(UnitStatusInfo *i) {
2988 if (!i->documentation) {
2989 log_info("Documentation for %s not known.", i->id);
2993 STRV_FOREACH(p, i->documentation) {
2995 if (startswith(*p, "man:")) {
2998 _cleanup_free_ char *page = NULL, *section = NULL;
2999 const char *args[4] = { "man", NULL, NULL, NULL };
3004 if ((*p)[k-1] == ')')
3005 e = strrchr(*p, '(');
3008 page = strndup((*p) + 4, e - *p - 4);
3009 section = strndup(e + 1, *p + k - e - 2);
3010 if (!page || !section) {
3022 log_error("Failed to fork: %m");
3028 execvp(args[0], (char**) args);
3029 log_error("Failed to execute man: %m");
3030 _exit(EXIT_FAILURE);
3033 wait_for_terminate(pid, NULL);
3035 log_info("Can't show: %s", *p);
3039 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
3045 switch (dbus_message_iter_get_arg_type(iter)) {
3047 case DBUS_TYPE_STRING: {
3050 dbus_message_iter_get_basic(iter, &s);
3053 if (streq(name, "Id"))
3055 else if (streq(name, "LoadState"))
3057 else if (streq(name, "ActiveState"))
3058 i->active_state = s;
3059 else if (streq(name, "SubState"))
3061 else if (streq(name, "Description"))
3063 else if (streq(name, "FragmentPath"))
3064 i->fragment_path = s;
3065 else if (streq(name, "SourcePath"))
3067 else if (streq(name, "DefaultControlGroup"))
3068 i->default_control_group = s;
3069 else if (streq(name, "StatusText"))
3071 else if (streq(name, "SysFSPath"))
3073 else if (streq(name, "Where"))
3075 else if (streq(name, "What"))
3077 else if (streq(name, "Following"))
3079 else if (streq(name, "UnitFileState"))
3080 i->unit_file_state = s;
3081 else if (streq(name, "Result"))
3088 case DBUS_TYPE_BOOLEAN: {
3091 dbus_message_iter_get_basic(iter, &b);
3093 if (streq(name, "Accept"))
3095 else if (streq(name, "NeedDaemonReload"))
3096 i->need_daemon_reload = b;
3097 else if (streq(name, "ConditionResult"))
3098 i->condition_result = b;
3103 case DBUS_TYPE_UINT32: {
3106 dbus_message_iter_get_basic(iter, &u);
3108 if (streq(name, "MainPID")) {
3110 i->main_pid = (pid_t) u;
3113 } else if (streq(name, "ControlPID"))
3114 i->control_pid = (pid_t) u;
3115 else if (streq(name, "ExecMainPID")) {
3117 i->main_pid = (pid_t) u;
3118 } else if (streq(name, "NAccepted"))
3120 else if (streq(name, "NConnections"))
3121 i->n_connections = u;
3126 case DBUS_TYPE_INT32: {
3129 dbus_message_iter_get_basic(iter, &j);
3131 if (streq(name, "ExecMainCode"))
3132 i->exit_code = (int) j;
3133 else if (streq(name, "ExecMainStatus"))
3134 i->exit_status = (int) j;
3139 case DBUS_TYPE_UINT64: {
3142 dbus_message_iter_get_basic(iter, &u);
3144 if (streq(name, "ExecMainStartTimestamp"))
3145 i->start_timestamp = (usec_t) u;
3146 else if (streq(name, "ExecMainExitTimestamp"))
3147 i->exit_timestamp = (usec_t) u;
3148 else if (streq(name, "ActiveEnterTimestamp"))
3149 i->active_enter_timestamp = (usec_t) u;
3150 else if (streq(name, "InactiveEnterTimestamp"))
3151 i->inactive_enter_timestamp = (usec_t) u;
3152 else if (streq(name, "InactiveExitTimestamp"))
3153 i->inactive_exit_timestamp = (usec_t) u;
3154 else if (streq(name, "InactiveExitTimestampMonotonic"))
3155 i->inactive_exit_timestamp_monotonic = (usec_t) u;
3156 else if (streq(name, "ActiveExitTimestamp"))
3157 i->active_exit_timestamp = (usec_t) u;
3158 else if (streq(name, "ConditionTimestamp"))
3159 i->condition_timestamp = (usec_t) u;
3164 case DBUS_TYPE_ARRAY: {
3166 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3167 startswith(name, "Exec")) {
3168 DBusMessageIter sub;
3170 dbus_message_iter_recurse(iter, &sub);
3171 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3172 ExecStatusInfo *info;
3175 if (!(info = new0(ExecStatusInfo, 1)))
3178 if (!(info->name = strdup(name))) {
3183 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
3188 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
3190 dbus_message_iter_next(&sub);
3193 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3194 DBusMessageIter sub, sub2;
3196 dbus_message_iter_recurse(iter, &sub);
3197 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3198 const char *type, *path;
3200 dbus_message_iter_recurse(&sub, &sub2);
3202 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3203 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
3206 r = strv_extend(&i->listen, type);
3209 r = strv_extend(&i->listen, path);
3214 dbus_message_iter_next(&sub);
3219 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
3220 int r = bus_parse_strv_iter(iter, &i->dropin_paths);
3224 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
3225 streq(name, "Documentation")) {
3227 DBusMessageIter sub;
3229 dbus_message_iter_recurse(iter, &sub);
3230 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
3234 dbus_message_iter_get_basic(&sub, &s);
3236 r = strv_extend(&i->documentation, s);
3240 dbus_message_iter_next(&sub);
3247 case DBUS_TYPE_STRUCT: {
3249 if (streq(name, "LoadError")) {
3250 DBusMessageIter sub;
3251 const char *n, *message;
3254 dbus_message_iter_recurse(iter, &sub);
3256 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
3260 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
3264 if (!isempty(message))
3265 i->load_error = message;
3275 static int print_property(const char *name, DBusMessageIter *iter) {
3279 /* This is a low-level property printer, see
3280 * print_status_info() for the nicer output */
3282 if (arg_properties && !strv_find(arg_properties, name))
3285 switch (dbus_message_iter_get_arg_type(iter)) {
3287 case DBUS_TYPE_STRUCT: {
3288 DBusMessageIter sub;
3289 dbus_message_iter_recurse(iter, &sub);
3291 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
3294 dbus_message_iter_get_basic(&sub, &u);
3297 printf("%s=%u\n", name, (unsigned) u);
3299 printf("%s=\n", name);
3302 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
3305 dbus_message_iter_get_basic(&sub, &s);
3307 if (arg_all || s[0])
3308 printf("%s=%s\n", name, s);
3311 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
3312 const char *a = NULL, *b = NULL;
3314 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
3315 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
3317 if (arg_all || !isempty(a) || !isempty(b))
3318 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
3326 case DBUS_TYPE_ARRAY:
3328 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
3329 DBusMessageIter sub, sub2;
3331 dbus_message_iter_recurse(iter, &sub);
3332 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3336 dbus_message_iter_recurse(&sub, &sub2);
3338 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3339 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
3340 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
3342 dbus_message_iter_next(&sub);
3347 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
3348 DBusMessageIter sub, sub2;
3350 dbus_message_iter_recurse(iter, &sub);
3352 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3353 const char *type, *path;
3355 dbus_message_iter_recurse(&sub, &sub2);
3357 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3358 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3359 printf("%s=%s\n", type, path);
3361 dbus_message_iter_next(&sub);
3366 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3367 DBusMessageIter sub, sub2;
3369 dbus_message_iter_recurse(iter, &sub);
3370 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3371 const char *type, *path;
3373 dbus_message_iter_recurse(&sub, &sub2);
3375 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3376 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3377 printf("Listen%s=%s\n", type, path);
3379 dbus_message_iter_next(&sub);
3384 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
3385 DBusMessageIter sub, sub2;
3387 dbus_message_iter_recurse(iter, &sub);
3388 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3390 uint64_t value, next_elapse;
3392 dbus_message_iter_recurse(&sub, &sub2);
3394 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
3395 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
3396 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
3397 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
3399 printf("%s={ value=%s ; next_elapse=%s }\n",
3401 format_timespan(timespan1, sizeof(timespan1), value, 0),
3402 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
3405 dbus_message_iter_next(&sub);
3410 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
3411 DBusMessageIter sub, sub2;
3413 dbus_message_iter_recurse(iter, &sub);
3414 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3415 const char *controller, *attr, *value;
3417 dbus_message_iter_recurse(&sub, &sub2);
3419 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
3420 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
3421 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
3423 printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
3429 dbus_message_iter_next(&sub);
3434 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3435 DBusMessageIter sub;
3437 dbus_message_iter_recurse(iter, &sub);
3438 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3439 ExecStatusInfo info = {};
3441 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3442 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3443 _cleanup_free_ char *t;
3445 t = strv_join(info.argv, " ");
3447 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3451 yes_no(info.ignore),
3452 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3453 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3454 (unsigned) info. pid,
3455 sigchld_code_to_string(info.code),
3457 info.code == CLD_EXITED ? "" : "/",
3458 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3462 strv_free(info.argv);
3464 dbus_message_iter_next(&sub);
3473 if (generic_print_property(name, iter, arg_all) > 0)
3477 printf("%s=[unprintable]\n", name);
3482 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3483 _cleanup_free_ DBusMessage *reply = NULL;
3484 const char *interface = "";
3486 DBusMessageIter iter, sub, sub2, sub3;
3487 UnitStatusInfo info = {};
3493 r = bus_method_call_with_reply(
3495 "org.freedesktop.systemd1",
3497 "org.freedesktop.DBus.Properties",
3501 DBUS_TYPE_STRING, &interface,
3506 if (!dbus_message_iter_init(reply, &iter) ||
3507 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3508 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
3509 log_error("Failed to parse reply.");