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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/reboot.h>
28 #include <sys/ioctl.h>
32 #include <sys/socket.h>
35 #include <sys/prctl.h>
36 #include <dbus/dbus.h>
42 #include "utmp-wtmp.h"
46 #include "dbus-common.h"
47 #include "cgroup-show.h"
48 #include "cgroup-util.h"
50 #include "path-lookup.h"
51 #include "conf-parser.h"
52 #include "sd-daemon.h"
53 #include "shutdownd.h"
54 #include "exit-status.h"
55 #include "bus-errors.h"
57 #include "unit-name.h"
59 #include "spawn-agent.h"
62 static const char *arg_type = NULL;
63 static char **arg_property = NULL;
64 static bool arg_all = false;
65 static const char *arg_job_mode = "replace";
66 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
67 static bool arg_immediate = false;
68 static bool arg_no_block = false;
69 static bool arg_no_legend = false;
70 static bool arg_no_pager = false;
71 static bool arg_no_wtmp = false;
72 static bool arg_no_sync = false;
73 static bool arg_no_wall = false;
74 static bool arg_no_reload = false;
75 static bool arg_dry = false;
76 static bool arg_quiet = false;
77 static bool arg_full = false;
78 static bool arg_force = false;
79 static bool arg_ask_password = false;
80 static bool arg_failed = false;
81 static bool arg_runtime = false;
82 static char **arg_wall = NULL;
83 static const char *arg_kill_who = NULL;
84 static const char *arg_kill_mode = NULL;
85 static int arg_signal = SIGTERM;
86 static const char *arg_root = NULL;
87 static usec_t arg_when = 0;
106 ACTION_CANCEL_SHUTDOWN,
108 } arg_action = ACTION_SYSTEMCTL;
114 static enum transport {
118 } arg_transport = TRANSPORT_NORMAL;
119 static const char *arg_host = NULL;
121 static bool private_bus = false;
123 static int daemon_reload(DBusConnection *bus, char **args);
125 static bool on_tty(void) {
128 /* Note that this is invoked relatively early, before we start
129 * the pager. That means the value we return reflects whether
130 * we originally were started on a tty, not if we currently
131 * are. But this is intended, since we want colour and so on
132 * when run in our own pager. */
134 if (_unlikely_(t < 0))
135 t = isatty(STDOUT_FILENO) > 0;
140 static void pager_open_if_enabled(void) {
142 /* Cache result before we open the pager */
151 static void agent_open_if_enabled(void) {
153 /* Open the password agent as a child process if necessary */
155 if (!arg_ask_password)
158 if (arg_scope != UNIT_FILE_SYSTEM)
164 static const char *ansi_highlight(bool b) {
169 return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
172 static const char *ansi_highlight_green(bool b) {
177 return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
180 static bool error_is_no_service(const DBusError *error) {
183 if (!dbus_error_is_set(error))
186 if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
189 if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
192 return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
195 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
198 if (!dbus_error_is_set(error))
201 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
202 dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
203 dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
204 dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
205 return EXIT_NOPERMISSION;
207 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
208 return EXIT_NOTINSTALLED;
210 if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
211 dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
212 return EXIT_NOTIMPLEMENTED;
214 if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
215 return EXIT_NOTCONFIGURED;
223 static void warn_wall(enum action action) {
224 static const char *table[_ACTION_MAX] = {
225 [ACTION_HALT] = "The system is going down for system halt NOW!",
226 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
227 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
228 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
229 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
230 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
239 if (!(p = strv_join(arg_wall, " "))) {
240 log_error("Failed to join strings.");
256 utmp_wall(table[action], NULL);
259 static bool avoid_bus(void) {
261 if (running_in_chroot() > 0)
264 if (sd_booted() <= 0)
267 if (!isempty(arg_root))
270 if (arg_scope == UNIT_FILE_GLOBAL)
278 const char *description;
279 const char *load_state;
280 const char *active_state;
281 const char *sub_state;
282 const char *following;
283 const char *unit_path;
285 const char *job_type;
286 const char *job_path;
289 static int compare_unit_info(const void *a, const void *b) {
291 const struct unit_info *u = a, *v = b;
293 d1 = strrchr(u->id, '.');
294 d2 = strrchr(v->id, '.');
299 if ((r = strcasecmp(d1, d2)) != 0)
303 return strcasecmp(u->id, v->id);
306 static bool output_show_unit(const struct unit_info *u) {
310 return streq(u->active_state, "failed");
312 return (!arg_type || ((dot = strrchr(u->id, '.')) &&
313 streq(dot+1, arg_type))) &&
314 (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
317 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
318 unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
319 const struct unit_info *u;
321 max_id_len = sizeof("UNIT")-1;
322 active_len = sizeof("ACTIVE")-1;
323 sub_len = sizeof("SUB")-1;
324 job_len = sizeof("JOB")-1;
327 for (u = unit_infos; u < unit_infos + c; u++) {
328 if (!output_show_unit(u))
331 max_id_len = MAX(max_id_len, strlen(u->id));
332 active_len = MAX(active_len, strlen(u->active_state));
333 sub_len = MAX(sub_len, strlen(u->sub_state));
335 job_len = MAX(job_len, strlen(u->job_type));
340 id_len = MIN(max_id_len, 25);
341 basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
342 if (basic_len < (unsigned) columns()) {
343 unsigned extra_len, incr;
344 extra_len = columns() - basic_len;
345 /* Either UNIT already got 25, or is fully satisfied.
346 * Grant up to 25 to DESC now. */
347 incr = MIN(extra_len, 25);
350 /* split the remaining space between UNIT and DESC,
351 * but do not give UNIT more than it needs. */
353 incr = MIN(extra_len / 2, max_id_len - id_len);
355 desc_len += extra_len - incr;
361 if (!arg_no_legend) {
362 printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
363 active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
364 if (!arg_full && arg_no_pager)
365 printf("%.*s\n", desc_len, "DESCRIPTION");
367 printf("%s\n", "DESCRIPTION");
370 for (u = unit_infos; u < unit_infos + c; u++) {
372 const char *on_loaded, *off_loaded;
373 const char *on_active, *off_active;
375 if (!output_show_unit(u))
380 if (!streq(u->load_state, "loaded") &&
381 !streq(u->load_state, "banned")) {
382 on_loaded = ansi_highlight(true);
383 off_loaded = ansi_highlight(false);
385 on_loaded = off_loaded = "";
387 if (streq(u->active_state, "failed")) {
388 on_active = ansi_highlight(true);
389 off_active = ansi_highlight(false);
391 on_active = off_active = "";
393 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
395 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
396 id_len, e ? e : u->id,
397 on_loaded, u->load_state, off_loaded,
398 on_active, active_len, u->active_state,
399 sub_len, u->sub_state, off_active,
400 job_len, u->job_id ? u->job_type : "");
401 if (!arg_full && arg_no_pager)
402 printf("%.*s\n", desc_len, u->description);
404 printf("%s\n", u->description);
409 if (!arg_no_legend) {
410 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
411 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
412 "SUB = The low-level unit activation state, values depend on unit type.\n"
413 "JOB = Pending job for the unit.\n");
416 printf("\n%u units listed.\n", n_shown);
418 printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
422 static int list_units(DBusConnection *bus, char **args) {
423 DBusMessage *m = NULL, *reply = NULL;
426 DBusMessageIter iter, sub, sub2;
427 unsigned c = 0, n_units = 0;
428 struct unit_info *unit_infos = NULL;
430 dbus_error_init(&error);
434 pager_open_if_enabled();
436 if (!(m = dbus_message_new_method_call(
437 "org.freedesktop.systemd1",
438 "/org/freedesktop/systemd1",
439 "org.freedesktop.systemd1.Manager",
441 log_error("Could not allocate message.");
445 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
446 log_error("Failed to issue method call: %s", bus_error_message(&error));
451 if (!dbus_message_iter_init(reply, &iter) ||
452 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
453 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
454 log_error("Failed to parse reply.");
459 dbus_message_iter_recurse(&iter, &sub);
461 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
464 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
465 log_error("Failed to parse reply.");
473 n_units = MAX(2*c, 16);
474 w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
477 log_error("Failed to allocate unit array.");
487 dbus_message_iter_recurse(&sub, &sub2);
489 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
490 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
491 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
492 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
493 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
494 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
495 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
496 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
497 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
498 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
499 log_error("Failed to parse reply.");
504 dbus_message_iter_next(&sub);
509 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
510 output_units_list(unit_infos, c);
517 dbus_message_unref(m);
520 dbus_message_unref(reply);
524 dbus_error_free(&error);
529 static int compare_unit_file_list(const void *a, const void *b) {
531 const UnitFileList *u = a, *v = b;
533 d1 = strrchr(u->path, '.');
534 d2 = strrchr(v->path, '.');
539 r = strcasecmp(d1, d2);
544 return strcasecmp(file_name_from_path(u->path), file_name_from_path(v->path));
547 static bool output_show_unit_file(const UnitFileList *u) {
550 return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
553 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
554 unsigned n_shown = 0;
555 const UnitFileList *u;
558 printf("%-25s %-6s\n", "UNIT FILE", "STATE");
560 for (u = units; u < units + c; u++) {
562 const char *on, *off;
565 if (!output_show_unit_file(u))
570 if (u->state == UNIT_FILE_MASKED ||
571 u->state == UNIT_FILE_MASKED_RUNTIME ||
572 u->state == UNIT_FILE_DISABLED) {
573 on = ansi_highlight(true);
574 off = ansi_highlight(false);
575 } else if (u->state == UNIT_FILE_ENABLED) {
576 on = ansi_highlight_green(true);
577 off = ansi_highlight_green(false);
581 id = file_name_from_path(u->path);
583 e = arg_full ? NULL : ellipsize(id, 25, 33);
585 printf("%-25s %s%-6s%s\n",
587 on, unit_file_state_to_string(u->state), off);
593 printf("\n%u unit files listed.\n", n_shown);
596 static int list_unit_files(DBusConnection *bus, char **args) {
597 DBusMessage *m = NULL, *reply = NULL;
600 DBusMessageIter iter, sub, sub2;
601 unsigned c = 0, n_units = 0;
602 UnitFileList *units = NULL;
604 dbus_error_init(&error);
608 pager_open_if_enabled();
615 h = hashmap_new(string_hash_func, string_compare_func);
617 log_error("Out of memory");
621 r = unit_file_get_list(arg_scope, arg_root, h);
623 unit_file_list_free(h);
624 log_error("Failed to get unit file list: %s", strerror(-r));
628 n_units = hashmap_size(h);
629 units = new(UnitFileList, n_units);
631 unit_file_list_free(h);
632 log_error("Out of memory");
636 HASHMAP_FOREACH(u, h, i) {
637 memcpy(units + c++, u, sizeof(UnitFileList));
643 m = dbus_message_new_method_call(
644 "org.freedesktop.systemd1",
645 "/org/freedesktop/systemd1",
646 "org.freedesktop.systemd1.Manager",
649 log_error("Could not allocate message.");
653 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
655 log_error("Failed to issue method call: %s", bus_error_message(&error));
660 if (!dbus_message_iter_init(reply, &iter) ||
661 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
662 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
663 log_error("Failed to parse reply.");
668 dbus_message_iter_recurse(&iter, &sub);
670 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
674 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
675 log_error("Failed to parse reply.");
683 n_units = MAX(2*c, 16);
684 w = realloc(units, sizeof(struct UnitFileList) * n_units);
687 log_error("Failed to allocate unit array.");
697 dbus_message_iter_recurse(&sub, &sub2);
699 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
700 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
701 log_error("Failed to parse reply.");
706 u->state = unit_file_state_from_string(state);
708 dbus_message_iter_next(&sub);
714 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
715 output_unit_file_list(units, c);
722 dbus_message_unref(m);
725 dbus_message_unref(reply);
729 dbus_error_free(&error);
734 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
735 static const char * const colors[] = {
736 "Requires", "[color=\"black\"]",
737 "RequiresOverridable", "[color=\"black\"]",
738 "Requisite", "[color=\"darkblue\"]",
739 "RequisiteOverridable", "[color=\"darkblue\"]",
740 "Wants", "[color=\"darkgrey\"]",
741 "Conflicts", "[color=\"red\"]",
742 "ConflictedBy", "[color=\"red\"]",
743 "After", "[color=\"green\"]"
746 const char *c = NULL;
753 for (i = 0; i < ELEMENTSOF(colors); i += 2)
754 if (streq(colors[i], prop)) {
762 if (arg_dot != DOT_ALL)
763 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
766 switch (dbus_message_iter_get_arg_type(iter)) {
768 case DBUS_TYPE_ARRAY:
770 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
773 dbus_message_iter_recurse(iter, &sub);
775 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
778 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
779 dbus_message_iter_get_basic(&sub, &s);
780 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
782 dbus_message_iter_next(&sub);
792 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
793 DBusMessage *m = NULL, *reply = NULL;
794 const char *interface = "org.freedesktop.systemd1.Unit";
797 DBusMessageIter iter, sub, sub2, sub3;
802 dbus_error_init(&error);
804 if (!(m = dbus_message_new_method_call(
805 "org.freedesktop.systemd1",
807 "org.freedesktop.DBus.Properties",
809 log_error("Could not allocate message.");
814 if (!dbus_message_append_args(m,
815 DBUS_TYPE_STRING, &interface,
816 DBUS_TYPE_INVALID)) {
817 log_error("Could not append arguments to message.");
822 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
823 log_error("Failed to issue method call: %s", bus_error_message(&error));
828 if (!dbus_message_iter_init(reply, &iter) ||
829 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
830 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
831 log_error("Failed to parse reply.");
836 dbus_message_iter_recurse(&iter, &sub);
838 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
841 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
842 log_error("Failed to parse reply.");
847 dbus_message_iter_recurse(&sub, &sub2);
849 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
850 log_error("Failed to parse reply.");
855 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
856 log_error("Failed to parse reply.");
861 dbus_message_iter_recurse(&sub2, &sub3);
863 if (dot_one_property(name, prop, &sub3)) {
864 log_error("Failed to parse reply.");
869 dbus_message_iter_next(&sub);
876 dbus_message_unref(m);
879 dbus_message_unref(reply);
881 dbus_error_free(&error);
886 static int dot(DBusConnection *bus, char **args) {
887 DBusMessage *m = NULL, *reply = NULL;
890 DBusMessageIter iter, sub, sub2;
892 dbus_error_init(&error);
896 if (!(m = dbus_message_new_method_call(
897 "org.freedesktop.systemd1",
898 "/org/freedesktop/systemd1",
899 "org.freedesktop.systemd1.Manager",
901 log_error("Could not allocate message.");
905 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
906 log_error("Failed to issue method call: %s", bus_error_message(&error));
911 if (!dbus_message_iter_init(reply, &iter) ||
912 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
913 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
914 log_error("Failed to parse reply.");
919 printf("digraph systemd {\n");
921 dbus_message_iter_recurse(&iter, &sub);
922 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
923 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
925 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
926 log_error("Failed to parse reply.");
931 dbus_message_iter_recurse(&sub, &sub2);
933 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
934 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
935 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
936 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
937 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
938 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
939 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
940 log_error("Failed to parse reply.");
945 if ((r = dot_one(bus, id, unit_path)) < 0)
948 /* printf("\t\"%s\";\n", id); */
949 dbus_message_iter_next(&sub);
954 log_info(" Color legend: black = Requires\n"
955 " dark blue = Requisite\n"
956 " dark grey = Wants\n"
961 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
962 "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
968 dbus_message_unref(m);
971 dbus_message_unref(reply);
973 dbus_error_free(&error);
978 static int list_jobs(DBusConnection *bus, char **args) {
979 DBusMessage *m = NULL, *reply = NULL;
982 DBusMessageIter iter, sub, sub2;
985 dbus_error_init(&error);
989 pager_open_if_enabled();
991 if (!(m = dbus_message_new_method_call(
992 "org.freedesktop.systemd1",
993 "/org/freedesktop/systemd1",
994 "org.freedesktop.systemd1.Manager",
996 log_error("Could not allocate message.");
1000 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1001 log_error("Failed to issue method call: %s", bus_error_message(&error));
1006 if (!dbus_message_iter_init(reply, &iter) ||
1007 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1008 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1009 log_error("Failed to parse reply.");
1014 dbus_message_iter_recurse(&iter, &sub);
1017 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1019 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1020 const char *name, *type, *state, *job_path, *unit_path;
1024 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1025 log_error("Failed to parse reply.");
1030 dbus_message_iter_recurse(&sub, &sub2);
1032 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1033 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1034 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1035 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1036 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1037 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1038 log_error("Failed to parse reply.");
1043 e = arg_full ? NULL : ellipsize(name, 25, 33);
1044 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1049 dbus_message_iter_next(&sub);
1053 printf("\n%u jobs listed.\n", k);
1059 dbus_message_unref(m);
1062 dbus_message_unref(reply);
1064 dbus_error_free(&error);
1069 static int load_unit(DBusConnection *bus, char **args) {
1070 DBusMessage *m = NULL;
1075 dbus_error_init(&error);
1080 STRV_FOREACH(name, args+1) {
1083 if (!(m = dbus_message_new_method_call(
1084 "org.freedesktop.systemd1",
1085 "/org/freedesktop/systemd1",
1086 "org.freedesktop.systemd1.Manager",
1088 log_error("Could not allocate message.");
1093 if (!dbus_message_append_args(m,
1094 DBUS_TYPE_STRING, name,
1095 DBUS_TYPE_INVALID)) {
1096 log_error("Could not append arguments to message.");
1101 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1102 log_error("Failed to issue method call: %s", bus_error_message(&error));
1107 dbus_message_unref(m);
1108 dbus_message_unref(reply);
1117 dbus_message_unref(m);
1119 dbus_error_free(&error);
1124 static int cancel_job(DBusConnection *bus, char **args) {
1125 DBusMessage *m = NULL, *reply = NULL;
1130 dbus_error_init(&error);
1135 if (strv_length(args) <= 1)
1136 return daemon_reload(bus, args);
1138 STRV_FOREACH(name, args+1) {
1142 if (!(m = dbus_message_new_method_call(
1143 "org.freedesktop.systemd1",
1144 "/org/freedesktop/systemd1",
1145 "org.freedesktop.systemd1.Manager",
1147 log_error("Could not allocate message.");
1152 if ((r = safe_atou(*name, &id)) < 0) {
1153 log_error("Failed to parse job id: %s", strerror(-r));
1157 assert_cc(sizeof(uint32_t) == sizeof(id));
1158 if (!dbus_message_append_args(m,
1159 DBUS_TYPE_UINT32, &id,
1160 DBUS_TYPE_INVALID)) {
1161 log_error("Could not append arguments to message.");
1166 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1167 log_error("Failed to issue method call: %s", bus_error_message(&error));
1172 if (!dbus_message_get_args(reply, &error,
1173 DBUS_TYPE_OBJECT_PATH, &path,
1174 DBUS_TYPE_INVALID)) {
1175 log_error("Failed to parse reply: %s", bus_error_message(&error));
1180 dbus_message_unref(m);
1181 if (!(m = dbus_message_new_method_call(
1182 "org.freedesktop.systemd1",
1184 "org.freedesktop.systemd1.Job",
1186 log_error("Could not allocate message.");
1191 dbus_message_unref(reply);
1192 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1193 log_error("Failed to issue method call: %s", bus_error_message(&error));
1198 dbus_message_unref(m);
1199 dbus_message_unref(reply);
1207 dbus_message_unref(m);
1210 dbus_message_unref(reply);
1212 dbus_error_free(&error);
1217 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1218 DBusMessage *m = NULL, *reply = NULL;
1219 dbus_bool_t b = FALSE;
1220 DBusMessageIter iter, sub;
1222 *interface = "org.freedesktop.systemd1.Unit",
1223 *property = "NeedDaemonReload",
1226 /* We ignore all errors here, since this is used to show a warning only */
1228 if (!(m = dbus_message_new_method_call(
1229 "org.freedesktop.systemd1",
1230 "/org/freedesktop/systemd1",
1231 "org.freedesktop.systemd1.Manager",
1235 if (!dbus_message_append_args(m,
1236 DBUS_TYPE_STRING, &unit,
1240 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1243 if (!dbus_message_get_args(reply, NULL,
1244 DBUS_TYPE_OBJECT_PATH, &path,
1248 dbus_message_unref(m);
1249 if (!(m = dbus_message_new_method_call(
1250 "org.freedesktop.systemd1",
1252 "org.freedesktop.DBus.Properties",
1256 if (!dbus_message_append_args(m,
1257 DBUS_TYPE_STRING, &interface,
1258 DBUS_TYPE_STRING, &property,
1259 DBUS_TYPE_INVALID)) {
1263 dbus_message_unref(reply);
1264 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1267 if (!dbus_message_iter_init(reply, &iter) ||
1268 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1271 dbus_message_iter_recurse(&iter, &sub);
1273 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1276 dbus_message_iter_get_basic(&sub, &b);
1280 dbus_message_unref(m);
1283 dbus_message_unref(reply);
1288 typedef struct WaitData {
1293 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1301 dbus_error_init(&error);
1303 log_debug("Got D-Bus request: %s.%s() on %s",
1304 dbus_message_get_interface(message),
1305 dbus_message_get_member(message),
1306 dbus_message_get_path(message));
1308 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1309 log_error("Warning! D-Bus connection terminated.");
1310 dbus_connection_close(connection);
1312 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1314 const char *path, *result;
1315 dbus_bool_t success = true;
1317 if (dbus_message_get_args(message, &error,
1318 DBUS_TYPE_UINT32, &id,
1319 DBUS_TYPE_OBJECT_PATH, &path,
1320 DBUS_TYPE_STRING, &result,
1321 DBUS_TYPE_INVALID)) {
1324 if ((p = set_remove(d->set, (char*) path)))
1328 d->result = strdup(result);
1333 dbus_error_free(&error);
1335 if (dbus_message_get_args(message, &error,
1336 DBUS_TYPE_UINT32, &id,
1337 DBUS_TYPE_OBJECT_PATH, &path,
1338 DBUS_TYPE_BOOLEAN, &success,
1339 DBUS_TYPE_INVALID)) {
1342 /* Compatibility with older systemd versions <
1343 * 19 during upgrades. This should be dropped
1346 if ((p = set_remove(d->set, (char*) path)))
1350 d->result = strdup("failed");
1356 log_error("Failed to parse message: %s", bus_error_message(&error));
1360 dbus_error_free(&error);
1361 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1364 static int enable_wait_for_jobs(DBusConnection *bus) {
1372 dbus_error_init(&error);
1373 dbus_bus_add_match(bus,
1375 "sender='org.freedesktop.systemd1',"
1376 "interface='org.freedesktop.systemd1.Manager',"
1377 "member='JobRemoved',"
1378 "path='/org/freedesktop/systemd1'",
1381 if (dbus_error_is_set(&error)) {
1382 log_error("Failed to add match: %s", bus_error_message(&error));
1383 dbus_error_free(&error);
1387 /* This is slightly dirty, since we don't undo the match registrations. */
1391 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1401 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1402 log_error("Failed to add filter.");
1407 while (!set_isempty(s) &&
1408 dbus_connection_read_write_dispatch(bus, -1))
1411 if (!arg_quiet && d.result) {
1412 if (streq(d.result, "timeout"))
1413 log_error("Job timed out.");
1414 else if (streq(d.result, "canceled"))
1415 log_error("Job canceled.");
1416 else if (streq(d.result, "dependency"))
1417 log_error("A dependency job failed. See system logs for details.");
1418 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1419 log_error("Job failed. See system logs and 'systemctl status' for details.");
1422 if (streq_ptr(d.result, "timeout"))
1424 else if (streq_ptr(d.result, "canceled"))
1426 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1434 /* This is slightly dirty, since we don't undo the filter registration. */
1439 static int start_unit_one(
1440 DBusConnection *bus,
1447 DBusMessage *m = NULL, *reply = NULL;
1456 assert(arg_no_block || s);
1458 if (!(m = dbus_message_new_method_call(
1459 "org.freedesktop.systemd1",
1460 "/org/freedesktop/systemd1",
1461 "org.freedesktop.systemd1.Manager",
1463 log_error("Could not allocate message.");
1468 if (!dbus_message_append_args(m,
1469 DBUS_TYPE_STRING, &name,
1470 DBUS_TYPE_STRING, &mode,
1471 DBUS_TYPE_INVALID)) {
1472 log_error("Could not append arguments to message.");
1477 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1479 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1480 /* There's always a fallback possible for
1481 * legacy actions. */
1486 log_error("Failed to issue method call: %s", bus_error_message(error));
1491 if (!dbus_message_get_args(reply, error,
1492 DBUS_TYPE_OBJECT_PATH, &path,
1493 DBUS_TYPE_INVALID)) {
1494 log_error("Failed to parse reply: %s", bus_error_message(error));
1499 if (need_daemon_reload(bus, name))
1500 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1501 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1503 if (!arg_no_block) {
1506 if (!(p = strdup(path))) {
1507 log_error("Failed to duplicate path.");
1512 if ((r = set_put(s, p)) < 0) {
1514 log_error("Failed to add path to set.");
1523 dbus_message_unref(m);
1526 dbus_message_unref(reply);
1531 static enum action verb_to_action(const char *verb) {
1532 if (streq(verb, "halt"))
1534 else if (streq(verb, "poweroff"))
1535 return ACTION_POWEROFF;
1536 else if (streq(verb, "reboot"))
1537 return ACTION_REBOOT;
1538 else if (streq(verb, "kexec"))
1539 return ACTION_KEXEC;
1540 else if (streq(verb, "rescue"))
1541 return ACTION_RESCUE;
1542 else if (streq(verb, "emergency"))
1543 return ACTION_EMERGENCY;
1544 else if (streq(verb, "default"))
1545 return ACTION_DEFAULT;
1546 else if (streq(verb, "exit"))
1549 return ACTION_INVALID;
1552 static int start_unit(DBusConnection *bus, char **args) {
1554 static const char * const table[_ACTION_MAX] = {
1555 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1556 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1557 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1558 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1559 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1560 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1561 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1562 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1563 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1564 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1565 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1566 [ACTION_EXIT] = SPECIAL_EXIT_TARGET
1570 const char *method, *mode, *one_name;
1575 dbus_error_init(&error);
1579 agent_open_if_enabled();
1581 if (arg_action == ACTION_SYSTEMCTL) {
1583 streq(args[0], "stop") ||
1584 streq(args[0], "condstop") ? "StopUnit" :
1585 streq(args[0], "reload") ? "ReloadUnit" :
1586 streq(args[0], "restart") ? "RestartUnit" :
1588 streq(args[0], "try-restart") ||
1589 streq(args[0], "condrestart") ? "TryRestartUnit" :
1591 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1593 streq(args[0], "reload-or-try-restart") ||
1594 streq(args[0], "condreload") ||
1596 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1600 (streq(args[0], "isolate") ||
1601 streq(args[0], "rescue") ||
1602 streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1604 one_name = table[verb_to_action(args[0])];
1607 assert(arg_action < ELEMENTSOF(table));
1608 assert(table[arg_action]);
1610 method = "StartUnit";
1612 mode = (arg_action == ACTION_EMERGENCY ||
1613 arg_action == ACTION_RESCUE ||
1614 arg_action == ACTION_RUNLEVEL2 ||
1615 arg_action == ACTION_RUNLEVEL3 ||
1616 arg_action == ACTION_RUNLEVEL4 ||
1617 arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1619 one_name = table[arg_action];
1622 if (!arg_no_block) {
1623 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1624 log_error("Could not watch jobs: %s", strerror(-ret));
1628 if (!(s = set_new(string_hash_func, string_compare_func))) {
1629 log_error("Failed to allocate set.");
1636 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1639 STRV_FOREACH(name, args+1)
1640 if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1641 ret = translate_bus_error_to_exit_status(r, &error);
1642 dbus_error_free(&error);
1647 if ((r = wait_for_jobs(bus, s)) < 0) {
1656 dbus_error_free(&error);
1661 static int start_special(DBusConnection *bus, char **args) {
1668 (streq(args[0], "halt") ||
1669 streq(args[0], "poweroff") ||
1670 streq(args[0], "reboot") ||
1671 streq(args[0], "kexec") ||
1672 streq(args[0], "exit")))
1673 return daemon_reload(bus, args);
1675 r = start_unit(bus, args);
1678 warn_wall(verb_to_action(args[0]));
1683 static int check_unit(DBusConnection *bus, char **args) {
1684 DBusMessage *m = NULL, *reply = NULL;
1686 *interface = "org.freedesktop.systemd1.Unit",
1687 *property = "ActiveState";
1688 int r = 3; /* According to LSB: "program is not running" */
1695 dbus_error_init(&error);
1697 STRV_FOREACH(name, args+1) {
1698 const char *path = NULL;
1700 DBusMessageIter iter, sub;
1702 if (!(m = dbus_message_new_method_call(
1703 "org.freedesktop.systemd1",
1704 "/org/freedesktop/systemd1",
1705 "org.freedesktop.systemd1.Manager",
1707 log_error("Could not allocate message.");
1712 if (!dbus_message_append_args(m,
1713 DBUS_TYPE_STRING, name,
1714 DBUS_TYPE_INVALID)) {
1715 log_error("Could not append arguments to message.");
1720 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1722 /* Hmm, cannot figure out anything about this unit... */
1726 dbus_error_free(&error);
1727 dbus_message_unref(m);
1732 if (!dbus_message_get_args(reply, &error,
1733 DBUS_TYPE_OBJECT_PATH, &path,
1734 DBUS_TYPE_INVALID)) {
1735 log_error("Failed to parse reply: %s", bus_error_message(&error));
1740 dbus_message_unref(m);
1741 if (!(m = dbus_message_new_method_call(
1742 "org.freedesktop.systemd1",
1744 "org.freedesktop.DBus.Properties",
1746 log_error("Could not allocate message.");
1751 if (!dbus_message_append_args(m,
1752 DBUS_TYPE_STRING, &interface,
1753 DBUS_TYPE_STRING, &property,
1754 DBUS_TYPE_INVALID)) {
1755 log_error("Could not append arguments to message.");
1760 dbus_message_unref(reply);
1761 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1762 log_error("Failed to issue method call: %s", bus_error_message(&error));
1767 if (!dbus_message_iter_init(reply, &iter) ||
1768 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1769 log_error("Failed to parse reply.");
1774 dbus_message_iter_recurse(&iter, &sub);
1776 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1777 log_error("Failed to parse reply.");
1782 dbus_message_iter_get_basic(&sub, &state);
1787 if (streq(state, "active") || streq(state, "reloading"))
1790 dbus_message_unref(m);
1791 dbus_message_unref(reply);
1797 dbus_message_unref(m);
1800 dbus_message_unref(reply);
1802 dbus_error_free(&error);
1807 static int kill_unit(DBusConnection *bus, char **args) {
1808 DBusMessage *m = NULL;
1816 dbus_error_init(&error);
1819 arg_kill_who = "all";
1822 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
1824 STRV_FOREACH(name, args+1) {
1827 if (!(m = dbus_message_new_method_call(
1828 "org.freedesktop.systemd1",
1829 "/org/freedesktop/systemd1",
1830 "org.freedesktop.systemd1.Manager",
1832 log_error("Could not allocate message.");
1837 if (!dbus_message_append_args(m,
1838 DBUS_TYPE_STRING, name,
1839 DBUS_TYPE_STRING, &arg_kill_who,
1840 DBUS_TYPE_STRING, &arg_kill_mode,
1841 DBUS_TYPE_INT32, &arg_signal,
1842 DBUS_TYPE_INVALID)) {
1843 log_error("Could not append arguments to message.");
1848 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1849 log_error("Failed to issue method call: %s", bus_error_message(&error));
1850 dbus_error_free(&error);
1854 dbus_message_unref(m);
1857 dbus_message_unref(reply);
1863 dbus_message_unref(m);
1865 dbus_error_free(&error);
1870 typedef struct ExecStatusInfo {
1878 usec_t start_timestamp;
1879 usec_t exit_timestamp;
1884 LIST_FIELDS(struct ExecStatusInfo, exec);
1887 static void exec_status_info_free(ExecStatusInfo *i) {
1896 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1897 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
1898 DBusMessageIter sub2, sub3;
1902 int32_t code, status;
1908 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1911 dbus_message_iter_recurse(sub, &sub2);
1913 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1916 if (!(i->path = strdup(path)))
1919 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1920 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1924 dbus_message_iter_recurse(&sub2, &sub3);
1925 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1926 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1927 dbus_message_iter_next(&sub3);
1932 if (!(i->argv = new0(char*, n+1)))
1936 dbus_message_iter_recurse(&sub2, &sub3);
1937 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1940 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1941 dbus_message_iter_get_basic(&sub3, &s);
1942 dbus_message_iter_next(&sub3);
1944 if (!(i->argv[n++] = strdup(s)))
1948 if (!dbus_message_iter_next(&sub2) ||
1949 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1950 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1951 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
1952 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1953 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
1954 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1955 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1956 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1960 i->start_timestamp = (usec_t) start_timestamp;
1961 i->exit_timestamp = (usec_t) exit_timestamp;
1962 i->pid = (pid_t) pid;
1969 typedef struct UnitStatusInfo {
1971 const char *load_state;
1972 const char *active_state;
1973 const char *sub_state;
1974 const char *unit_file_state;
1976 const char *description;
1977 const char *following;
1980 const char *default_control_group;
1982 const char *load_error;
1984 usec_t inactive_exit_timestamp;
1985 usec_t active_enter_timestamp;
1986 usec_t active_exit_timestamp;
1987 usec_t inactive_enter_timestamp;
1989 bool need_daemon_reload;
1994 const char *status_text;
1996 #ifdef HAVE_SYSV_COMPAT
2000 usec_t start_timestamp;
2001 usec_t exit_timestamp;
2003 int exit_code, exit_status;
2005 usec_t condition_timestamp;
2006 bool condition_result;
2009 unsigned n_accepted;
2010 unsigned n_connections;
2014 const char *sysfs_path;
2016 /* Mount, Automount */
2022 LIST_HEAD(ExecStatusInfo, exec);
2025 static void print_status_info(UnitStatusInfo *i) {
2027 const char *on, *off, *ss;
2029 char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2030 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2034 /* This shows pretty information about a unit. See
2035 * print_property() for a low-level property printer */
2037 printf("%s", strna(i->id));
2039 if (i->description && !streq_ptr(i->id, i->description))
2040 printf(" - %s", i->description);
2045 printf("\t Follow: unit currently follows state of %s\n", i->following);
2047 if (streq_ptr(i->load_state, "failed") ||
2048 streq_ptr(i->load_state, "banned")) {
2049 on = ansi_highlight(true);
2050 off = ansi_highlight(false);
2055 printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2056 else if (i->path && i->unit_file_state)
2057 printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state);
2059 printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
2061 printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off);
2063 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2065 if (streq_ptr(i->active_state, "failed")) {
2066 on = ansi_highlight(true);
2067 off = ansi_highlight(false);
2068 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2069 on = ansi_highlight_green(true);
2070 off = ansi_highlight_green(false);
2075 printf("\t Active: %s%s (%s)%s",
2077 strna(i->active_state),
2081 printf("\t Active: %s%s%s",
2083 strna(i->active_state),
2086 timestamp = (streq_ptr(i->active_state, "active") ||
2087 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2088 (streq_ptr(i->active_state, "inactive") ||
2089 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2090 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2091 i->active_exit_timestamp;
2093 s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2094 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2097 printf(" since %s; %s\n", s2, s1);
2099 printf(" since %s\n", s2);
2103 if (!i->condition_result && i->condition_timestamp > 0) {
2104 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2105 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2108 printf("\t start condition failed at %s; %s\n", s2, s1);
2110 printf("\t start condition failed at %s\n", s2);
2114 printf("\t Device: %s\n", i->sysfs_path);
2116 printf("\t Where: %s\n", i->where);
2118 printf("\t What: %s\n", i->what);
2121 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2123 LIST_FOREACH(exec, p, i->exec) {
2127 /* Only show exited processes here */
2131 t = strv_join(p->argv, " ");
2132 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2135 #ifdef HAVE_SYSV_COMPAT
2137 good = is_clean_exit_lsb(p->code, p->status);
2140 good = is_clean_exit(p->code, p->status);
2143 on = ansi_highlight(true);
2144 off = ansi_highlight(false);
2148 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2150 if (p->code == CLD_EXITED) {
2153 printf("status=%i", p->status);
2155 #ifdef HAVE_SYSV_COMPAT
2156 if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2158 if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
2163 printf("signal=%s", signal_to_string(p->status));
2165 printf(")%s\n", off);
2167 if (i->main_pid == p->pid &&
2168 i->start_timestamp == p->start_timestamp &&
2169 i->exit_timestamp == p->start_timestamp)
2170 /* Let's not show this twice */
2173 if (p->pid == i->control_pid)
2177 if (i->main_pid > 0 || i->control_pid > 0) {
2180 if (i->main_pid > 0) {
2181 printf("Main PID: %u", (unsigned) i->main_pid);
2185 get_process_name(i->main_pid, &t);
2190 } else if (i->exit_code > 0) {
2191 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2193 if (i->exit_code == CLD_EXITED) {
2196 printf("status=%i", i->exit_status);
2198 #ifdef HAVE_SYSV_COMPAT
2199 if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2201 if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
2206 printf("signal=%s", signal_to_string(i->exit_status));
2211 if (i->main_pid > 0 && i->control_pid > 0)
2214 if (i->control_pid > 0) {
2217 printf(" Control: %u", (unsigned) i->control_pid);
2219 get_process_name(i->control_pid, &t);
2230 printf("\t Status: \"%s\"\n", i->status_text);
2232 if (i->default_control_group) {
2235 printf("\t CGroup: %s\n", i->default_control_group);
2237 if (arg_transport != TRANSPORT_SSH) {
2238 if ((c = columns()) > 18)
2243 show_cgroup_by_path(i->default_control_group, "\t\t ", c);
2247 if (i->need_daemon_reload)
2248 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2249 ansi_highlight(true),
2250 ansi_highlight(false),
2251 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2254 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2260 switch (dbus_message_iter_get_arg_type(iter)) {
2262 case DBUS_TYPE_STRING: {
2265 dbus_message_iter_get_basic(iter, &s);
2268 if (streq(name, "Id"))
2270 else if (streq(name, "LoadState"))
2272 else if (streq(name, "ActiveState"))
2273 i->active_state = s;
2274 else if (streq(name, "SubState"))
2276 else if (streq(name, "Description"))
2278 else if (streq(name, "FragmentPath"))
2280 #ifdef HAVE_SYSV_COMPAT
2281 else if (streq(name, "SysVPath")) {
2286 else if (streq(name, "DefaultControlGroup"))
2287 i->default_control_group = s;
2288 else if (streq(name, "StatusText"))
2290 else if (streq(name, "SysFSPath"))
2292 else if (streq(name, "Where"))
2294 else if (streq(name, "What"))
2296 else if (streq(name, "Following"))
2298 else if (streq(name, "UnitFileState"))
2299 i->unit_file_state = s;
2305 case DBUS_TYPE_BOOLEAN: {
2308 dbus_message_iter_get_basic(iter, &b);
2310 if (streq(name, "Accept"))
2312 else if (streq(name, "NeedDaemonReload"))
2313 i->need_daemon_reload = b;
2314 else if (streq(name, "ConditionResult"))
2315 i->condition_result = b;
2320 case DBUS_TYPE_UINT32: {
2323 dbus_message_iter_get_basic(iter, &u);
2325 if (streq(name, "MainPID")) {
2327 i->main_pid = (pid_t) u;
2330 } else if (streq(name, "ControlPID"))
2331 i->control_pid = (pid_t) u;
2332 else if (streq(name, "ExecMainPID")) {
2334 i->main_pid = (pid_t) u;
2335 } else if (streq(name, "NAccepted"))
2337 else if (streq(name, "NConnections"))
2338 i->n_connections = u;
2343 case DBUS_TYPE_INT32: {
2346 dbus_message_iter_get_basic(iter, &j);
2348 if (streq(name, "ExecMainCode"))
2349 i->exit_code = (int) j;
2350 else if (streq(name, "ExecMainStatus"))
2351 i->exit_status = (int) j;
2356 case DBUS_TYPE_UINT64: {
2359 dbus_message_iter_get_basic(iter, &u);
2361 if (streq(name, "ExecMainStartTimestamp"))
2362 i->start_timestamp = (usec_t) u;
2363 else if (streq(name, "ExecMainExitTimestamp"))
2364 i->exit_timestamp = (usec_t) u;
2365 else if (streq(name, "ActiveEnterTimestamp"))
2366 i->active_enter_timestamp = (usec_t) u;
2367 else if (streq(name, "InactiveEnterTimestamp"))
2368 i->inactive_enter_timestamp = (usec_t) u;
2369 else if (streq(name, "InactiveExitTimestamp"))
2370 i->inactive_exit_timestamp = (usec_t) u;
2371 else if (streq(name, "ActiveExitTimestamp"))
2372 i->active_exit_timestamp = (usec_t) u;
2373 else if (streq(name, "ConditionTimestamp"))
2374 i->condition_timestamp = (usec_t) u;
2379 case DBUS_TYPE_ARRAY: {
2381 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2382 startswith(name, "Exec")) {
2383 DBusMessageIter sub;
2385 dbus_message_iter_recurse(iter, &sub);
2386 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2387 ExecStatusInfo *info;
2390 if (!(info = new0(ExecStatusInfo, 1)))
2393 if (!(info->name = strdup(name))) {
2398 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2403 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2405 dbus_message_iter_next(&sub);
2412 case DBUS_TYPE_STRUCT: {
2414 if (streq(name, "LoadError")) {
2415 DBusMessageIter sub;
2416 const char *n, *message;
2419 dbus_message_iter_recurse(iter, &sub);
2421 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2425 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2429 if (!isempty(message))
2430 i->load_error = message;
2440 static int print_property(const char *name, DBusMessageIter *iter) {
2444 /* This is a low-level property printer, see
2445 * print_status_info() for the nicer output */
2447 if (arg_property && !strv_find(arg_property, name))
2450 switch (dbus_message_iter_get_arg_type(iter)) {
2452 case DBUS_TYPE_STRUCT: {
2453 DBusMessageIter sub;
2454 dbus_message_iter_recurse(iter, &sub);
2456 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2459 dbus_message_iter_get_basic(&sub, &u);
2462 printf("%s=%u\n", name, (unsigned) u);
2464 printf("%s=\n", name);
2467 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2470 dbus_message_iter_get_basic(&sub, &s);
2472 if (arg_all || s[0])
2473 printf("%s=%s\n", name, s);
2476 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2477 const char *a = NULL, *b = NULL;
2479 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2480 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2482 if (arg_all || !isempty(a) || !isempty(b))
2483 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2491 case DBUS_TYPE_ARRAY:
2493 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2494 DBusMessageIter sub, sub2;
2496 dbus_message_iter_recurse(iter, &sub);
2497 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2501 dbus_message_iter_recurse(&sub, &sub2);
2503 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2504 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2505 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2507 dbus_message_iter_next(&sub);
2512 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2513 DBusMessageIter sub, sub2;
2515 dbus_message_iter_recurse(iter, &sub);
2516 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2517 const char *type, *path;
2519 dbus_message_iter_recurse(&sub, &sub2);
2521 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2522 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2523 printf("%s=%s\n", type, path);
2525 dbus_message_iter_next(&sub);
2530 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2531 DBusMessageIter sub, sub2;
2533 dbus_message_iter_recurse(iter, &sub);
2534 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2536 uint64_t value, next_elapse;
2538 dbus_message_iter_recurse(&sub, &sub2);
2540 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2541 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2542 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2543 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2545 printf("%s={ value=%s ; next_elapse=%s }\n",
2547 format_timespan(timespan1, sizeof(timespan1), value),
2548 format_timespan(timespan2, sizeof(timespan2), next_elapse));
2551 dbus_message_iter_next(&sub);
2556 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2557 DBusMessageIter sub, sub2;
2559 dbus_message_iter_recurse(iter, &sub);
2560 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2561 const char *controller, *attr, *value;
2563 dbus_message_iter_recurse(&sub, &sub2);
2565 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2566 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2567 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2569 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2575 dbus_message_iter_next(&sub);
2580 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2581 DBusMessageIter sub;
2583 dbus_message_iter_recurse(iter, &sub);
2584 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2585 ExecStatusInfo info;
2588 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2589 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2592 t = strv_join(info.argv, " ");
2594 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2598 yes_no(info.ignore),
2599 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2600 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2601 (unsigned) info. pid,
2602 sigchld_code_to_string(info.code),
2604 info.code == CLD_EXITED ? "" : "/",
2605 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2611 strv_free(info.argv);
2613 dbus_message_iter_next(&sub);
2622 if (generic_print_property(name, iter, arg_all) > 0)
2626 printf("%s=[unprintable]\n", name);
2631 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2632 DBusMessage *m = NULL, *reply = NULL;
2633 const char *interface = "";
2636 DBusMessageIter iter, sub, sub2, sub3;
2637 UnitStatusInfo info;
2645 dbus_error_init(&error);
2647 if (!(m = dbus_message_new_method_call(
2648 "org.freedesktop.systemd1",
2650 "org.freedesktop.DBus.Properties",
2652 log_error("Could not allocate message.");
2657 if (!dbus_message_append_args(m,
2658 DBUS_TYPE_STRING, &interface,
2659 DBUS_TYPE_INVALID)) {
2660 log_error("Could not append arguments to message.");
2665 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2666 log_error("Failed to issue method call: %s", bus_error_message(&error));
2671 if (!dbus_message_iter_init(reply, &iter) ||
2672 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2673 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
2674 log_error("Failed to parse reply.");
2679 dbus_message_iter_recurse(&iter, &sub);
2686 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2689 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2690 log_error("Failed to parse reply.");
2695 dbus_message_iter_recurse(&sub, &sub2);
2697 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2698 log_error("Failed to parse reply.");
2703 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
2704 log_error("Failed to parse reply.");
2709 dbus_message_iter_recurse(&sub2, &sub3);
2711 if (show_properties)
2712 r = print_property(name, &sub3);
2714 r = status_property(name, &sub3, &info);
2717 log_error("Failed to parse reply.");
2722 dbus_message_iter_next(&sub);
2727 if (!show_properties)
2728 print_status_info(&info);
2730 if (!streq_ptr(info.active_state, "active") &&
2731 !streq_ptr(info.active_state, "reloading") &&
2732 streq(verb, "status"))
2733 /* According to LSB: "program not running" */
2736 while ((p = info.exec)) {
2737 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2738 exec_status_info_free(p);
2743 dbus_message_unref(m);
2746 dbus_message_unref(reply);
2748 dbus_error_free(&error);
2753 static int show(DBusConnection *bus, char **args) {
2754 DBusMessage *m = NULL, *reply = NULL;
2757 bool show_properties, new_line = false;
2763 dbus_error_init(&error);
2765 show_properties = !streq(args[0], "status");
2767 if (show_properties)
2768 pager_open_if_enabled();
2770 if (show_properties && strv_length(args) <= 1) {
2771 /* If not argument is specified inspect the manager
2774 ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2778 STRV_FOREACH(name, args+1) {
2779 const char *path = NULL;
2782 if (safe_atou32(*name, &id) < 0) {
2784 /* Interpret as unit name */
2786 if (!(m = dbus_message_new_method_call(
2787 "org.freedesktop.systemd1",
2788 "/org/freedesktop/systemd1",
2789 "org.freedesktop.systemd1.Manager",
2791 log_error("Could not allocate message.");
2796 if (!dbus_message_append_args(m,
2797 DBUS_TYPE_STRING, name,
2798 DBUS_TYPE_INVALID)) {
2799 log_error("Could not append arguments to message.");
2804 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2806 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2807 log_error("Failed to issue method call: %s", bus_error_message(&error));
2812 dbus_error_free(&error);
2814 dbus_message_unref(m);
2815 if (!(m = dbus_message_new_method_call(
2816 "org.freedesktop.systemd1",
2817 "/org/freedesktop/systemd1",
2818 "org.freedesktop.systemd1.Manager",
2820 log_error("Could not allocate message.");
2825 if (!dbus_message_append_args(m,
2826 DBUS_TYPE_STRING, name,
2827 DBUS_TYPE_INVALID)) {
2828 log_error("Could not append arguments to message.");
2833 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2834 log_error("Failed to issue method call: %s", bus_error_message(&error));
2836 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
2837 ret = 4; /* According to LSB: "program or service status is unknown" */
2844 } else if (show_properties) {
2846 /* Interpret as job id */
2848 if (!(m = dbus_message_new_method_call(
2849 "org.freedesktop.systemd1",
2850 "/org/freedesktop/systemd1",
2851 "org.freedesktop.systemd1.Manager",
2853 log_error("Could not allocate message.");
2858 if (!dbus_message_append_args(m,
2859 DBUS_TYPE_UINT32, &id,
2860 DBUS_TYPE_INVALID)) {
2861 log_error("Could not append arguments to message.");
2866 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2867 log_error("Failed to issue method call: %s", bus_error_message(&error));
2873 /* Interpret as PID */
2875 if (!(m = dbus_message_new_method_call(
2876 "org.freedesktop.systemd1",
2877 "/org/freedesktop/systemd1",
2878 "org.freedesktop.systemd1.Manager",
2880 log_error("Could not allocate message.");
2885 if (!dbus_message_append_args(m,
2886 DBUS_TYPE_UINT32, &id,
2887 DBUS_TYPE_INVALID)) {
2888 log_error("Could not append arguments to message.");
2893 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2894 log_error("Failed to issue method call: %s", bus_error_message(&error));
2900 if (!dbus_message_get_args(reply, &error,
2901 DBUS_TYPE_OBJECT_PATH, &path,
2902 DBUS_TYPE_INVALID)) {
2903 log_error("Failed to parse reply: %s", bus_error_message(&error));
2908 if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
2911 dbus_message_unref(m);
2912 dbus_message_unref(reply);
2918 dbus_message_unref(m);
2921 dbus_message_unref(reply);
2923 dbus_error_free(&error);
2928 static int dump(DBusConnection *bus, char **args) {
2929 DBusMessage *m = NULL, *reply = NULL;
2934 dbus_error_init(&error);
2936 pager_open_if_enabled();
2938 if (!(m = dbus_message_new_method_call(
2939 "org.freedesktop.systemd1",
2940 "/org/freedesktop/systemd1",
2941 "org.freedesktop.systemd1.Manager",
2943 log_error("Could not allocate message.");
2947 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2948 log_error("Failed to issue method call: %s", bus_error_message(&error));
2953 if (!dbus_message_get_args(reply, &error,
2954 DBUS_TYPE_STRING, &text,
2955 DBUS_TYPE_INVALID)) {
2956 log_error("Failed to parse reply: %s", bus_error_message(&error));
2961 fputs(text, stdout);
2967 dbus_message_unref(m);
2970 dbus_message_unref(reply);
2972 dbus_error_free(&error);
2977 static int snapshot(DBusConnection *bus, char **args) {
2978 DBusMessage *m = NULL, *reply = NULL;
2981 const char *name = "", *path, *id;
2982 dbus_bool_t cleanup = FALSE;
2983 DBusMessageIter iter, sub;
2985 *interface = "org.freedesktop.systemd1.Unit",
2988 dbus_error_init(&error);
2990 if (!(m = dbus_message_new_method_call(
2991 "org.freedesktop.systemd1",
2992 "/org/freedesktop/systemd1",
2993 "org.freedesktop.systemd1.Manager",
2994 "CreateSnapshot"))) {
2995 log_error("Could not allocate message.");
2999 if (strv_length(args) > 1)
3002 if (!dbus_message_append_args(m,
3003 DBUS_TYPE_STRING, &name,
3004 DBUS_TYPE_BOOLEAN, &cleanup,
3005 DBUS_TYPE_INVALID)) {
3006 log_error("Could not append arguments to message.");
3011 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3012 log_error("Failed to issue method call: %s", bus_error_message(&error));
3017 if (!dbus_message_get_args(reply, &error,
3018 DBUS_TYPE_OBJECT_PATH, &path,
3019 DBUS_TYPE_INVALID)) {
3020 log_error("Failed to parse reply: %s", bus_error_message(&error));
3025 dbus_message_unref(m);
3026 if (!(m = dbus_message_new_method_call(
3027 "org.freedesktop.systemd1",
3029 "org.freedesktop.DBus.Properties",
3031 log_error("Could not allocate message.");
3035 if (!dbus_message_append_args(m,
3036 DBUS_TYPE_STRING, &interface,
3037 DBUS_TYPE_STRING, &property,
3038 DBUS_TYPE_INVALID)) {
3039 log_error("Could not append arguments to message.");
3044 dbus_message_unref(reply);
3045 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3046 log_error("Failed to issue method call: %s", bus_error_message(&error));
3051 if (!dbus_message_iter_init(reply, &iter) ||
3052 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3053 log_error("Failed to parse reply.");
3058 dbus_message_iter_recurse(&iter, &sub);
3060 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
3061 log_error("Failed to parse reply.");
3066 dbus_message_iter_get_basic(&sub, &id);
3074 dbus_message_unref(m);
3077 dbus_message_unref(reply);
3079 dbus_error_free(&error);
3084 static int delete_snapshot(DBusConnection *bus, char **args) {
3085 DBusMessage *m = NULL, *reply = NULL;
3093 dbus_error_init(&error);
3095 STRV_FOREACH(name, args+1) {
3096 const char *path = NULL;
3098 if (!(m = dbus_message_new_method_call(
3099 "org.freedesktop.systemd1",
3100 "/org/freedesktop/systemd1",
3101 "org.freedesktop.systemd1.Manager",
3103 log_error("Could not allocate message.");
3108 if (!dbus_message_append_args(m,
3109 DBUS_TYPE_STRING, name,
3110 DBUS_TYPE_INVALID)) {
3111 log_error("Could not append arguments to message.");
3116 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3117 log_error("Failed to issue method call: %s", bus_error_message(&error));
3122 if (!dbus_message_get_args(reply, &error,
3123 DBUS_TYPE_OBJECT_PATH, &path,
3124 DBUS_TYPE_INVALID)) {
3125 log_error("Failed to parse reply: %s", bus_error_message(&error));
3130 dbus_message_unref(m);
3131 if (!(m = dbus_message_new_method_call(
3132 "org.freedesktop.systemd1",
3134 "org.freedesktop.systemd1.Snapshot",
3136 log_error("Could not allocate message.");
3141 dbus_message_unref(reply);
3142 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3143 log_error("Failed to issue method call: %s", bus_error_message(&error));