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>
28 #include <sys/ioctl.h>
32 #include <sys/socket.h>
35 #include <sys/prctl.h>
36 #include <dbus/dbus.h>
38 #include <systemd/sd-daemon.h>
39 #include <systemd/sd-shutdown.h>
45 #include "utmp-wtmp.h"
48 #include "path-util.h"
50 #include "dbus-common.h"
51 #include "cgroup-show.h"
52 #include "cgroup-util.h"
54 #include "path-lookup.h"
55 #include "conf-parser.h"
56 #include "exit-status.h"
57 #include "bus-errors.h"
59 #include "unit-name.h"
61 #include "spawn-ask-password-agent.h"
62 #include "spawn-polkit-agent.h"
64 #include "logs-show.h"
65 #include "path-util.h"
67 static const char *arg_type
= NULL
;
68 static char **arg_property
= NULL
;
69 static bool arg_all
= false;
70 static const char *arg_job_mode
= "replace";
71 static UnitFileScope arg_scope
= UNIT_FILE_SYSTEM
;
72 static bool arg_no_block
= false;
73 static bool arg_no_legend
= false;
74 static bool arg_no_pager
= false;
75 static bool arg_no_wtmp
= false;
76 static bool arg_no_sync
= false;
77 static bool arg_no_wall
= false;
78 static bool arg_no_reload
= false;
79 static bool arg_dry
= false;
80 static bool arg_quiet
= false;
81 static bool arg_full
= false;
82 static int arg_force
= 0;
83 static bool arg_ask_password
= true;
84 static bool arg_failed
= false;
85 static bool arg_runtime
= false;
86 static char **arg_wall
= NULL
;
87 static const char *arg_kill_who
= NULL
;
88 static const char *arg_kill_mode
= NULL
;
89 static int arg_signal
= SIGTERM
;
90 static const char *arg_root
= NULL
;
91 static usec_t arg_when
= 0;
110 ACTION_CANCEL_SHUTDOWN
,
112 } arg_action
= ACTION_SYSTEMCTL
;
118 static enum transport
{
122 } arg_transport
= TRANSPORT_NORMAL
;
123 static const char *arg_host
= NULL
;
124 static bool arg_follow
= false;
125 static unsigned arg_lines
= 10;
126 static OutputMode arg_output
= OUTPUT_SHORT
;
128 static bool private_bus
= false;
130 static int daemon_reload(DBusConnection
*bus
, char **args
);
131 static void halt_now(enum action a
);
133 static bool on_tty(void) {
136 /* Note that this is invoked relatively early, before we start
137 * the pager. That means the value we return reflects whether
138 * we originally were started on a tty, not if we currently
139 * are. But this is intended, since we want colour and so on
140 * when run in our own pager. */
142 if (_unlikely_(t
< 0))
143 t
= isatty(STDOUT_FILENO
) > 0;
148 static void pager_open_if_enabled(void) {
150 /* Cache result before we open the pager */
159 static void ask_password_agent_open_if_enabled(void) {
161 /* Open the password agent as a child process if necessary */
163 if (!arg_ask_password
)
166 if (arg_scope
!= UNIT_FILE_SYSTEM
)
169 ask_password_agent_open();
172 static void polkit_agent_open_if_enabled(void) {
174 /* Open the polkit agent as a child process if necessary */
176 if (!arg_ask_password
)
179 if (arg_scope
!= UNIT_FILE_SYSTEM
)
185 static const char *ansi_highlight_red(bool b
) {
190 return b
? ANSI_HIGHLIGHT_RED_ON
: ANSI_HIGHLIGHT_OFF
;
193 static const char *ansi_highlight_green(bool b
) {
198 return b
? ANSI_HIGHLIGHT_GREEN_ON
: ANSI_HIGHLIGHT_OFF
;
201 static bool error_is_no_service(const DBusError
*error
) {
204 if (!dbus_error_is_set(error
))
207 if (dbus_error_has_name(error
, DBUS_ERROR_NAME_HAS_NO_OWNER
))
210 if (dbus_error_has_name(error
, DBUS_ERROR_SERVICE_UNKNOWN
))
213 return startswith(error
->name
, "org.freedesktop.DBus.Error.Spawn.");
216 static int translate_bus_error_to_exit_status(int r
, const DBusError
*error
) {
219 if (!dbus_error_is_set(error
))
222 if (dbus_error_has_name(error
, DBUS_ERROR_ACCESS_DENIED
) ||
223 dbus_error_has_name(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
) ||
224 dbus_error_has_name(error
, BUS_ERROR_NO_ISOLATION
) ||
225 dbus_error_has_name(error
, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE
))
226 return EXIT_NOPERMISSION
;
228 if (dbus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
))
229 return EXIT_NOTINSTALLED
;
231 if (dbus_error_has_name(error
, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE
) ||
232 dbus_error_has_name(error
, BUS_ERROR_NOT_SUPPORTED
))
233 return EXIT_NOTIMPLEMENTED
;
235 if (dbus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
))
236 return EXIT_NOTCONFIGURED
;
244 static void warn_wall(enum action a
) {
245 static const char *table
[_ACTION_MAX
] = {
246 [ACTION_HALT
] = "The system is going down for system halt NOW!",
247 [ACTION_REBOOT
] = "The system is going down for reboot NOW!",
248 [ACTION_POWEROFF
] = "The system is going down for power-off NOW!",
249 [ACTION_KEXEC
] = "The system is going down for kexec reboot NOW!",
250 [ACTION_RESCUE
] = "The system is going down to rescue mode NOW!",
251 [ACTION_EMERGENCY
] = "The system is going down to emergency mode NOW!"
260 p
= strv_join(arg_wall
, " ");
262 log_error("Failed to join strings.");
278 utmp_wall(table
[a
], NULL
);
281 static bool avoid_bus(void) {
283 if (running_in_chroot() > 0)
286 if (sd_booted() <= 0)
289 if (!isempty(arg_root
))
292 if (arg_scope
== UNIT_FILE_GLOBAL
)
300 const char *description
;
301 const char *load_state
;
302 const char *active_state
;
303 const char *sub_state
;
304 const char *following
;
305 const char *unit_path
;
307 const char *job_type
;
308 const char *job_path
;
311 static int compare_unit_info(const void *a
, const void *b
) {
313 const struct unit_info
*u
= a
, *v
= b
;
315 d1
= strrchr(u
->id
, '.');
316 d2
= strrchr(v
->id
, '.');
321 if ((r
= strcasecmp(d1
, d2
)) != 0)
325 return strcasecmp(u
->id
, v
->id
);
328 static bool output_show_unit(const struct unit_info
*u
) {
332 return streq(u
->active_state
, "failed");
334 return (!arg_type
|| ((dot
= strrchr(u
->id
, '.')) &&
335 streq(dot
+1, arg_type
))) &&
336 (arg_all
|| !(streq(u
->active_state
, "inactive") || u
->following
[0]) || u
->job_id
> 0);
339 static void output_units_list(const struct unit_info
*unit_infos
, unsigned c
) {
340 unsigned id_len
, max_id_len
, active_len
, sub_len
, job_len
, desc_len
, n_shown
= 0;
341 const struct unit_info
*u
;
343 max_id_len
= sizeof("UNIT")-1;
344 active_len
= sizeof("ACTIVE")-1;
345 sub_len
= sizeof("SUB")-1;
346 job_len
= sizeof("JOB")-1;
349 for (u
= unit_infos
; u
< unit_infos
+ c
; u
++) {
350 if (!output_show_unit(u
))
353 max_id_len
= MAX(max_id_len
, strlen(u
->id
));
354 active_len
= MAX(active_len
, strlen(u
->active_state
));
355 sub_len
= MAX(sub_len
, strlen(u
->sub_state
));
357 job_len
= MAX(job_len
, strlen(u
->job_type
));
362 id_len
= MIN(max_id_len
, 25);
363 basic_len
= 5 + id_len
+ 6 + active_len
+ sub_len
+ job_len
;
364 if (basic_len
< (unsigned) columns()) {
365 unsigned extra_len
, incr
;
366 extra_len
= columns() - basic_len
;
367 /* Either UNIT already got 25, or is fully satisfied.
368 * Grant up to 25 to DESC now. */
369 incr
= MIN(extra_len
, 25);
372 /* split the remaining space between UNIT and DESC,
373 * but do not give UNIT more than it needs. */
375 incr
= MIN(extra_len
/ 2, max_id_len
- id_len
);
377 desc_len
+= extra_len
- incr
;
383 if (!arg_no_legend
) {
384 printf("%-*s %-6s %-*s %-*s %-*s ", id_len
, "UNIT", "LOAD",
385 active_len
, "ACTIVE", sub_len
, "SUB", job_len
, "JOB");
386 if (!arg_full
&& arg_no_pager
)
387 printf("%.*s\n", desc_len
, "DESCRIPTION");
389 printf("%s\n", "DESCRIPTION");
392 for (u
= unit_infos
; u
< unit_infos
+ c
; u
++) {
394 const char *on_loaded
, *off_loaded
;
395 const char *on_active
, *off_active
;
397 if (!output_show_unit(u
))
402 if (streq(u
->load_state
, "error")) {
403 on_loaded
= ansi_highlight_red(true);
404 off_loaded
= ansi_highlight_red(false);
406 on_loaded
= off_loaded
= "";
408 if (streq(u
->active_state
, "failed")) {
409 on_active
= ansi_highlight_red(true);
410 off_active
= ansi_highlight_red(false);
412 on_active
= off_active
= "";
414 e
= arg_full
? NULL
: ellipsize(u
->id
, id_len
, 33);
416 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
417 id_len
, e
? e
: u
->id
,
418 on_loaded
, u
->load_state
, off_loaded
,
419 on_active
, active_len
, u
->active_state
,
420 sub_len
, u
->sub_state
, off_active
,
421 job_len
, u
->job_id
? u
->job_type
: "");
422 if (!arg_full
&& arg_no_pager
)
423 printf("%.*s\n", desc_len
, u
->description
);
425 printf("%s\n", u
->description
);
430 if (!arg_no_legend
) {
431 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
432 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
433 "SUB = The low-level unit activation state, values depend on unit type.\n"
434 "JOB = Pending job for the unit.\n");
437 printf("\n%u units listed.\n", n_shown
);
439 printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown
);
443 static int list_units(DBusConnection
*bus
, char **args
) {
444 DBusMessage
*m
= NULL
, *reply
= NULL
;
447 DBusMessageIter iter
, sub
, sub2
;
448 unsigned c
= 0, n_units
= 0;
449 struct unit_info
*unit_infos
= NULL
;
451 dbus_error_init(&error
);
455 pager_open_if_enabled();
457 if (!(m
= dbus_message_new_method_call(
458 "org.freedesktop.systemd1",
459 "/org/freedesktop/systemd1",
460 "org.freedesktop.systemd1.Manager",
462 log_error("Could not allocate message.");
466 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
467 log_error("Failed to issue method call: %s", bus_error_message(&error
));
472 if (!dbus_message_iter_init(reply
, &iter
) ||
473 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
474 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
475 log_error("Failed to parse reply.");
480 dbus_message_iter_recurse(&iter
, &sub
);
482 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
485 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
486 log_error("Failed to parse reply.");
494 n_units
= MAX(2*c
, 16);
495 w
= realloc(unit_infos
, sizeof(struct unit_info
) * n_units
);
498 log_error("Failed to allocate unit array.");
508 dbus_message_iter_recurse(&sub
, &sub2
);
510 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->id
, true) < 0 ||
511 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->description
, true) < 0 ||
512 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->load_state
, true) < 0 ||
513 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->active_state
, true) < 0 ||
514 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->sub_state
, true) < 0 ||
515 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->following
, true) < 0 ||
516 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &u
->unit_path
, true) < 0 ||
517 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &u
->job_id
, true) < 0 ||
518 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->job_type
, true) < 0 ||
519 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &u
->job_path
, false) < 0) {
520 log_error("Failed to parse reply.");
525 dbus_message_iter_next(&sub
);
530 qsort(unit_infos
, c
, sizeof(struct unit_info
), compare_unit_info
);
531 output_units_list(unit_infos
, c
);
538 dbus_message_unref(m
);
541 dbus_message_unref(reply
);
545 dbus_error_free(&error
);
550 static int compare_unit_file_list(const void *a
, const void *b
) {
552 const UnitFileList
*u
= a
, *v
= b
;
554 d1
= strrchr(u
->path
, '.');
555 d2
= strrchr(v
->path
, '.');
560 r
= strcasecmp(d1
, d2
);
565 return strcasecmp(path_get_file_name(u
->path
), path_get_file_name(v
->path
));
568 static bool output_show_unit_file(const UnitFileList
*u
) {
571 return !arg_type
|| ((dot
= strrchr(u
->path
, '.')) && streq(dot
+1, arg_type
));
574 static void output_unit_file_list(const UnitFileList
*units
, unsigned c
) {
575 unsigned max_id_len
, id_cols
, state_cols
, n_shown
= 0;
576 const UnitFileList
*u
;
578 max_id_len
= sizeof("UNIT FILE")-1;
579 state_cols
= sizeof("STATE")-1;
580 for (u
= units
; u
< units
+ c
; u
++) {
581 if (!output_show_unit_file(u
))
584 max_id_len
= MAX(max_id_len
, strlen(path_get_file_name(u
->path
)));
585 state_cols
= MAX(state_cols
, strlen(unit_file_state_to_string(u
->state
)));
590 id_cols
= MIN(max_id_len
, 25);
591 basic_cols
= 1 + id_cols
+ state_cols
;
592 if (basic_cols
< (unsigned) columns())
593 id_cols
+= MIN(columns() - basic_cols
, max_id_len
- id_cols
);
595 id_cols
= max_id_len
;
598 printf("%-*s %-*s\n", id_cols
, "UNIT FILE", state_cols
, "STATE");
600 for (u
= units
; u
< units
+ c
; u
++) {
602 const char *on
, *off
;
605 if (!output_show_unit_file(u
))
610 if (u
->state
== UNIT_FILE_MASKED
||
611 u
->state
== UNIT_FILE_MASKED_RUNTIME
||
612 u
->state
== UNIT_FILE_DISABLED
) {
613 on
= ansi_highlight_red(true);
614 off
= ansi_highlight_red(false);
615 } else if (u
->state
== UNIT_FILE_ENABLED
) {
616 on
= ansi_highlight_green(true);
617 off
= ansi_highlight_green(false);
621 id
= path_get_file_name(u
->path
);
623 e
= arg_full
? NULL
: ellipsize(id
, id_cols
, 33);
625 printf("%-*s %s%-*s%s\n",
627 on
, state_cols
, unit_file_state_to_string(u
->state
), off
);
633 printf("\n%u unit files listed.\n", n_shown
);
636 static int list_unit_files(DBusConnection
*bus
, char **args
) {
637 DBusMessage
*m
= NULL
, *reply
= NULL
;
640 DBusMessageIter iter
, sub
, sub2
;
641 unsigned c
= 0, n_units
= 0;
642 UnitFileList
*units
= NULL
;
644 dbus_error_init(&error
);
646 pager_open_if_enabled();
653 h
= hashmap_new(string_hash_func
, string_compare_func
);
655 log_error("Out of memory");
659 r
= unit_file_get_list(arg_scope
, arg_root
, h
);
661 unit_file_list_free(h
);
662 log_error("Failed to get unit file list: %s", strerror(-r
));
666 n_units
= hashmap_size(h
);
667 units
= new(UnitFileList
, n_units
);
669 unit_file_list_free(h
);
670 log_error("Out of memory");
674 HASHMAP_FOREACH(u
, h
, i
) {
675 memcpy(units
+ c
++, u
, sizeof(UnitFileList
));
683 m
= dbus_message_new_method_call(
684 "org.freedesktop.systemd1",
685 "/org/freedesktop/systemd1",
686 "org.freedesktop.systemd1.Manager",
689 log_error("Could not allocate message.");
693 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
695 log_error("Failed to issue method call: %s", bus_error_message(&error
));
700 if (!dbus_message_iter_init(reply
, &iter
) ||
701 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
702 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
703 log_error("Failed to parse reply.");
708 dbus_message_iter_recurse(&iter
, &sub
);
710 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
714 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
715 log_error("Failed to parse reply.");
723 n_units
= MAX(2*c
, 16);
724 w
= realloc(units
, sizeof(struct UnitFileList
) * n_units
);
727 log_error("Failed to allocate unit array.");
737 dbus_message_iter_recurse(&sub
, &sub2
);
739 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->path
, true) < 0 ||
740 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &state
, false) < 0) {
741 log_error("Failed to parse reply.");
746 u
->state
= unit_file_state_from_string(state
);
748 dbus_message_iter_next(&sub
);
754 qsort(units
, c
, sizeof(UnitFileList
), compare_unit_file_list
);
755 output_unit_file_list(units
, c
);
762 dbus_message_unref(m
);
765 dbus_message_unref(reply
);
769 dbus_error_free(&error
);
774 static int dot_one_property(const char *name
, const char *prop
, DBusMessageIter
*iter
) {
775 static const char * const colors
[] = {
776 "Requires", "[color=\"black\"]",
777 "RequiresOverridable", "[color=\"black\"]",
778 "Requisite", "[color=\"darkblue\"]",
779 "RequisiteOverridable", "[color=\"darkblue\"]",
780 "Wants", "[color=\"darkgrey\"]",
781 "Conflicts", "[color=\"red\"]",
782 "ConflictedBy", "[color=\"red\"]",
783 "After", "[color=\"green\"]"
786 const char *c
= NULL
;
793 for (i
= 0; i
< ELEMENTSOF(colors
); i
+= 2)
794 if (streq(colors
[i
], prop
)) {
802 if (arg_dot
!= DOT_ALL
)
803 if ((arg_dot
== DOT_ORDER
) != streq(prop
, "After"))
806 switch (dbus_message_iter_get_arg_type(iter
)) {
808 case DBUS_TYPE_ARRAY
:
810 if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRING
) {
813 dbus_message_iter_recurse(iter
, &sub
);
815 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
818 assert(dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRING
);
819 dbus_message_iter_get_basic(&sub
, &s
);
820 printf("\t\"%s\"->\"%s\" %s;\n", name
, s
, c
);
822 dbus_message_iter_next(&sub
);
832 static int dot_one(DBusConnection
*bus
, const char *name
, const char *path
) {
833 DBusMessage
*m
= NULL
, *reply
= NULL
;
834 const char *interface
= "org.freedesktop.systemd1.Unit";
837 DBusMessageIter iter
, sub
, sub2
, sub3
;
842 dbus_error_init(&error
);
844 if (!(m
= dbus_message_new_method_call(
845 "org.freedesktop.systemd1",
847 "org.freedesktop.DBus.Properties",
849 log_error("Could not allocate message.");
854 if (!dbus_message_append_args(m
,
855 DBUS_TYPE_STRING
, &interface
,
856 DBUS_TYPE_INVALID
)) {
857 log_error("Could not append arguments to message.");
862 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
863 log_error("Failed to issue method call: %s", bus_error_message(&error
));
868 if (!dbus_message_iter_init(reply
, &iter
) ||
869 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
870 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_DICT_ENTRY
) {
871 log_error("Failed to parse reply.");
876 dbus_message_iter_recurse(&iter
, &sub
);
878 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
881 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_DICT_ENTRY
) {
882 log_error("Failed to parse reply.");
887 dbus_message_iter_recurse(&sub
, &sub2
);
889 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &prop
, true) < 0) {
890 log_error("Failed to parse reply.");
895 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_VARIANT
) {
896 log_error("Failed to parse reply.");
901 dbus_message_iter_recurse(&sub2
, &sub3
);
903 if (dot_one_property(name
, prop
, &sub3
)) {
904 log_error("Failed to parse reply.");
909 dbus_message_iter_next(&sub
);
916 dbus_message_unref(m
);
919 dbus_message_unref(reply
);
921 dbus_error_free(&error
);
926 static int dot(DBusConnection
*bus
, char **args
) {
927 DBusMessage
*m
= NULL
, *reply
= NULL
;
930 DBusMessageIter iter
, sub
, sub2
;
932 dbus_error_init(&error
);
936 if (!(m
= dbus_message_new_method_call(
937 "org.freedesktop.systemd1",
938 "/org/freedesktop/systemd1",
939 "org.freedesktop.systemd1.Manager",
941 log_error("Could not allocate message.");
945 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
946 log_error("Failed to issue method call: %s", bus_error_message(&error
));
951 if (!dbus_message_iter_init(reply
, &iter
) ||
952 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
953 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
954 log_error("Failed to parse reply.");
959 printf("digraph systemd {\n");
961 dbus_message_iter_recurse(&iter
, &sub
);
962 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
963 const char *id
, *description
, *load_state
, *active_state
, *sub_state
, *following
, *unit_path
;
965 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
966 log_error("Failed to parse reply.");
971 dbus_message_iter_recurse(&sub
, &sub2
);
973 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &id
, true) < 0 ||
974 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &description
, true) < 0 ||
975 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &load_state
, true) < 0 ||
976 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &active_state
, true) < 0 ||
977 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &sub_state
, true) < 0 ||
978 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &following
, true) < 0 ||
979 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &unit_path
, true) < 0) {
980 log_error("Failed to parse reply.");
985 if ((r
= dot_one(bus
, id
, unit_path
)) < 0)
988 /* printf("\t\"%s\";\n", id); */
989 dbus_message_iter_next(&sub
);
994 log_info(" Color legend: black = Requires\n"
995 " dark blue = Requisite\n"
996 " dark grey = Wants\n"
1001 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
1002 "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
1008 dbus_message_unref(m
);
1011 dbus_message_unref(reply
);
1013 dbus_error_free(&error
);
1018 static int list_jobs(DBusConnection
*bus
, char **args
) {
1019 DBusMessage
*m
= NULL
, *reply
= NULL
;
1022 DBusMessageIter iter
, sub
, sub2
;
1025 dbus_error_init(&error
);
1029 pager_open_if_enabled();
1031 if (!(m
= dbus_message_new_method_call(
1032 "org.freedesktop.systemd1",
1033 "/org/freedesktop/systemd1",
1034 "org.freedesktop.systemd1.Manager",
1036 log_error("Could not allocate message.");
1040 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1041 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1046 if (!dbus_message_iter_init(reply
, &iter
) ||
1047 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
1048 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
1049 log_error("Failed to parse reply.");
1054 dbus_message_iter_recurse(&iter
, &sub
);
1057 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1059 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
1060 const char *name
, *type
, *state
, *job_path
, *unit_path
;
1064 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
1065 log_error("Failed to parse reply.");
1070 dbus_message_iter_recurse(&sub
, &sub2
);
1072 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &id
, true) < 0 ||
1073 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &name
, true) < 0 ||
1074 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) < 0 ||
1075 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &state
, true) < 0 ||
1076 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &job_path
, true) < 0 ||
1077 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &unit_path
, false) < 0) {
1078 log_error("Failed to parse reply.");
1083 e
= arg_full
? NULL
: ellipsize(name
, 25, 33);
1084 printf("%4u %-25s %-15s %-7s\n", id
, e
? e
: name
, type
, state
);
1089 dbus_message_iter_next(&sub
);
1093 printf("\n%u jobs listed.\n", k
);
1099 dbus_message_unref(m
);
1102 dbus_message_unref(reply
);
1104 dbus_error_free(&error
);
1109 static int load_unit(DBusConnection
*bus
, char **args
) {
1110 DBusMessage
*m
= NULL
;
1115 dbus_error_init(&error
);
1120 STRV_FOREACH(name
, args
+1) {
1123 if (!(m
= dbus_message_new_method_call(
1124 "org.freedesktop.systemd1",
1125 "/org/freedesktop/systemd1",
1126 "org.freedesktop.systemd1.Manager",
1128 log_error("Could not allocate message.");
1133 if (!dbus_message_append_args(m
,
1134 DBUS_TYPE_STRING
, name
,
1135 DBUS_TYPE_INVALID
)) {
1136 log_error("Could not append arguments to message.");
1141 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1142 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1147 dbus_message_unref(m
);
1148 dbus_message_unref(reply
);
1157 dbus_message_unref(m
);
1159 dbus_error_free(&error
);
1164 static int cancel_job(DBusConnection
*bus
, char **args
) {
1165 DBusMessage
*m
= NULL
, *reply
= NULL
;
1170 dbus_error_init(&error
);
1175 if (strv_length(args
) <= 1)
1176 return daemon_reload(bus
, args
);
1178 STRV_FOREACH(name
, args
+1) {
1182 if (!(m
= dbus_message_new_method_call(
1183 "org.freedesktop.systemd1",
1184 "/org/freedesktop/systemd1",
1185 "org.freedesktop.systemd1.Manager",
1187 log_error("Could not allocate message.");
1192 if ((r
= safe_atou(*name
, &id
)) < 0) {
1193 log_error("Failed to parse job id: %s", strerror(-r
));
1197 assert_cc(sizeof(uint32_t) == sizeof(id
));
1198 if (!dbus_message_append_args(m
,
1199 DBUS_TYPE_UINT32
, &id
,
1200 DBUS_TYPE_INVALID
)) {
1201 log_error("Could not append arguments to message.");
1206 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1207 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1212 if (!dbus_message_get_args(reply
, &error
,
1213 DBUS_TYPE_OBJECT_PATH
, &path
,
1214 DBUS_TYPE_INVALID
)) {
1215 log_error("Failed to parse reply: %s", bus_error_message(&error
));
1220 dbus_message_unref(m
);
1221 if (!(m
= dbus_message_new_method_call(
1222 "org.freedesktop.systemd1",
1224 "org.freedesktop.systemd1.Job",
1226 log_error("Could not allocate message.");
1231 dbus_message_unref(reply
);
1232 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1233 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1238 dbus_message_unref(m
);
1239 dbus_message_unref(reply
);
1247 dbus_message_unref(m
);
1250 dbus_message_unref(reply
);
1252 dbus_error_free(&error
);
1257 static bool need_daemon_reload(DBusConnection
*bus
, const char *unit
) {
1258 DBusMessage
*m
= NULL
, *reply
= NULL
;
1259 dbus_bool_t b
= FALSE
;
1260 DBusMessageIter iter
, sub
;
1262 *interface
= "org.freedesktop.systemd1.Unit",
1263 *property
= "NeedDaemonReload",
1266 /* We ignore all errors here, since this is used to show a warning only */
1268 if (!(m
= dbus_message_new_method_call(
1269 "org.freedesktop.systemd1",
1270 "/org/freedesktop/systemd1",
1271 "org.freedesktop.systemd1.Manager",
1275 if (!dbus_message_append_args(m
,
1276 DBUS_TYPE_STRING
, &unit
,
1280 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, NULL
)))
1283 if (!dbus_message_get_args(reply
, NULL
,
1284 DBUS_TYPE_OBJECT_PATH
, &path
,
1288 dbus_message_unref(m
);
1289 if (!(m
= dbus_message_new_method_call(
1290 "org.freedesktop.systemd1",
1292 "org.freedesktop.DBus.Properties",
1296 if (!dbus_message_append_args(m
,
1297 DBUS_TYPE_STRING
, &interface
,
1298 DBUS_TYPE_STRING
, &property
,
1299 DBUS_TYPE_INVALID
)) {
1303 dbus_message_unref(reply
);
1304 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, NULL
)))
1307 if (!dbus_message_iter_init(reply
, &iter
) ||
1308 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
)
1311 dbus_message_iter_recurse(&iter
, &sub
);
1313 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_BOOLEAN
)
1316 dbus_message_iter_get_basic(&sub
, &b
);
1320 dbus_message_unref(m
);
1323 dbus_message_unref(reply
);
1328 typedef struct WaitData
{
1333 static DBusHandlerResult
wait_filter(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
1341 dbus_error_init(&error
);
1343 log_debug("Got D-Bus request: %s.%s() on %s",
1344 dbus_message_get_interface(message
),
1345 dbus_message_get_member(message
),
1346 dbus_message_get_path(message
));
1348 if (dbus_message_is_signal(message
, DBUS_INTERFACE_LOCAL
, "Disconnected")) {
1349 log_error("Warning! D-Bus connection terminated.");
1350 dbus_connection_close(connection
);
1352 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1354 const char *path
, *result
, *unit
;
1355 dbus_bool_t success
= true;
1357 if (dbus_message_get_args(message
, &error
,
1358 DBUS_TYPE_UINT32
, &id
,
1359 DBUS_TYPE_OBJECT_PATH
, &path
,
1360 DBUS_TYPE_STRING
, &unit
,
1361 DBUS_TYPE_STRING
, &result
,
1362 DBUS_TYPE_INVALID
)) {
1365 p
= set_remove(d
->set
, (char*) path
);
1369 d
->result
= strdup(result
);
1374 dbus_error_free(&error
);
1375 if (dbus_message_get_args(message
, &error
,
1376 DBUS_TYPE_UINT32
, &id
,
1377 DBUS_TYPE_OBJECT_PATH
, &path
,
1378 DBUS_TYPE_STRING
, &result
,
1379 DBUS_TYPE_INVALID
)) {
1382 /* Compatibility with older systemd versions <
1383 * 183 during upgrades. This should be dropped
1385 p
= set_remove(d
->set
, (char*) path
);
1389 d
->result
= strdup(result
);
1394 dbus_error_free(&error
);
1395 if (dbus_message_get_args(message
, &error
,
1396 DBUS_TYPE_UINT32
, &id
,
1397 DBUS_TYPE_OBJECT_PATH
, &path
,
1398 DBUS_TYPE_BOOLEAN
, &success
,
1399 DBUS_TYPE_INVALID
)) {
1402 /* Compatibility with older systemd versions <
1403 * 19 during upgrades. This should be dropped
1406 p
= set_remove(d
->set
, (char*) path
);
1410 d
->result
= strdup("failed");
1416 log_error("Failed to parse message: %s", bus_error_message(&error
));
1420 dbus_error_free(&error
);
1421 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
1424 static int enable_wait_for_jobs(DBusConnection
*bus
) {
1432 dbus_error_init(&error
);
1433 dbus_bus_add_match(bus
,
1435 "sender='org.freedesktop.systemd1',"
1436 "interface='org.freedesktop.systemd1.Manager',"
1437 "member='JobRemoved',"
1438 "path='/org/freedesktop/systemd1'",
1441 if (dbus_error_is_set(&error
)) {
1442 log_error("Failed to add match: %s", bus_error_message(&error
));
1443 dbus_error_free(&error
);
1447 /* This is slightly dirty, since we don't undo the match registrations. */
1451 static int wait_for_jobs(DBusConnection
*bus
, Set
*s
) {
1461 if (!dbus_connection_add_filter(bus
, wait_filter
, &d
, NULL
)) {
1462 log_error("Failed to add filter.");
1467 while (!set_isempty(s
) &&
1468 dbus_connection_read_write_dispatch(bus
, -1))
1471 if (!arg_quiet
&& d
.result
) {
1472 if (streq(d
.result
, "timeout"))
1473 log_error("Job timed out.");
1474 else if (streq(d
.result
, "canceled"))
1475 log_error("Job canceled.");
1476 else if (streq(d
.result
, "dependency"))
1477 log_error("A dependency job failed. See system journal for details.");
1478 else if (!streq(d
.result
, "done") && !streq(d
.result
, "skipped"))
1479 log_error("Job failed. See system journal and 'systemctl status' for details.");
1482 if (streq_ptr(d
.result
, "timeout"))
1484 else if (streq_ptr(d
.result
, "canceled"))
1486 else if (!streq_ptr(d
.result
, "done") && !streq_ptr(d
.result
, "skipped"))
1494 /* This is slightly dirty, since we don't undo the filter registration. */
1499 static int start_unit_one(
1500 DBusConnection
*bus
,
1507 DBusMessage
*m
= NULL
, *reply
= NULL
;
1516 assert(arg_no_block
|| s
);
1518 if (!(m
= dbus_message_new_method_call(
1519 "org.freedesktop.systemd1",
1520 "/org/freedesktop/systemd1",
1521 "org.freedesktop.systemd1.Manager",
1523 log_error("Could not allocate message.");
1528 if (!dbus_message_append_args(m
,
1529 DBUS_TYPE_STRING
, &name
,
1530 DBUS_TYPE_STRING
, &mode
,
1531 DBUS_TYPE_INVALID
)) {
1532 log_error("Could not append arguments to message.");
1537 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, error
))) {
1539 if (arg_action
!= ACTION_SYSTEMCTL
&& error_is_no_service(error
)) {
1540 /* There's always a fallback possible for
1541 * legacy actions. */
1546 log_error("Failed to issue method call: %s", bus_error_message(error
));
1551 if (!dbus_message_get_args(reply
, error
,
1552 DBUS_TYPE_OBJECT_PATH
, &path
,
1553 DBUS_TYPE_INVALID
)) {
1554 log_error("Failed to parse reply: %s", bus_error_message(error
));
1559 if (need_daemon_reload(bus
, name
))
1560 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1561 arg_scope
== UNIT_FILE_SYSTEM
? "--system" : "--user");
1563 if (!arg_no_block
) {
1566 if (!(p
= strdup(path
))) {
1567 log_error("Failed to duplicate path.");
1572 if ((r
= set_put(s
, p
)) < 0) {
1574 log_error("Failed to add path to set.");
1583 dbus_message_unref(m
);
1586 dbus_message_unref(reply
);
1591 static enum action
verb_to_action(const char *verb
) {
1592 if (streq(verb
, "halt"))
1594 else if (streq(verb
, "poweroff"))
1595 return ACTION_POWEROFF
;
1596 else if (streq(verb
, "reboot"))
1597 return ACTION_REBOOT
;
1598 else if (streq(verb
, "kexec"))
1599 return ACTION_KEXEC
;
1600 else if (streq(verb
, "rescue"))
1601 return ACTION_RESCUE
;
1602 else if (streq(verb
, "emergency"))
1603 return ACTION_EMERGENCY
;
1604 else if (streq(verb
, "default"))
1605 return ACTION_DEFAULT
;
1606 else if (streq(verb
, "exit"))
1609 return ACTION_INVALID
;
1612 static int start_unit(DBusConnection
*bus
, char **args
) {
1614 static const char * const table
[_ACTION_MAX
] = {
1615 [ACTION_HALT
] = SPECIAL_HALT_TARGET
,
1616 [ACTION_POWEROFF
] = SPECIAL_POWEROFF_TARGET
,
1617 [ACTION_REBOOT
] = SPECIAL_REBOOT_TARGET
,
1618 [ACTION_KEXEC
] = SPECIAL_KEXEC_TARGET
,
1619 [ACTION_RUNLEVEL2
] = SPECIAL_RUNLEVEL2_TARGET
,
1620 [ACTION_RUNLEVEL3
] = SPECIAL_RUNLEVEL3_TARGET
,
1621 [ACTION_RUNLEVEL4
] = SPECIAL_RUNLEVEL4_TARGET
,
1622 [ACTION_RUNLEVEL5
] = SPECIAL_RUNLEVEL5_TARGET
,
1623 [ACTION_RESCUE
] = SPECIAL_RESCUE_TARGET
,
1624 [ACTION_EMERGENCY
] = SPECIAL_EMERGENCY_TARGET
,
1625 [ACTION_DEFAULT
] = SPECIAL_DEFAULT_TARGET
,
1626 [ACTION_EXIT
] = SPECIAL_EXIT_TARGET
1630 const char *method
, *mode
, *one_name
;
1635 dbus_error_init(&error
);
1639 ask_password_agent_open_if_enabled();
1641 if (arg_action
== ACTION_SYSTEMCTL
) {
1643 streq(args
[0], "stop") ||
1644 streq(args
[0], "condstop") ? "StopUnit" :
1645 streq(args
[0], "reload") ? "ReloadUnit" :
1646 streq(args
[0], "restart") ? "RestartUnit" :
1648 streq(args
[0], "try-restart") ||
1649 streq(args
[0], "condrestart") ? "TryRestartUnit" :
1651 streq(args
[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1653 streq(args
[0], "reload-or-try-restart") ||
1654 streq(args
[0], "condreload") ||
1656 streq(args
[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1660 (streq(args
[0], "isolate") ||
1661 streq(args
[0], "rescue") ||
1662 streq(args
[0], "emergency")) ? "isolate" : arg_job_mode
;
1664 one_name
= table
[verb_to_action(args
[0])];
1667 assert(arg_action
< ELEMENTSOF(table
));
1668 assert(table
[arg_action
]);
1670 method
= "StartUnit";
1672 mode
= (arg_action
== ACTION_EMERGENCY
||
1673 arg_action
== ACTION_RESCUE
||
1674 arg_action
== ACTION_RUNLEVEL2
||
1675 arg_action
== ACTION_RUNLEVEL3
||
1676 arg_action
== ACTION_RUNLEVEL4
||
1677 arg_action
== ACTION_RUNLEVEL5
) ? "isolate" : "replace";
1679 one_name
= table
[arg_action
];
1682 if (!arg_no_block
) {
1683 if ((ret
= enable_wait_for_jobs(bus
)) < 0) {
1684 log_error("Could not watch jobs: %s", strerror(-ret
));
1688 if (!(s
= set_new(string_hash_func
, string_compare_func
))) {
1689 log_error("Failed to allocate set.");
1696 if ((ret
= start_unit_one(bus
, method
, one_name
, mode
, &error
, s
)) <= 0)
1699 STRV_FOREACH(name
, args
+1)
1700 if ((r
= start_unit_one(bus
, method
, *name
, mode
, &error
, s
)) != 0) {
1701 ret
= translate_bus_error_to_exit_status(r
, &error
);
1702 dbus_error_free(&error
);
1707 if ((r
= wait_for_jobs(bus
, s
)) < 0) {
1716 dbus_error_free(&error
);
1721 /* Ask systemd-logind, which might grant access to unprivileged users
1722 * through PolicyKit */
1723 static int reboot_with_logind(DBusConnection
*bus
, enum action a
) {
1726 DBusMessage
*m
= NULL
, *reply
= NULL
;
1728 dbus_bool_t interactive
= true;
1731 dbus_error_init(&error
);
1733 polkit_agent_open_if_enabled();
1741 case ACTION_POWEROFF
:
1742 method
= "PowerOff";
1749 m
= dbus_message_new_method_call(
1750 "org.freedesktop.login1",
1751 "/org/freedesktop/login1",
1752 "org.freedesktop.login1.Manager",
1755 log_error("Could not allocate message.");
1760 if (!dbus_message_append_args(m
,
1761 DBUS_TYPE_BOOLEAN
, &interactive
,
1762 DBUS_TYPE_INVALID
)) {
1763 log_error("Could not append arguments to message.");
1768 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
1770 if (error_is_no_service(&error
)) {
1771 log_debug("Failed to issue method call: %s", bus_error_message(&error
));
1776 if (dbus_error_has_name(&error
, DBUS_ERROR_ACCESS_DENIED
)) {
1777 log_debug("Failed to issue method call: %s", bus_error_message(&error
));
1782 log_info("Failed to issue method call: %s", bus_error_message(&error
));
1791 dbus_message_unref(m
);
1794 dbus_message_unref(reply
);
1796 dbus_error_free(&error
);
1804 static int start_special(DBusConnection
*bus
, char **args
) {
1810 a
= verb_to_action(args
[0]);
1812 if (arg_force
>= 2 && geteuid() != 0) {
1813 log_error("Must be root.");
1817 if (arg_force
>= 2 &&
1818 (a
== ACTION_HALT
||
1819 a
== ACTION_POWEROFF
||
1820 a
== ACTION_REBOOT
))
1823 if (arg_force
>= 1 &&
1824 (a
== ACTION_HALT
||
1825 a
== ACTION_POWEROFF
||
1826 a
== ACTION_REBOOT
||
1827 a
== ACTION_KEXEC
||
1829 return daemon_reload(bus
, args
);
1831 /* first try logind, to allow authentication with polkit */
1832 if (geteuid() != 0 &&
1833 (a
== ACTION_POWEROFF
||
1834 a
== ACTION_REBOOT
)) {
1835 r
= reboot_with_logind(bus
, a
);
1840 r
= start_unit(bus
, args
);
1847 static int check_unit(DBusConnection
*bus
, char **args
) {
1848 DBusMessage
*m
= NULL
, *reply
= NULL
;
1850 *interface
= "org.freedesktop.systemd1.Unit",
1851 *property
= "ActiveState";
1852 int r
= 3; /* According to LSB: "program is not running" */
1859 dbus_error_init(&error
);
1861 STRV_FOREACH(name
, args
+1) {
1862 const char *path
= NULL
;
1864 DBusMessageIter iter
, sub
;
1866 if (!(m
= dbus_message_new_method_call(
1867 "org.freedesktop.systemd1",
1868 "/org/freedesktop/systemd1",
1869 "org.freedesktop.systemd1.Manager",
1871 log_error("Could not allocate message.");
1876 if (!dbus_message_append_args(m
,
1877 DBUS_TYPE_STRING
, name
,
1878 DBUS_TYPE_INVALID
)) {
1879 log_error("Could not append arguments to message.");
1884 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1886 /* Hmm, cannot figure out anything about this unit... */
1890 dbus_error_free(&error
);
1891 dbus_message_unref(m
);
1896 if (!dbus_message_get_args(reply
, &error
,
1897 DBUS_TYPE_OBJECT_PATH
, &path
,
1898 DBUS_TYPE_INVALID
)) {
1899 log_error("Failed to parse reply: %s", bus_error_message(&error
));
1904 dbus_message_unref(m
);
1905 if (!(m
= dbus_message_new_method_call(
1906 "org.freedesktop.systemd1",
1908 "org.freedesktop.DBus.Properties",
1910 log_error("Could not allocate message.");
1915 if (!dbus_message_append_args(m
,
1916 DBUS_TYPE_STRING
, &interface
,
1917 DBUS_TYPE_STRING
, &property
,
1918 DBUS_TYPE_INVALID
)) {
1919 log_error("Could not append arguments to message.");
1924 dbus_message_unref(reply
);
1925 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1926 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1931 if (!dbus_message_iter_init(reply
, &iter
) ||
1932 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
1933 log_error("Failed to parse reply.");
1938 dbus_message_iter_recurse(&iter
, &sub
);
1940 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRING
) {
1941 log_error("Failed to parse reply.");
1946 dbus_message_iter_get_basic(&sub
, &state
);
1951 if (streq(state
, "active") || streq(state
, "reloading"))
1954 dbus_message_unref(m
);
1955 dbus_message_unref(reply
);
1961 dbus_message_unref(m
);
1964 dbus_message_unref(reply
);
1966 dbus_error_free(&error
);
1971 static int kill_unit(DBusConnection
*bus
, char **args
) {
1972 DBusMessage
*m
= NULL
;
1980 dbus_error_init(&error
);
1983 arg_kill_who
= "all";
1986 arg_kill_mode
= streq(arg_kill_who
, "all") ? "control-group" : "process";
1988 STRV_FOREACH(name
, args
+1) {
1991 if (!(m
= dbus_message_new_method_call(
1992 "org.freedesktop.systemd1",
1993 "/org/freedesktop/systemd1",
1994 "org.freedesktop.systemd1.Manager",
1996 log_error("Could not allocate message.");
2001 if (!dbus_message_append_args(m
,
2002 DBUS_TYPE_STRING
, name
,
2003 DBUS_TYPE_STRING
, &arg_kill_who
,
2004 DBUS_TYPE_STRING
, &arg_kill_mode
,
2005 DBUS_TYPE_INT32
, &arg_signal
,
2006 DBUS_TYPE_INVALID
)) {
2007 log_error("Could not append arguments to message.");
2012 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
2013 log_error("Failed to issue method call: %s", bus_error_message(&error
));
2014 dbus_error_free(&error
);
2018 dbus_message_unref(m
);
2021 dbus_message_unref(reply
);
2027 dbus_message_unref(m
);
2029 dbus_error_free(&error
);
2034 typedef struct ExecStatusInfo
{
2042 usec_t start_timestamp
;
2043 usec_t exit_timestamp
;
2048 LIST_FIELDS(struct ExecStatusInfo
, exec
);
2051 static void exec_status_info_free(ExecStatusInfo
*i
) {
2060 static int exec_status_info_deserialize(DBusMessageIter
*sub
, ExecStatusInfo
*i
) {
2061 uint64_t start_timestamp
, exit_timestamp
, start_timestamp_monotonic
, exit_timestamp_monotonic
;
2062 DBusMessageIter sub2
, sub3
;
2066 int32_t code
, status
;
2072 if (dbus_message_iter_get_arg_type(sub
) != DBUS_TYPE_STRUCT
)
2075 dbus_message_iter_recurse(sub
, &sub2
);
2077 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0)
2080 if (!(i
->path
= strdup(path
)))
2083 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_ARRAY
||
2084 dbus_message_iter_get_element_type(&sub2
) != DBUS_TYPE_STRING
)
2088 dbus_message_iter_recurse(&sub2
, &sub3
);
2089 while (dbus_message_iter_get_arg_type(&sub3
) != DBUS_TYPE_INVALID
) {
2090 assert(dbus_message_iter_get_arg_type(&sub3
) == DBUS_TYPE_STRING
);
2091 dbus_message_iter_next(&sub3
);
2096 if (!(i
->argv
= new0(char*, n
+1)))
2100 dbus_message_iter_recurse(&sub2
, &sub3
);
2101 while (dbus_message_iter_get_arg_type(&sub3
) != DBUS_TYPE_INVALID
) {
2104 assert(dbus_message_iter_get_arg_type(&sub3
) == DBUS_TYPE_STRING
);
2105 dbus_message_iter_get_basic(&sub3
, &s
);
2106 dbus_message_iter_next(&sub3
);
2108 if (!(i
->argv
[n
++] = strdup(s
)))
2112 if (!dbus_message_iter_next(&sub2
) ||
2113 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_BOOLEAN
, &ignore
, true) < 0 ||
2114 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &start_timestamp
, true) < 0 ||
2115 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &start_timestamp_monotonic
, true) < 0 ||
2116 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &exit_timestamp
, true) < 0 ||
2117 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &exit_timestamp_monotonic
, true) < 0 ||
2118 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &pid
, true) < 0 ||
2119 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_INT32
, &code
, true) < 0 ||
2120 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_INT32
, &status
, false) < 0)
2124 i
->start_timestamp
= (usec_t
) start_timestamp
;
2125 i
->exit_timestamp
= (usec_t
) exit_timestamp
;
2126 i
->pid
= (pid_t
) pid
;
2133 typedef struct UnitStatusInfo
{
2135 const char *load_state
;
2136 const char *active_state
;
2137 const char *sub_state
;
2138 const char *unit_file_state
;
2140 const char *description
;
2141 const char *following
;
2144 const char *default_control_group
;
2146 const char *load_error
;
2149 usec_t inactive_exit_timestamp
;
2150 usec_t inactive_exit_timestamp_monotonic
;
2151 usec_t active_enter_timestamp
;
2152 usec_t active_exit_timestamp
;
2153 usec_t inactive_enter_timestamp
;
2155 bool need_daemon_reload
;
2160 const char *status_text
;
2162 #ifdef HAVE_SYSV_COMPAT
2166 usec_t start_timestamp
;
2167 usec_t exit_timestamp
;
2169 int exit_code
, exit_status
;
2171 usec_t condition_timestamp
;
2172 bool condition_result
;
2175 unsigned n_accepted
;
2176 unsigned n_connections
;
2180 const char *sysfs_path
;
2182 /* Mount, Automount */
2188 LIST_HEAD(ExecStatusInfo
, exec
);
2191 static void print_status_info(UnitStatusInfo
*i
) {
2193 const char *on
, *off
, *ss
;
2195 char since1
[FORMAT_TIMESTAMP_PRETTY_MAX
], *s1
;
2196 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
2200 /* This shows pretty information about a unit. See
2201 * print_property() for a low-level property printer */
2203 printf("%s", strna(i
->id
));
2205 if (i
->description
&& !streq_ptr(i
->id
, i
->description
))
2206 printf(" - %s", i
->description
);
2211 printf("\t Follow: unit currently follows state of %s\n", i
->following
);
2213 if (streq_ptr(i
->load_state
, "error")) {
2214 on
= ansi_highlight_red(true);
2215 off
= ansi_highlight_red(false);
2220 printf("\t Loaded: %s%s%s (Reason: %s)\n", on
, strna(i
->load_state
), off
, i
->load_error
);
2221 else if (i
->path
&& i
->unit_file_state
)
2222 printf("\t Loaded: %s%s%s (%s; %s)\n", on
, strna(i
->load_state
), off
, i
->path
, i
->unit_file_state
);
2224 printf("\t Loaded: %s%s%s (%s)\n", on
, strna(i
->load_state
), off
, i
->path
);
2226 printf("\t Loaded: %s%s%s\n", on
, strna(i
->load_state
), off
);
2228 ss
= streq_ptr(i
->active_state
, i
->sub_state
) ? NULL
: i
->sub_state
;
2230 if (streq_ptr(i
->active_state
, "failed")) {
2231 on
= ansi_highlight_red(true);
2232 off
= ansi_highlight_red(false);
2233 } else if (streq_ptr(i
->active_state
, "active") || streq_ptr(i
->active_state
, "reloading")) {
2234 on
= ansi_highlight_green(true);
2235 off
= ansi_highlight_green(false);
2240 printf("\t Active: %s%s (%s)%s",
2242 strna(i
->active_state
),
2246 printf("\t Active: %s%s%s",
2248 strna(i
->active_state
),
2251 if (!isempty(i
->result
) && !streq(i
->result
, "success"))
2252 printf(" (Result: %s)", i
->result
);
2254 timestamp
= (streq_ptr(i
->active_state
, "active") ||
2255 streq_ptr(i
->active_state
, "reloading")) ? i
->active_enter_timestamp
:
2256 (streq_ptr(i
->active_state
, "inactive") ||
2257 streq_ptr(i
->active_state
, "failed")) ? i
->inactive_enter_timestamp
:
2258 streq_ptr(i
->active_state
, "activating") ? i
->inactive_exit_timestamp
:
2259 i
->active_exit_timestamp
;
2261 s1
= format_timestamp_pretty(since1
, sizeof(since1
), timestamp
);
2262 s2
= format_timestamp(since2
, sizeof(since2
), timestamp
);
2265 printf(" since %s; %s\n", s2
, s1
);
2267 printf(" since %s\n", s2
);
2271 if (!i
->condition_result
&& i
->condition_timestamp
> 0) {
2272 s1
= format_timestamp_pretty(since1
, sizeof(since1
), i
->condition_timestamp
);
2273 s2
= format_timestamp(since2
, sizeof(since2
), i
->condition_timestamp
);
2276 printf("\t start condition failed at %s; %s\n", s2
, s1
);
2278 printf("\t start condition failed at %s\n", s2
);
2282 printf("\t Device: %s\n", i
->sysfs_path
);
2284 printf("\t Where: %s\n", i
->where
);
2286 printf("\t What: %s\n", i
->what
);
2289 printf("\tAccepted: %u; Connected: %u\n", i
->n_accepted
, i
->n_connections
);
2291 LIST_FOREACH(exec
, p
, i
->exec
) {
2295 /* Only show exited processes here */
2299 t
= strv_join(p
->argv
, " ");
2300 printf("\t Process: %u %s=%s ", p
->pid
, p
->name
, strna(t
));
2303 #ifdef HAVE_SYSV_COMPAT
2305 good
= is_clean_exit_lsb(p
->code
, p
->status
);
2308 good
= is_clean_exit(p
->code
, p
->status
);
2311 on
= ansi_highlight_red(true);
2312 off
= ansi_highlight_red(false);
2316 printf("%s(code=%s, ", on
, sigchld_code_to_string(p
->code
));
2318 if (p
->code
== CLD_EXITED
) {
2321 printf("status=%i", p
->status
);
2323 #ifdef HAVE_SYSV_COMPAT
2324 if ((c
= exit_status_to_string(p
->status
, i
->is_sysv
? EXIT_STATUS_LSB
: EXIT_STATUS_SYSTEMD
)))
2326 if ((c
= exit_status_to_string(p
->status
, EXIT_STATUS_SYSTEMD
)))
2331 printf("signal=%s", signal_to_string(p
->status
));
2333 printf(")%s\n", off
);
2335 if (i
->main_pid
== p
->pid
&&
2336 i
->start_timestamp
== p
->start_timestamp
&&
2337 i
->exit_timestamp
== p
->start_timestamp
)
2338 /* Let's not show this twice */
2341 if (p
->pid
== i
->control_pid
)
2345 if (i
->main_pid
> 0 || i
->control_pid
> 0) {
2348 if (i
->main_pid
> 0) {
2349 printf("Main PID: %u", (unsigned) i
->main_pid
);
2353 get_process_comm(i
->main_pid
, &t
);
2358 } else if (i
->exit_code
> 0) {
2359 printf(" (code=%s, ", sigchld_code_to_string(i
->exit_code
));
2361 if (i
->exit_code
== CLD_EXITED
) {
2364 printf("status=%i", i
->exit_status
);
2366 #ifdef HAVE_SYSV_COMPAT
2367 if ((c
= exit_status_to_string(i
->exit_status
, i
->is_sysv
? EXIT_STATUS_LSB
: EXIT_STATUS_SYSTEMD
)))
2369 if ((c
= exit_status_to_string(i
->exit_status
, EXIT_STATUS_SYSTEMD
)))
2374 printf("signal=%s", signal_to_string(i
->exit_status
));
2379 if (i
->main_pid
> 0 && i
->control_pid
> 0)
2382 if (i
->control_pid
> 0) {
2385 printf(" Control: %u", (unsigned) i
->control_pid
);
2387 get_process_comm(i
->control_pid
, &t
);
2398 printf("\t Status: \"%s\"\n", i
->status_text
);
2400 if (i
->default_control_group
) {
2403 printf("\t CGroup: %s\n", i
->default_control_group
);
2405 if (arg_transport
!= TRANSPORT_SSH
) {
2415 if (i
->main_pid
> 0)
2416 extra
[k
++] = i
->main_pid
;
2418 if (i
->control_pid
> 0)
2419 extra
[k
++] = i
->control_pid
;
2421 show_cgroup_and_extra_by_spec(i
->default_control_group
, "\t\t ", c
, false, arg_all
, extra
, k
);
2425 if (i
->id
&& arg_transport
!= TRANSPORT_SSH
) {
2427 show_journal_by_unit(i
->id
, arg_output
, 0, i
->inactive_exit_timestamp_monotonic
, arg_lines
, arg_all
, arg_follow
);
2430 if (i
->need_daemon_reload
)
2431 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2432 ansi_highlight_red(true),
2433 ansi_highlight_red(false),
2434 arg_scope
== UNIT_FILE_SYSTEM
? "--system" : "--user");
2437 static int status_property(const char *name
, DBusMessageIter
*iter
, UnitStatusInfo
*i
) {
2443 switch (dbus_message_iter_get_arg_type(iter
)) {
2445 case DBUS_TYPE_STRING
: {
2448 dbus_message_iter_get_basic(iter
, &s
);
2451 if (streq(name
, "Id"))
2453 else if (streq(name
, "LoadState"))
2455 else if (streq(name
, "ActiveState"))
2456 i
->active_state
= s
;
2457 else if (streq(name
, "SubState"))
2459 else if (streq(name
, "Description"))
2461 else if (streq(name
, "FragmentPath"))
2463 #ifdef HAVE_SYSV_COMPAT
2464 else if (streq(name
, "SysVPath")) {
2469 else if (streq(name
, "DefaultControlGroup"))
2470 i
->default_control_group
= s
;
2471 else if (streq(name
, "StatusText"))
2473 else if (streq(name
, "SysFSPath"))
2475 else if (streq(name
, "Where"))
2477 else if (streq(name
, "What"))
2479 else if (streq(name
, "Following"))
2481 else if (streq(name
, "UnitFileState"))
2482 i
->unit_file_state
= s
;
2483 else if (streq(name
, "Result"))
2490 case DBUS_TYPE_BOOLEAN
: {
2493 dbus_message_iter_get_basic(iter
, &b
);
2495 if (streq(name
, "Accept"))
2497 else if (streq(name
, "NeedDaemonReload"))
2498 i
->need_daemon_reload
= b
;
2499 else if (streq(name
, "ConditionResult"))
2500 i
->condition_result
= b
;
2505 case DBUS_TYPE_UINT32
: {
2508 dbus_message_iter_get_basic(iter
, &u
);
2510 if (streq(name
, "MainPID")) {
2512 i
->main_pid
= (pid_t
) u
;
2515 } else if (streq(name
, "ControlPID"))
2516 i
->control_pid
= (pid_t
) u
;
2517 else if (streq(name
, "ExecMainPID")) {
2519 i
->main_pid
= (pid_t
) u
;
2520 } else if (streq(name
, "NAccepted"))
2522 else if (streq(name
, "NConnections"))
2523 i
->n_connections
= u
;
2528 case DBUS_TYPE_INT32
: {
2531 dbus_message_iter_get_basic(iter
, &j
);
2533 if (streq(name
, "ExecMainCode"))
2534 i
->exit_code
= (int) j
;
2535 else if (streq(name
, "ExecMainStatus"))
2536 i
->exit_status
= (int) j
;
2541 case DBUS_TYPE_UINT64
: {
2544 dbus_message_iter_get_basic(iter
, &u
);
2546 if (streq(name
, "ExecMainStartTimestamp"))
2547 i
->start_timestamp
= (usec_t
) u
;
2548 else if (streq(name
, "ExecMainExitTimestamp"))
2549 i
->exit_timestamp
= (usec_t
) u
;
2550 else if (streq(name
, "ActiveEnterTimestamp"))
2551 i
->active_enter_timestamp
= (usec_t
) u
;
2552 else if (streq(name
, "InactiveEnterTimestamp"))
2553 i
->inactive_enter_timestamp
= (usec_t
) u
;
2554 else if (streq(name
, "InactiveExitTimestamp"))
2555 i
->inactive_exit_timestamp
= (usec_t
) u
;
2556 else if (streq(name
, "InactiveExitTimestampMonotonic"))
2557 i
->inactive_exit_timestamp_monotonic
= (usec_t
) u
;
2558 else if (streq(name
, "ActiveExitTimestamp"))
2559 i
->active_exit_timestamp
= (usec_t
) u
;
2560 else if (streq(name
, "ConditionTimestamp"))
2561 i
->condition_timestamp
= (usec_t
) u
;
2566 case DBUS_TYPE_ARRAY
: {
2568 if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&&
2569 startswith(name
, "Exec")) {
2570 DBusMessageIter sub
;
2572 dbus_message_iter_recurse(iter
, &sub
);
2573 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2574 ExecStatusInfo
*info
;
2577 if (!(info
= new0(ExecStatusInfo
, 1)))
2580 if (!(info
->name
= strdup(name
))) {
2585 if ((r
= exec_status_info_deserialize(&sub
, info
)) < 0) {
2590 LIST_PREPEND(ExecStatusInfo
, exec
, i
->exec
, info
);
2592 dbus_message_iter_next(&sub
);
2599 case DBUS_TYPE_STRUCT
: {
2601 if (streq(name
, "LoadError")) {
2602 DBusMessageIter sub
;
2603 const char *n
, *message
;
2606 dbus_message_iter_recurse(iter
, &sub
);
2608 r
= bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &n
, true);
2612 r
= bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &message
, false);
2616 if (!isempty(message
))
2617 i
->load_error
= message
;
2627 static int print_property(const char *name
, DBusMessageIter
*iter
) {
2631 /* This is a low-level property printer, see
2632 * print_status_info() for the nicer output */
2634 if (arg_property
&& !strv_find(arg_property
, name
))
2637 switch (dbus_message_iter_get_arg_type(iter
)) {
2639 case DBUS_TYPE_STRUCT
: {
2640 DBusMessageIter sub
;
2641 dbus_message_iter_recurse(iter
, &sub
);
2643 if (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_UINT32
&& streq(name
, "Job")) {
2646 dbus_message_iter_get_basic(&sub
, &u
);
2649 printf("%s=%u\n", name
, (unsigned) u
);
2651 printf("%s=\n", name
);
2654 } else if (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRING
&& streq(name
, "Unit")) {
2657 dbus_message_iter_get_basic(&sub
, &s
);
2659 if (arg_all
|| s
[0])
2660 printf("%s=%s\n", name
, s
);
2663 } else if (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRING
&& streq(name
, "LoadError")) {
2664 const char *a
= NULL
, *b
= NULL
;
2666 if (bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &a
, true) >= 0)
2667 bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &b
, false);
2669 if (arg_all
|| !isempty(a
) || !isempty(b
))
2670 printf("%s=%s \"%s\"\n", name
, strempty(a
), strempty(b
));
2678 case DBUS_TYPE_ARRAY
:
2680 if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "EnvironmentFiles")) {
2681 DBusMessageIter sub
, sub2
;
2683 dbus_message_iter_recurse(iter
, &sub
);
2684 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2688 dbus_message_iter_recurse(&sub
, &sub2
);
2690 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) >= 0 &&
2691 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_BOOLEAN
, &ignore
, false) >= 0)
2692 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path
, yes_no(ignore
));
2694 dbus_message_iter_next(&sub
);
2699 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "Paths")) {
2700 DBusMessageIter sub
, sub2
;
2702 dbus_message_iter_recurse(iter
, &sub
);
2703 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2704 const char *type
, *path
;
2706 dbus_message_iter_recurse(&sub
, &sub2
);
2708 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) >= 0 &&
2709 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, false) >= 0)
2710 printf("%s=%s\n", type
, path
);
2712 dbus_message_iter_next(&sub
);
2717 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "Timers")) {
2718 DBusMessageIter sub
, sub2
;
2720 dbus_message_iter_recurse(iter
, &sub
);
2721 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2723 uint64_t value
, next_elapse
;
2725 dbus_message_iter_recurse(&sub
, &sub2
);
2727 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &base
, true) >= 0 &&
2728 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &value
, true) >= 0 &&
2729 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &next_elapse
, false) >= 0) {
2730 char timespan1
[FORMAT_TIMESPAN_MAX
], timespan2
[FORMAT_TIMESPAN_MAX
];
2732 printf("%s={ value=%s ; next_elapse=%s }\n",
2734 format_timespan(timespan1
, sizeof(timespan1
), value
),
2735 format_timespan(timespan2
, sizeof(timespan2
), next_elapse
));
2738 dbus_message_iter_next(&sub
);
2743 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "ControlGroupAttributes")) {
2744 DBusMessageIter sub
, sub2
;
2746 dbus_message_iter_recurse(iter
, &sub
);
2747 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2748 const char *controller
, *attr
, *value
;
2750 dbus_message_iter_recurse(&sub
, &sub2
);
2752 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &controller
, true) >= 0 &&
2753 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &attr
, true) >= 0 &&
2754 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &value
, false) >= 0) {
2756 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2762 dbus_message_iter_next(&sub
);
2767 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& startswith(name
, "Exec")) {
2768 DBusMessageIter sub
;
2770 dbus_message_iter_recurse(iter
, &sub
);
2771 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2772 ExecStatusInfo info
;
2775 if (exec_status_info_deserialize(&sub
, &info
) >= 0) {
2776 char timestamp1
[FORMAT_TIMESTAMP_MAX
], timestamp2
[FORMAT_TIMESTAMP_MAX
];
2779 t
= strv_join(info
.argv
, " ");
2781 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2785 yes_no(info
.ignore
),
2786 strna(format_timestamp(timestamp1
, sizeof(timestamp1
), info
.start_timestamp
)),
2787 strna(format_timestamp(timestamp2
, sizeof(timestamp2
), info
.exit_timestamp
)),
2788 (unsigned) info
. pid
,
2789 sigchld_code_to_string(info
.code
),
2791 info
.code
== CLD_EXITED
? "" : "/",
2792 strempty(info
.code
== CLD_EXITED
? NULL
: signal_to_string(info
.status
)));
2798 strv_free(info
.argv
);
2800 dbus_message_iter_next(&sub
);
2809 if (generic_print_property(name
, iter
, arg_all
) > 0)
2813 printf("%s=[unprintable]\n", name
);
2818 static int show_one(const char *verb
, DBusConnection
*bus
, const char *path
, bool show_properties
, bool *new_line
) {
2819 DBusMessage
*m
= NULL
, *reply
= NULL
;
2820 const char *interface
= "";
2823 DBusMessageIter iter
, sub
, sub2
, sub3
;
2824 UnitStatusInfo info
;
2832 dbus_error_init(&error
);
2834 if (!(m
= dbus_message_new_method_call(
2835 "org.freedesktop.systemd1",
2837 "org.freedesktop.DBus.Properties",
2839 log_error("Could not allocate message.");
2844 if (!dbus_message_append_args(m
,
2845 DBUS_TYPE_STRING
, &interface
,
2846 DBUS_TYPE_INVALID
)) {
2847 log_error("Could not append arguments to message.");
2852 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
2853 log_error("Failed to issue method call: %s", bus_error_message(&error
));
2858 if (!dbus_message_iter_init(reply
, &iter
) ||
2859 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
2860 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_DICT_ENTRY
) {
2861 log_error("Failed to parse reply.");
2866 dbus_message_iter_recurse(&iter
, &sub
);
2873 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
2876 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_DICT_ENTRY
) {
2877 log_error("Failed to parse reply.");
2882 dbus_message_iter_recurse(&sub
, &sub2
);
2884 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &name
, true) < 0) {
2885 log_error("Failed to parse reply.");
2890 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_VARIANT
) {
2891 log_error("Failed to parse reply.");
2896 dbus_message_iter_recurse(&sub2
, &sub3
);
2898 if (show_properties
)
2899 r
= print_property(name
, &sub3
);
2901 r
= status_property(name
, &sub3
, &info
);
2904 log_error("Failed to parse reply.");
2909 dbus_message_iter_next(&sub
);
2914 if (!show_properties
)
2915 print_status_info(&info
);
2917 if (!streq_ptr(info
.active_state
, "active") &&
2918 !streq_ptr(info
.active_state
, "reloading") &&
2919 streq(verb
, "status"))
2920 /* According to LSB: "program not running" */
2923 while ((p
= info
.exec
)) {
2924 LIST_REMOVE(ExecStatusInfo
, exec
, info
.exec
, p
);
2925 exec_status_info_free(p
);
2930 dbus_message_unref(m
);
2933 dbus_message_unref(reply
);
2935 dbus_error_free(&error
);
2940 static int show(DBusConnection
*bus
, char **args
) {
2941 DBusMessage
*m
= NULL
, *reply
= NULL
;
2944 bool show_properties
, new_line
= false;
2950 dbus_error_init(&error
);
2952 show_properties
= !streq(args
[0], "status");
2954 if (show_properties
)
2955 pager_open_if_enabled();
2957 if (show_properties
&& strv_length(args
) <= 1) {
2958 /* If not argument is specified inspect the manager
2961 ret
= show_one(args
[0], bus
, "/org/freedesktop/systemd1", show_properties
, &new_line
);
2965 STRV_FOREACH(name
, args
+1) {
2966 const char *path
= NULL
;
2969 if (safe_atou32(*name
, &id
) < 0) {
2971 /* Interpret as unit name */
2973 if (!(m
= dbus_message_new_method_call(
2974 "org.freedesktop.systemd1",
2975 "/org/freedesktop/systemd1",
2976 "org.freedesktop.systemd1.Manager",
2978 log_error("Could not allocate message.");
2983 if (!dbus_message_append_args(m
,
2984 DBUS_TYPE_STRING
, name
,
2985 DBUS_TYPE_INVALID
)) {
2986 log_error("Could not append arguments to message.");
2991 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
2993 if (!dbus_error_has_name(&error
, DBUS_ERROR_ACCESS_DENIED
)) {
2994 log_error("Failed to issue method call: %s", bus_error_message(&error
));
2999 dbus_error_free(&error
);
3001 dbus_message_unref(m
);
3002 if (!(m
= dbus_message_new_method_call(
3003 "org.freedesktop.systemd1",
3004 "/org/freedesktop/systemd1",
3005 "org.freedesktop.systemd1.Manager",
3007 log_error("Could not allocate message.");
3012 if (!dbus_message_append_args(m
,
3013 DBUS_TYPE_STRING
, name
,
3014 DBUS_TYPE_INVALID
)) {
3015 log_error("Could not append arguments to message.");
3020 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3021 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3023 if (dbus_error_has_name(&error
, BUS_ERROR_NO_SUCH_UNIT
))
3024 ret
= 4; /* According to LSB: "program or service status is unknown" */
3031 } else if (show_properties
) {
3033 /* Interpret as job id */
3035 if (!(m
= dbus_message_new_method_call(
3036 "org.freedesktop.systemd1",
3037 "/org/freedesktop/systemd1",
3038 "org.freedesktop.systemd1.Manager",
3040 log_error("Could not allocate message.");
3045 if (!dbus_message_append_args(m
,
3046 DBUS_TYPE_UINT32
, &id
,
3047 DBUS_TYPE_INVALID
)) {
3048 log_error("Could not append arguments to message.");
3053 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3054 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3060 /* Interpret as PID */
3062 if (!(m
= dbus_message_new_method_call(
3063 "org.freedesktop.systemd1",
3064 "/org/freedesktop/systemd1",
3065 "org.freedesktop.systemd1.Manager",
3067 log_error("Could not allocate message.");
3072 if (!dbus_message_append_args(m
,
3073 DBUS_TYPE_UINT32
, &id
,
3074 DBUS_TYPE_INVALID
)) {
3075 log_error("Could not append arguments to message.");
3080 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3081 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3087 if (!dbus_message_get_args(reply
, &error
,
3088 DBUS_TYPE_OBJECT_PATH
, &path
,
3089 DBUS_TYPE_INVALID
)) {
3090 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3095 if ((r
= show_one(args
[0], bus
, path
, show_properties
, &new_line
)) != 0)
3098 dbus_message_unref(m
);
3099 dbus_message_unref(reply
);
3105 dbus_message_unref(m
);
3108 dbus_message_unref(reply
);
3110 dbus_error_free(&error
);
3115 static int dump(DBusConnection
*bus
, char **args
) {
3116 DBusMessage
*m
= NULL
, *reply
= NULL
;
3121 dbus_error_init(&error
);
3123 pager_open_if_enabled();
3125 if (!(m
= dbus_message_new_method_call(
3126 "org.freedesktop.systemd1",
3127 "/org/freedesktop/systemd1",
3128 "org.freedesktop.systemd1.Manager",
3130 log_error("Could not allocate message.");
3134 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3135 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3140 if (!dbus_message_get_args(reply
, &error
,
3141 DBUS_TYPE_STRING
, &text
,
3142 DBUS_TYPE_INVALID
)) {
3143 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3148 fputs(text
, stdout
);
3154 dbus_message_unref(m
);
3157 dbus_message_unref(reply
);
3159 dbus_error_free(&error
);
3164 static int snapshot(DBusConnection
*bus
, char **args
) {
3165 DBusMessage
*m
= NULL
, *reply
= NULL
;
3168 const char *name
= "", *path
, *id
;
3169 dbus_bool_t cleanup
= FALSE
;
3170 DBusMessageIter iter
, sub
;
3172 *interface
= "org.freedesktop.systemd1.Unit",
3175 dbus_error_init(&error
);
3177 if (!(m
= dbus_message_new_method_call(
3178 "org.freedesktop.systemd1",
3179 "/org/freedesktop/systemd1",
3180 "org.freedesktop.systemd1.Manager",
3181 "CreateSnapshot"))) {
3182 log_error("Could not allocate message.");
3186 if (strv_length(args
) > 1)
3189 if (!dbus_message_append_args(m
,
3190 DBUS_TYPE_STRING
, &name
,
3191 DBUS_TYPE_BOOLEAN
, &cleanup
,
3192 DBUS_TYPE_INVALID
)) {
3193 log_error("Could not append arguments to message.");
3198 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3199 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3204 if (!dbus_message_get_args(reply
, &error
,
3205 DBUS_TYPE_OBJECT_PATH
, &path
,
3206 DBUS_TYPE_INVALID
)) {
3207 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3212 dbus_message_unref(m
);
3213 if (!(m
= dbus_message_new_method_call(
3214 "org.freedesktop.systemd1",
3216 "org.freedesktop.DBus.Properties",
3218 log_error("Could not allocate message.");
3222 if (!dbus_message_append_args(m
,
3223 DBUS_TYPE_STRING
, &interface
,
3224 DBUS_TYPE_STRING
, &property
,
3225 DBUS_TYPE_INVALID
)) {
3226 log_error("Could not append arguments to message.");
3231 dbus_message_unref(reply
);
3232 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3233 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3238 if (!dbus_message_iter_init(reply
, &iter
) ||
3239 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
3240 log_error("Failed to parse reply.");
3245 dbus_message_iter_recurse(&iter
, &sub
);
3247 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRING
) {
3248 log_error("Failed to parse reply.");
3253 dbus_message_iter_get_basic(&sub
, &id
);
3261 dbus_message_unref(m
);
3264 dbus_message_unref(reply
);
3266 dbus_error_free(&error
);
3271 static int delete_snapshot(DBusConnection
*bus
, char **args
) {
3272 DBusMessage
*m
= NULL
, *reply
= NULL
;
3280 dbus_error_init(&error
);
3282 STRV_FOREACH(name
, args
+1) {
3283 const char *path
= NULL
;
3285 if (!(m
= dbus_message_new_method_call(
3286 "org.freedesktop.systemd1",
3287 "/org/freedesktop/systemd1",
3288 "org.freedesktop.systemd1.Manager",
3290 log_error("Could not allocate message.");
3295 if (!dbus_message_append_args(m
,
3296 DBUS_TYPE_STRING
, name
,
3297 DBUS_TYPE_INVALID
)) {
3298 log_error("Could not append arguments to message.");
3303 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3304 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3309 if (!dbus_message_get_args(reply
, &error
,
3310 DBUS_TYPE_OBJECT_PATH
, &path
,
3311 DBUS_TYPE_INVALID
)) {
3312 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3317 dbus_message_unref(m
);
3318 if (!(m
= dbus_message_new_method_call(
3319 "org.freedesktop.systemd1",
3321 "org.freedesktop.systemd1.Snapshot",
3323 log_error("Could not allocate message.");
3328 dbus_message_unref(reply
);
3329 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3330 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3335 dbus_message_unref(m
);
3336 dbus_message_unref(reply
);
3344 dbus_message_unref(m
);
3347 dbus_message_unref(reply
);
3349 dbus_error_free(&error
);
3354 static int daemon_reload(DBusConnection
*bus
, char **args
) {
3355 DBusMessage
*m
= NULL
, *reply
= NULL
;
3360 dbus_error_init(&error
);
3362 if (arg_action
== ACTION_RELOAD
)
3364 else if (arg_action
== ACTION_REEXEC
)
3365 method
= "Reexecute";
3367 assert(arg_action
== ACTION_SYSTEMCTL
);
3370 streq(args
[0], "clear-jobs") ||
3371 streq(args
[0], "cancel") ? "ClearJobs" :
3372 streq(args
[0], "daemon-reexec") ? "Reexecute" :
3373 streq(args
[0], "reset-failed") ? "ResetFailed" :
3374 streq(args
[0], "halt") ? "Halt" :
3375 streq(args
[0], "poweroff") ? "PowerOff" :
3376 streq(args
[0], "reboot") ? "Reboot" :
3377 streq(args
[0], "kexec") ? "KExec" :
3378 streq(args
[0], "exit") ? "Exit" :
3379 /* "daemon-reload" */ "Reload";
3382 if (!(m
= dbus_message_new_method_call(
3383 "org.freedesktop.systemd1",
3384 "/org/freedesktop/systemd1",
3385 "org.freedesktop.systemd1.Manager",
3387 log_error("Could not allocate message.");
3391 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3393 if (arg_action
!= ACTION_SYSTEMCTL
&& error_is_no_service(&error
)) {
3394 /* There's always a fallback possible for
3395 * legacy actions. */
3400 if (streq(method
, "Reexecute") && dbus_error_has_name(&error
, DBUS_ERROR_NO_REPLY
)) {
3401 /* On reexecution, we expect a disconnect, not
3407 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3416 dbus_message_unref(m
);
3419 dbus_message_unref(reply
);
3421 dbus_error_free(&error
);
3426 static int reset_failed(DBusConnection
*bus
, char **args
) {
3427 DBusMessage
*m
= NULL
;
3433 dbus_error_init(&error
);
3435 if (strv_length(args
) <= 1)
3436 return daemon_reload(bus
, args
);
3438 STRV_FOREACH(name
, args
+1) {
3441 if (!(m
= dbus_message_new_method_call(
3442 "org.freedesktop.systemd1",
3443 "/org/freedesktop/systemd1",
3444 "org.freedesktop.systemd1.Manager",
3445 "ResetFailedUnit"))) {
3446 log_error("Could not allocate message.");
3451 if (!dbus_message_append_args(m
,
3452 DBUS_TYPE_STRING
, name
,
3453 DBUS_TYPE_INVALID
)) {
3454 log_error("Could not append arguments to message.");
3459 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3460 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3465 dbus_message_unref(m
);
3466 dbus_message_unref(reply
);
3474 dbus_message_unref(m
);
3476 dbus_error_free(&error
);
3481 static int show_enviroment(DBusConnection
*bus
, char **args
) {
3482 DBusMessage
*m
= NULL
, *reply
= NULL
;
3484 DBusMessageIter iter
, sub
, sub2
;
3487 *interface
= "org.freedesktop.systemd1.Manager",
3488 *property
= "Environment";
3490 dbus_error_init(&error
);
3492 pager_open_if_enabled();
3494 if (!(m
= dbus_message_new_method_call(
3495 "org.freedesktop.systemd1",
3496 "/org/freedesktop/systemd1",
3497 "org.freedesktop.DBus.Properties",
3499 log_error("Could not allocate message.");
3503 if (!dbus_message_append_args(m
,
3504 DBUS_TYPE_STRING
, &interface
,
3505 DBUS_TYPE_STRING
, &property
,
3506 DBUS_TYPE_INVALID
)) {
3507 log_error("Could not append arguments to message.");
3512 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3513 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3518 if (!dbus_message_iter_init(reply
, &iter
) ||
3519 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
3520 log_error("Failed to parse reply.");
3525 dbus_message_iter_recurse(&iter
, &sub
);
3527 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_ARRAY
||
3528 dbus_message_iter_get_element_type(&sub
) != DBUS_TYPE_STRING
) {
3529 log_error("Failed to parse reply.");
3534 dbus_message_iter_recurse(&sub
, &sub2
);
3536 while (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_INVALID
) {
3539 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_STRING
) {
3540 log_error("Failed to parse reply.");
3545 dbus_message_iter_get_basic(&sub2
, &text
);
3546 printf("%s\n", text
);
3548 dbus_message_iter_next(&sub2
);
3555 dbus_message_unref(m
);
3558 dbus_message_unref(reply
);
3560 dbus_error_free(&error
);
3565 static int set_environment(DBusConnection
*bus
, char **args
) {
3566 DBusMessage
*m
= NULL
, *reply
= NULL
;
3570 DBusMessageIter iter
, sub
;
3573 dbus_error_init(&error
);
3575 method
= streq(args
[0], "set-environment")
3577 : "UnsetEnvironment";
3579 if (!(m
= dbus_message_new_method_call(
3580 "org.freedesktop.systemd1",
3581 "/org/freedesktop/systemd1",
3582 "org.freedesktop.systemd1.Manager",
3585 log_error("Could not allocate message.");
3589 dbus_message_iter_init_append(m
, &iter
);
3591 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "s", &sub
)) {
3592 log_error("Could not append arguments to message.");
3597 STRV_FOREACH(name
, args
+1)
3598 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, name
)) {
3599 log_error("Could not append arguments to message.");
3604 if (!dbus_message_iter_close_container(&iter
, &sub
)) {
3605 log_error("Could not append arguments to message.");
3610 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3611 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3620 dbus_message_unref(m
);
3623 dbus_message_unref(reply
);
3625 dbus_error_free(&error
);
3630 static int enable_sysv_units(char **args
) {
3633 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3634 const char *verb
= args
[0];
3635 unsigned f
= 1, t
= 1;
3638 if (arg_scope
!= UNIT_FILE_SYSTEM
)
3641 if (!streq(verb
, "enable") &&
3642 !streq(verb
, "disable") &&
3643 !streq(verb
, "is-enabled"))
3646 /* Processes all SysV units, and reshuffles the array so that
3647 * afterwards only the native units remain */
3650 r
= lookup_paths_init(&paths
, MANAGER_SYSTEM
, false);
3656 for (f
= 1; args
[f
]; f
++) {
3659 bool found_native
= false, found_sysv
;
3661 const char *argv
[6] = { "/sbin/chkconfig", NULL
, NULL
, NULL
, NULL
};
3662 char **k
, *l
, *q
= NULL
;
3669 if (!endswith(name
, ".service"))
3672 if (path_is_absolute(name
))
3675 STRV_FOREACH(k
, paths
.unit_path
) {
3678 if (!isempty(arg_root
))
3679 asprintf(&p
, "%s/%s/%s", arg_root
, *k
, name
);
3681 asprintf(&p
, "%s/%s", *k
, name
);
3684 log_error("No memory");
3689 found_native
= access(p
, F_OK
) >= 0;
3700 if (!isempty(arg_root
))
3701 asprintf(&p
, "%s/" SYSTEM_SYSVINIT_PATH
"/%s", arg_root
, name
);
3703 asprintf(&p
, SYSTEM_SYSVINIT_PATH
"/%s", name
);
3705 log_error("No memory");
3710 p
[strlen(p
) - sizeof(".service") + 1] = 0;
3711 found_sysv
= access(p
, F_OK
) >= 0;
3718 /* Mark this entry, so that we don't try enabling it as native unit */
3719 args
[f
] = (char*) "";
3721 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name
);
3723 if (!isempty(arg_root
))
3724 argv
[c
++] = q
= strappend("--root=", arg_root
);
3726 argv
[c
++] = path_get_file_name(p
);
3728 streq(verb
, "enable") ? "on" :
3729 streq(verb
, "disable") ? "off" : "--level=5";
3732 l
= strv_join((char**)argv
, " ");
3734 log_error("No memory.");
3741 log_info("Executing %s", l
);
3746 log_error("Failed to fork: %m");
3751 } else if (pid
== 0) {
3754 execv(argv
[0], (char**) argv
);
3755 _exit(EXIT_FAILURE
);
3761 j
= wait_for_terminate(pid
, &status
);
3763 log_error("Failed to wait for child: %s", strerror(-r
));
3768 if (status
.si_code
== CLD_EXITED
) {
3769 if (streq(verb
, "is-enabled")) {
3770 if (status
.si_status
== 0) {
3779 } else if (status
.si_status
!= 0) {
3790 lookup_paths_free(&paths
);
3792 /* Drop all SysV units */
3793 for (f
= 1, t
= 1; args
[f
]; f
++) {
3795 if (isempty(args
[f
]))
3798 args
[t
++] = args
[f
];
3807 static int enable_unit(DBusConnection
*bus
, char **args
) {
3808 const char *verb
= args
[0];
3809 UnitFileChange
*changes
= NULL
;
3810 unsigned n_changes
= 0, i
;
3811 int carries_install_info
= -1;
3812 DBusMessage
*m
= NULL
, *reply
= NULL
;
3816 r
= enable_sysv_units(args
);
3823 dbus_error_init(&error
);
3825 if (!bus
|| avoid_bus()) {
3826 if (streq(verb
, "enable")) {
3827 r
= unit_file_enable(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3828 carries_install_info
= r
;
3829 } else if (streq(verb
, "disable"))
3830 r
= unit_file_disable(arg_scope
, arg_runtime
, arg_root
, args
+1, &changes
, &n_changes
);
3831 else if (streq(verb
, "reenable")) {
3832 r
= unit_file_reenable(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3833 carries_install_info
= r
;
3834 } else if (streq(verb
, "link"))
3835 r
= unit_file_link(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3836 else if (streq(verb
, "preset")) {
3837 r
= unit_file_preset(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3838 carries_install_info
= r
;
3839 } else if (streq(verb
, "mask"))
3840 r
= unit_file_mask(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3841 else if (streq(verb
, "unmask"))
3842 r
= unit_file_unmask(arg_scope
, arg_runtime
, arg_root
, args
+1, &changes
, &n_changes
);
3844 assert_not_reached("Unknown verb");
3847 log_error("Operation failed: %s", strerror(-r
));
3852 for (i
= 0; i
< n_changes
; i
++) {
3853 if (changes
[i
].type
== UNIT_FILE_SYMLINK
)
3854 log_info("ln -s '%s' '%s'", changes
[i
].source
, changes
[i
].path
);
3856 log_info("rm '%s'", changes
[i
].path
);
3862 bool send_force
= true, expect_carries_install_info
= false;
3864 DBusMessageIter iter
, sub
, sub2
;
3866 if (streq(verb
, "enable")) {
3867 method
= "EnableUnitFiles";
3868 expect_carries_install_info
= true;
3869 } else if (streq(verb
, "disable")) {
3870 method
= "DisableUnitFiles";
3872 } else if (streq(verb
, "reenable")) {
3873 method
= "ReenableUnitFiles";
3874 expect_carries_install_info
= true;
3875 } else if (streq(verb
, "link"))
3876 method
= "LinkUnitFiles";
3877 else if (streq(verb
, "preset")) {
3878 method
= "PresetUnitFiles";
3879 expect_carries_install_info
= true;
3880 } else if (streq(verb
, "mask"))
3881 method
= "MaskUnitFiles";
3882 else if (streq(verb
, "unmask")) {
3883 method
= "UnmaskUnitFiles";
3886 assert_not_reached("Unknown verb");
3888 m
= dbus_message_new_method_call(
3889 "org.freedesktop.systemd1",
3890 "/org/freedesktop/systemd1",
3891 "org.freedesktop.systemd1.Manager",
3894 log_error("Out of memory");
3899 dbus_message_iter_init_append(m
, &iter
);
3901 r
= bus_append_strv_iter(&iter
, args
+1);
3903 log_error("Failed to append unit files.");
3908 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &a
)) {
3909 log_error("Failed to append runtime boolean.");
3917 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &b
)) {
3918 log_error("Failed to append force boolean.");
3924 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
3926 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3931 if (!dbus_message_iter_init(reply
, &iter
)) {
3932 log_error("Failed to initialize iterator.");
3936 if (expect_carries_install_info
) {
3937 r
= bus_iter_get_basic_and_next(&iter
, DBUS_TYPE_BOOLEAN
, &b
, true);
3939 log_error("Failed to parse reply.");
3943 carries_install_info
= b
;
3946 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
3947 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
3948 log_error("Failed to parse reply.");
3953 dbus_message_iter_recurse(&iter
, &sub
);
3954 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
3955 const char *type
, *path
, *source
;
3957 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
3958 log_error("Failed to parse reply.");
3963 dbus_message_iter_recurse(&sub
, &sub2
);
3965 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) < 0 ||
3966 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0 ||
3967 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &source
, false) < 0) {
3968 log_error("Failed to parse reply.");
3974 if (streq(type
, "symlink"))
3975 log_info("ln -s '%s' '%s'", source
, path
);
3977 log_info("rm '%s'", path
);
3980 dbus_message_iter_next(&sub
);
3983 /* Try to reload if enabeld */
3985 r
= daemon_reload(bus
, args
);
3988 if (carries_install_info
== 0)
3989 log_warning("Warning: unit files do not carry install information. No operation executed.");
3993 dbus_message_unref(m
);
3996 dbus_message_unref(reply
);
3998 unit_file_changes_free(changes
, n_changes
);
4000 dbus_error_free(&error
);
4004 static int unit_is_enabled(DBusConnection
*bus
, char **args
) {
4007 DBusMessage
*m
= NULL
, *reply
= NULL
;
4011 dbus_error_init(&error
);
4013 r
= enable_sysv_units(args
);
4019 if (!bus
|| avoid_bus()) {
4021 STRV_FOREACH(name
, args
+1) {
4022 UnitFileState state
;
4024 state
= unit_file_get_state(arg_scope
, arg_root
, *name
);
4030 if (state
== UNIT_FILE_ENABLED
||
4031 state
== UNIT_FILE_ENABLED_RUNTIME
||
4032 state
== UNIT_FILE_STATIC
)
4036 puts(unit_file_state_to_string(state
));
4040 STRV_FOREACH(name
, args
+1) {
4043 m
= dbus_message_new_method_call(
4044 "org.freedesktop.systemd1",
4045 "/org/freedesktop/systemd1",
4046 "org.freedesktop.systemd1.Manager",
4047 "GetUnitFileState");
4049 log_error("Out of memory");
4054 if (!dbus_message_append_args(m
,
4055 DBUS_TYPE_STRING
, name
,
4056 DBUS_TYPE_INVALID
)) {
4057 log_error("Could not append arguments to message.");
4062 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
4064 log_error("Failed to issue method call: %s", bus_error_message(&error
));
4069 if (!dbus_message_get_args(reply
, &error
,
4070 DBUS_TYPE_STRING
, &s
,
4071 DBUS_TYPE_INVALID
)) {
4072 log_error("Failed to parse reply: %s", bus_error_message(&error
));
4077 dbus_message_unref(m
);
4078 dbus_message_unref(reply
);
4081 if (streq(s
, "enabled") ||
4082 streq(s
, "enabled-runtime") ||
4091 r
= enabled
? 0 : 1;
4095 dbus_message_unref(m
);
4098 dbus_message_unref(reply
);
4100 dbus_error_free(&error
);
4104 static int systemctl_help(void) {
4106 pager_open_if_enabled();
4108 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4109 "Query or send control commands to the systemd manager.\n\n"
4110 " -h --help Show this help\n"
4111 " --version Show package version\n"
4112 " -t --type=TYPE List only units of a particular type\n"
4113 " -p --property=NAME Show only properties by this name\n"
4114 " -a --all Show all units/properties, including dead/empty ones\n"
4115 " --failed Show only failed units\n"
4116 " --full Don't ellipsize unit names on output\n"
4117 " --fail When queueing a new job, fail if conflicting jobs are\n"
4119 " --ignore-dependencies\n"
4120 " When queueing a new job, ignore all its dependencies\n"
4121 " --kill-who=WHO Who to send signal to\n"
4122 " -s --signal=SIGNAL Which signal to send\n"
4123 " -H --host=[USER@]HOST\n"
4124 " Show information for remote host\n"
4125 " -P --privileged Acquire privileges before execution\n"
4126 " -q --quiet Suppress output\n"
4127 " --no-block Do not wait until operation finished\n"
4128 " --no-wall Don't send wall message before halt/power-off/reboot\n"
4129 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4131 " --no-legend Do not print a legend (column headers and hints)\n"
4132 " --no-pager Do not pipe output into a pager\n"
4133 " --no-ask-password\n"
4134 " Do not ask for system passwords\n"
4135 " --order When generating graph for dot, show only order\n"
4136 " --require When generating graph for dot, show only requirement\n"
4137 " --system Connect to system manager\n"
4138 " --user Connect to user service manager\n"
4139 " --global Enable/disable unit files globally\n"
4140 " -f --force When enabling unit files, override existing symlinks\n"
4141 " When shutting down, execute action immediately\n"
4142 " --root=PATH Enable unit files in the specified root directory\n"
4143 " --runtime Enable unit files only temporarily until next reboot\n"
4144 " -n --lines=INTEGER Journal entries to show\n"
4145 " --follow Follow journal\n"
4146 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
4147 " verbose, export, json, cat)\n\n"
4149 " list-units List loaded units\n"
4150 " start [NAME...] Start (activate) one or more units\n"
4151 " stop [NAME...] Stop (deactivate) one or more units\n"
4152 " reload [NAME...] Reload one or more units\n"
4153 " restart [NAME...] Start or restart one or more units\n"
4154 " try-restart [NAME...] Restart one or more units if active\n"
4155 " reload-or-restart [NAME...] Reload one or more units is possible,\n"
4156 " otherwise start or restart\n"
4157 " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4158 " otherwise restart if active\n"
4159 " isolate [NAME] Start one unit and stop all others\n"
4160 " kill [NAME...] Send signal to processes of a unit\n"
4161 " is-active [NAME...] Check whether units are active\n"
4162 " status [NAME...|PID...] Show runtime status of one or more units\n"
4163 " show [NAME...|JOB...] Show properties of one or more\n"
4164 " units/jobs or the manager\n"
4165 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4167 " load [NAME...] Load one or more units\n\n"
4168 "Unit File Commands:\n"
4169 " list-unit-files List installed unit files\n"
4170 " enable [NAME...] Enable one or more unit files\n"
4171 " disable [NAME...] Disable one or more unit files\n"
4172 " reenable [NAME...] Reenable one or more unit files\n"
4173 " preset [NAME...] Enable/disable one or more unit files\n"
4174 " based on preset configuration\n"
4175 " mask [NAME...] Mask one or more units\n"
4176 " unmask [NAME...] Unmask one or more units\n"
4177 " link [PATH...] Link one or more units files into\n"
4178 " the search path\n"
4179 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
4181 " list-jobs List jobs\n"
4182 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
4183 "Status Commands:\n"
4184 " dump Dump server status\n"
4185 " dot Dump dependency graph for dot(1)\n\n"
4186 "Snapshot Commands:\n"
4187 " snapshot [NAME] Create a snapshot\n"
4188 " delete [NAME...] Remove one or more snapshots\n\n"
4189 "Environment Commands:\n"
4190 " show-environment Dump environment\n"
4191 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
4192 " unset-environment [NAME...] Unset one or more environment variables\n\n"
4193 "Manager Lifecycle Commands:\n"
4194 " daemon-reload Reload systemd manager configuration\n"
4195 " daemon-reexec Reexecute systemd manager\n\n"
4196 "System Commands:\n"
4197 " default Enter system default mode\n"
4198 " rescue Enter system rescue mode\n"
4199 " emergency Enter system emergency mode\n"
4200 " halt Shut down and halt the system\n"
4201 " poweroff Shut down and power-off the system\n"
4202 " reboot Shut down and reboot the system\n"
4203 " kexec Shut down and reboot the system with kexec\n"
4204 " exit Ask for user instance termination\n",
4205 program_invocation_short_name
);
4210 static int halt_help(void) {
4212 printf("%s [OPTIONS...]\n\n"
4213 "%s the system.\n\n"
4214 " --help Show this help\n"
4215 " --halt Halt the machine\n"
4216 " -p --poweroff Switch off the machine\n"
4217 " --reboot Reboot the machine\n"
4218 " -f --force Force immediate halt/power-off/reboot\n"
4219 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4220 " -d --no-wtmp Don't write wtmp record\n"
4221 " -n --no-sync Don't sync before halt/power-off/reboot\n"
4222 " --no-wall Don't send wall message before halt/power-off/reboot\n",
4223 program_invocation_short_name
,
4224 arg_action
== ACTION_REBOOT
? "Reboot" :
4225 arg_action
== ACTION_POWEROFF
? "Power off" :
4231 static int shutdown_help(void) {
4233 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4234 "Shut down the system.\n\n"
4235 " --help Show this help\n"
4236 " -H --halt Halt the machine\n"
4237 " -P --poweroff Power-off the machine\n"
4238 " -r --reboot Reboot the machine\n"
4239 " -h Equivalent to --poweroff, overriden by --halt\n"
4240 " -k Don't halt/power-off/reboot, just send warnings\n"
4241 " --no-wall Don't send wall message before halt/power-off/reboot\n"
4242 " -c Cancel a pending shutdown\n",
4243 program_invocation_short_name
);
4248 static int telinit_help(void) {
4250 printf("%s [OPTIONS...] {COMMAND}\n\n"
4251 "Send control commands to the init daemon.\n\n"
4252 " --help Show this help\n"
4253 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
4255 " 0 Power-off the machine\n"
4256 " 6 Reboot the machine\n"
4257 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4258 " 1, s, S Enter rescue mode\n"
4259 " q, Q Reload init daemon configuration\n"
4260 " u, U Reexecute init daemon\n",
4261 program_invocation_short_name
);
4266 static int runlevel_help(void) {
4268 printf("%s [OPTIONS...]\n\n"
4269 "Prints the previous and current runlevel of the init system.\n\n"
4270 " --help Show this help\n",
4271 program_invocation_short_name
);
4276 static int systemctl_parse_argv(int argc
, char *argv
[]) {
4280 ARG_IGNORE_DEPENDENCIES
,
4296 ARG_NO_ASK_PASSWORD
,
4303 static const struct option options
[] = {
4304 { "help", no_argument
, NULL
, 'h' },
4305 { "version", no_argument
, NULL
, ARG_VERSION
},
4306 { "type", required_argument
, NULL
, 't' },
4307 { "property", required_argument
, NULL
, 'p' },
4308 { "all", no_argument
, NULL
, 'a' },
4309 { "failed", no_argument
, NULL
, ARG_FAILED
},
4310 { "full", no_argument
, NULL
, ARG_FULL
},
4311 { "fail", no_argument
, NULL
, ARG_FAIL
},
4312 { "ignore-dependencies", no_argument
, NULL
, ARG_IGNORE_DEPENDENCIES
},
4313 { "user", no_argument
, NULL
, ARG_USER
},
4314 { "system", no_argument
, NULL
, ARG_SYSTEM
},
4315 { "global", no_argument
, NULL
, ARG_GLOBAL
},
4316 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
4317 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
4318 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
4319 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4320 { "quiet", no_argument
, NULL
, 'q' },
4321 { "order", no_argument
, NULL
, ARG_ORDER
},
4322 { "require", no_argument
, NULL
, ARG_REQUIRE
},
4323 { "root", required_argument
, NULL
, ARG_ROOT
},
4324 { "force", no_argument
, NULL
, ARG_FORCE
},
4325 { "no-reload", no_argument
, NULL
, ARG_NO_RELOAD
},
4326 { "kill-mode", required_argument
, NULL
, ARG_KILL_MODE
}, /* undocumented on purpose */
4327 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
4328 { "signal", required_argument
, NULL
, 's' },
4329 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
4330 { "host", required_argument
, NULL
, 'H' },
4331 { "privileged",no_argument
, NULL
, 'P' },
4332 { "runtime", no_argument
, NULL
, ARG_RUNTIME
},
4333 { "lines", required_argument
, NULL
, 'n' },
4334 { "follow", no_argument
, NULL
, ARG_FOLLOW
},
4335 { "output", required_argument
, NULL
, 'o' },
4336 { NULL
, 0, NULL
, 0 }
4344 while ((c
= getopt_long(argc
, argv
, "ht:p:aqfs:H:Pn:o:", options
, NULL
)) >= 0) {
4353 puts(PACKAGE_STRING
);
4355 puts(SYSTEMD_FEATURES
);
4365 if (!(l
= strv_append(arg_property
, optarg
)))
4368 strv_free(arg_property
);
4371 /* If the user asked for a particular
4372 * property, show it to him, even if it is
4383 arg_job_mode
= "fail";
4386 case ARG_IGNORE_DEPENDENCIES
:
4387 arg_job_mode
= "ignore-dependencies";
4391 arg_scope
= UNIT_FILE_USER
;
4395 arg_scope
= UNIT_FILE_SYSTEM
;
4399 arg_scope
= UNIT_FILE_GLOBAL
;
4403 arg_no_block
= true;
4407 arg_no_legend
= true;
4411 arg_no_pager
= true;
4419 arg_dot
= DOT_ORDER
;
4423 arg_dot
= DOT_REQUIRE
;
4451 /* -f is short for both --follow and --force! */
4457 arg_no_reload
= true;
4461 arg_kill_who
= optarg
;
4465 arg_kill_mode
= optarg
;
4469 if ((arg_signal
= signal_from_string_try_harder(optarg
)) < 0) {
4470 log_error("Failed to parse signal string %s.", optarg
);
4475 case ARG_NO_ASK_PASSWORD
:
4476 arg_ask_password
= false;
4480 arg_transport
= TRANSPORT_POLKIT
;
4484 arg_transport
= TRANSPORT_SSH
;
4493 if (safe_atou(optarg
, &arg_lines
) < 0) {
4494 log_error("Failed to parse lines '%s'", optarg
);
4500 arg_output
= output_mode_from_string(optarg
);
4501 if (arg_output
< 0) {
4502 log_error("Unknown output '%s'.", optarg
);
4511 log_error("Unknown option code %c", c
);
4516 if (arg_transport
!= TRANSPORT_NORMAL
&& arg_scope
!= UNIT_FILE_SYSTEM
) {
4517 log_error("Cannot access user instance remotely.");
4524 static int halt_parse_argv(int argc
, char *argv
[]) {
4533 static const struct option options
[] = {
4534 { "help", no_argument
, NULL
, ARG_HELP
},
4535 { "halt", no_argument
, NULL
, ARG_HALT
},
4536 { "poweroff", no_argument
, NULL
, 'p' },
4537 { "reboot", no_argument
, NULL
, ARG_REBOOT
},
4538 { "force", no_argument
, NULL
, 'f' },
4539 { "wtmp-only", no_argument
, NULL
, 'w' },
4540 { "no-wtmp", no_argument
, NULL
, 'd' },
4541 { "no-sync", no_argument
, NULL
, 'n' },
4542 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4543 { NULL
, 0, NULL
, 0 }
4551 if (utmp_get_runlevel(&runlevel
, NULL
) >= 0)
4552 if (runlevel
== '0' || runlevel
== '6')
4555 while ((c
= getopt_long(argc
, argv
, "pfwdnih", options
, NULL
)) >= 0) {
4563 arg_action
= ACTION_HALT
;
4567 if (arg_action
!= ACTION_REBOOT
)
4568 arg_action
= ACTION_POWEROFF
;
4572 arg_action
= ACTION_REBOOT
;
4597 /* Compatibility nops */
4604 log_error("Unknown option code %c", c
);
4609 if (optind
< argc
) {
4610 log_error("Too many arguments.");
4617 static int parse_time_spec(const char *t
, usec_t
*_u
) {
4621 if (streq(t
, "now"))
4623 else if (!strchr(t
, ':')) {
4626 if (safe_atou64(t
, &u
) < 0)
4629 *_u
= now(CLOCK_REALTIME
) + USEC_PER_MINUTE
* u
;
4638 hour
= strtol(t
, &e
, 10);
4639 if (errno
!= 0 || *e
!= ':' || hour
< 0 || hour
> 23)
4642 minute
= strtol(e
+1, &e
, 10);
4643 if (errno
!= 0 || *e
!= 0 || minute
< 0 || minute
> 59)
4646 n
= now(CLOCK_REALTIME
);
4647 s
= (time_t) (n
/ USEC_PER_SEC
);
4650 assert_se(localtime_r(&s
, &tm
));
4652 tm
.tm_hour
= (int) hour
;
4653 tm
.tm_min
= (int) minute
;
4656 assert_se(s
= mktime(&tm
));
4658 *_u
= (usec_t
) s
* USEC_PER_SEC
;
4661 *_u
+= USEC_PER_DAY
;
4667 static int shutdown_parse_argv(int argc
, char *argv
[]) {
4674 static const struct option options
[] = {
4675 { "help", no_argument
, NULL
, ARG_HELP
},
4676 { "halt", no_argument
, NULL
, 'H' },
4677 { "poweroff", no_argument
, NULL
, 'P' },
4678 { "reboot", no_argument
, NULL
, 'r' },
4679 { "kexec", no_argument
, NULL
, 'K' }, /* not documented extension */
4680 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4681 { NULL
, 0, NULL
, 0 }
4689 while ((c
= getopt_long(argc
, argv
, "HPrhkt:afFc", options
, NULL
)) >= 0) {
4697 arg_action
= ACTION_HALT
;
4701 arg_action
= ACTION_POWEROFF
;
4706 arg_action
= ACTION_KEXEC
;
4708 arg_action
= ACTION_REBOOT
;
4712 arg_action
= ACTION_KEXEC
;
4716 if (arg_action
!= ACTION_HALT
)
4717 arg_action
= ACTION_POWEROFF
;
4730 /* Compatibility nops */
4734 arg_action
= ACTION_CANCEL_SHUTDOWN
;
4741 log_error("Unknown option code %c", c
);
4746 if (argc
> optind
) {
4747 r
= parse_time_spec(argv
[optind
], &arg_when
);
4749 log_error("Failed to parse time specification: %s", argv
[optind
]);
4753 arg_when
= now(CLOCK_REALTIME
) + USEC_PER_MINUTE
;
4755 /* We skip the time argument */
4756 if (argc
> optind
+ 1)
4757 arg_wall
= argv
+ optind
+ 1;
4764 static int telinit_parse_argv(int argc
, char *argv
[]) {
4771 static const struct option options
[] = {
4772 { "help", no_argument
, NULL
, ARG_HELP
},
4773 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4774 { NULL
, 0, NULL
, 0 }
4777 static const struct {
4781 { '0', ACTION_POWEROFF
},
4782 { '6', ACTION_REBOOT
},
4783 { '1', ACTION_RESCUE
},
4784 { '2', ACTION_RUNLEVEL2
},
4785 { '3', ACTION_RUNLEVEL3
},
4786 { '4', ACTION_RUNLEVEL4
},
4787 { '5', ACTION_RUNLEVEL5
},
4788 { 's', ACTION_RESCUE
},
4789 { 'S', ACTION_RESCUE
},
4790 { 'q', ACTION_RELOAD
},
4791 { 'Q', ACTION_RELOAD
},
4792 { 'u', ACTION_REEXEC
},
4793 { 'U', ACTION_REEXEC
}
4802 while ((c
= getopt_long(argc
, argv
, "", options
, NULL
)) >= 0) {
4817 log_error("Unknown option code %c", c
);
4822 if (optind
>= argc
) {
4827 if (optind
+ 1 < argc
) {
4828 log_error("Too many arguments.");
4832 if (strlen(argv
[optind
]) != 1) {
4833 log_error("Expected single character argument.");
4837 for (i
= 0; i
< ELEMENTSOF(table
); i
++)
4838 if (table
[i
].from
== argv
[optind
][0])
4841 if (i
>= ELEMENTSOF(table
)) {
4842 log_error("Unknown command %s.", argv
[optind
]);
4846 arg_action
= table
[i
].to
;
4853 static int runlevel_parse_argv(int argc
, char *argv
[]) {
4859 static const struct option options
[] = {
4860 { "help", no_argument
, NULL
, ARG_HELP
},
4861 { NULL
, 0, NULL
, 0 }
4869 while ((c
= getopt_long(argc
, argv
, "", options
, NULL
)) >= 0) {
4880 log_error("Unknown option code %c", c
);
4885 if (optind
< argc
) {
4886 log_error("Too many arguments.");
4893 static int parse_argv(int argc
, char *argv
[]) {
4897 if (program_invocation_short_name
) {
4899 if (strstr(program_invocation_short_name
, "halt")) {
4900 arg_action
= ACTION_HALT
;
4901 return halt_parse_argv(argc
, argv
);
4902 } else if (strstr(program_invocation_short_name
, "poweroff")) {
4903 arg_action
= ACTION_POWEROFF
;
4904 return halt_parse_argv(argc
, argv
);
4905 } else if (strstr(program_invocation_short_name
, "reboot")) {
4907 arg_action
= ACTION_KEXEC
;
4909 arg_action
= ACTION_REBOOT
;
4910 return halt_parse_argv(argc
, argv
);
4911 } else if (strstr(program_invocation_short_name
, "shutdown")) {
4912 arg_action
= ACTION_POWEROFF
;
4913 return shutdown_parse_argv(argc
, argv
);
4914 } else if (strstr(program_invocation_short_name
, "init")) {
4916 if (sd_booted() > 0) {
4917 arg_action
= ACTION_INVALID
;
4918 return telinit_parse_argv(argc
, argv
);
4920 /* Hmm, so some other init system is
4921 * running, we need to forward this
4922 * request to it. For now we simply
4923 * guess that it is Upstart. */
4925 execv("/lib/upstart/telinit", argv
);
4927 log_error("Couldn't find an alternative telinit implementation to spawn.");
4931 } else if (strstr(program_invocation_short_name
, "runlevel")) {
4932 arg_action
= ACTION_RUNLEVEL
;
4933 return runlevel_parse_argv(argc
, argv
);
4937 arg_action
= ACTION_SYSTEMCTL
;
4938 return systemctl_parse_argv(argc
, argv
);
4941 static int action_to_runlevel(void) {
4943 static const char table
[_ACTION_MAX
] = {
4944 [ACTION_HALT
] = '0',
4945 [ACTION_POWEROFF
] = '0',
4946 [ACTION_REBOOT
] = '6',
4947 [ACTION_RUNLEVEL2
] = '2',
4948 [ACTION_RUNLEVEL3
] = '3',
4949 [ACTION_RUNLEVEL4
] = '4',
4950 [ACTION_RUNLEVEL5
] = '5',
4951 [ACTION_RESCUE
] = '1'
4954 assert(arg_action
< _ACTION_MAX
);
4956 return table
[arg_action
];
4959 static int talk_upstart(void) {
4960 DBusMessage
*m
= NULL
, *reply
= NULL
;
4962 int previous
, rl
, r
;
4964 env1_buf
[] = "RUNLEVEL=X",
4965 env2_buf
[] = "PREVLEVEL=X";
4966 char *env1
= env1_buf
, *env2
= env2_buf
;
4967 const char *emit
= "runlevel";
4968 dbus_bool_t b_false
= FALSE
;
4969 DBusMessageIter iter
, sub
;
4970 DBusConnection
*bus
;
4972 dbus_error_init(&error
);
4974 if (!(rl
= action_to_runlevel()))
4977 if (utmp_get_runlevel(&previous
, NULL
) < 0)
4980 if (!(bus
= dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error
))) {
4981 if (dbus_error_has_name(&error
, DBUS_ERROR_NO_SERVER
)) {
4986 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error
));
4991 if ((r
= bus_check_peercred(bus
)) < 0) {
4992 log_error("Failed to verify owner of bus.");
4996 if (!(m
= dbus_message_new_method_call(
4997 "com.ubuntu.Upstart",
4998 "/com/ubuntu/Upstart",
4999 "com.ubuntu.Upstart0_6",
5002 log_error("Could not allocate message.");
5007 dbus_message_iter_init_append(m
, &iter
);
5009 env1_buf
[sizeof(env1_buf
)-2] = rl
;
5010 env2_buf
[sizeof(env2_buf
)-2] = previous
;
5012 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_STRING
, &emit
) ||
5013 !dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "s", &sub
) ||
5014 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &env1
) ||
5015 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &env2
) ||
5016 !dbus_message_iter_close_container(&iter
, &sub
) ||
5017 !dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &b_false
)) {
5018 log_error("Could not append arguments to message.");
5023 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
5025 if (error_is_no_service(&error
)) {
5030 log_error("Failed to issue method call: %s", bus_error_message(&error
));
5039 dbus_message_unref(m
);
5042 dbus_message_unref(reply
);
5045 dbus_connection_flush(bus
);
5046 dbus_connection_close(bus
);
5047 dbus_connection_unref(bus
);
5050 dbus_error_free(&error
);
5055 static int talk_initctl(void) {
5056 struct init_request request
;
5060 if (!(rl
= action_to_runlevel()))
5064 request
.magic
= INIT_MAGIC
;
5065 request
.sleeptime
= 0;
5066 request
.cmd
= INIT_CMD_RUNLVL
;
5067 request
.runlevel
= rl
;
5069 if ((fd
= open(INIT_FIFO
, O_WRONLY
|O_NDELAY
|O_CLOEXEC
|O_NOCTTY
)) < 0) {
5071 if (errno
== ENOENT
)
5074 log_error("Failed to open "INIT_FIFO
": %m");
5079 r
= loop_write(fd
, &request
, sizeof(request
), false) != sizeof(request
);
5080 close_nointr_nofail(fd
);
5083 log_error("Failed to write to "INIT_FIFO
": %m");
5084 return errno
? -errno
: -EIO
;
5090 static int systemctl_main(DBusConnection
*bus
, int argc
, char *argv
[], DBusError
*error
) {
5092 static const struct {
5100 int (* const dispatch
)(DBusConnection
*bus
, char **args
);
5102 { "list-units", LESS
, 1, list_units
},
5103 { "list-unit-files", EQUAL
, 1, list_unit_files
},
5104 { "list-jobs", EQUAL
, 1, list_jobs
},
5105 { "clear-jobs", EQUAL
, 1, daemon_reload
},
5106 { "load", MORE
, 2, load_unit
},
5107 { "cancel", MORE
, 2, cancel_job
},
5108 { "start", MORE
, 2, start_unit
},
5109 { "stop", MORE
, 2, start_unit
},
5110 { "condstop", MORE
, 2, start_unit
}, /* For compatibility with ALTLinux */
5111 { "reload", MORE
, 2, start_unit
},
5112 { "restart", MORE
, 2, start_unit
},
5113 { "try-restart", MORE
, 2, start_unit
},
5114 { "reload-or-restart", MORE
, 2, start_unit
},
5115 { "reload-or-try-restart", MORE
, 2, start_unit
},
5116 { "force-reload", MORE
, 2, start_unit
}, /* For compatibility with SysV */
5117 { "condreload", MORE
, 2, start_unit
}, /* For compatibility with ALTLinux */
5118 { "condrestart", MORE
, 2, start_unit
}, /* For compatibility with RH */
5119 { "isolate", EQUAL
, 2, start_unit
},
5120 { "kill", MORE
, 2, kill_unit
},
5121 { "is-active", MORE
, 2, check_unit
},
5122 { "check", MORE
, 2, check_unit
},
5123 { "show", MORE
, 1, show
},
5124 { "status", MORE
, 2, show
},
5125 { "dump", EQUAL
, 1, dump
},
5126 { "dot", EQUAL
, 1, dot
},
5127 { "snapshot", LESS
, 2, snapshot
},
5128 { "delete", MORE
, 2, delete_snapshot
},
5129 { "daemon-reload", EQUAL
, 1, daemon_reload
},
5130 { "daemon-reexec", EQUAL
, 1, daemon_reload
},
5131 { "show-environment", EQUAL
, 1, show_enviroment
},
5132 { "set-environment", MORE
, 2, set_environment
},
5133 { "unset-environment", MORE
, 2, set_environment
},
5134 { "halt", EQUAL
, 1, start_special
},
5135 { "poweroff", EQUAL
, 1, start_special
},
5136 { "reboot", EQUAL
, 1, start_special
},
5137 { "kexec", EQUAL
, 1, start_special
},
5138 { "default", EQUAL
, 1, start_special
},
5139 { "rescue", EQUAL
, 1, start_special
},
5140 { "emergency", EQUAL
, 1, start_special
},
5141 { "exit", EQUAL
, 1, start_special
},
5142 { "reset-failed", MORE
, 1, reset_failed
},
5143 { "enable", MORE
, 2, enable_unit
},
5144 { "disable", MORE
, 2, enable_unit
},
5145 { "is-enabled", MORE
, 2, unit_is_enabled
},
5146 { "reenable", MORE
, 2, enable_unit
},
5147 { "preset", MORE
, 2, enable_unit
},
5148 { "mask", MORE
, 2, enable_unit
},
5149 { "unmask", MORE
, 2, enable_unit
},
5150 { "link", MORE
, 2, enable_unit
}
5160 left
= argc
- optind
;
5163 /* Special rule: no arguments means "list-units" */
5166 if (streq(argv
[optind
], "help")) {
5171 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
5172 if (streq(argv
[optind
], verbs
[i
].verb
))
5175 if (i
>= ELEMENTSOF(verbs
)) {
5176 log_error("Unknown operation %s", argv
[optind
]);
5181 switch (verbs
[i
].argc_cmp
) {
5184 if (left
!= verbs
[i
].argc
) {
5185 log_error("Invalid number of arguments.");
5192 if (left
< verbs
[i
].argc
) {
5193 log_error("Too few arguments.");
5200 if (left
> verbs
[i
].argc
) {
5201 log_error("Too many arguments.");
5208 assert_not_reached("Unknown comparison operator.");
5211 /* Require a bus connection for all operations but
5213 if (!streq(verbs
[i
].verb
, "enable") &&
5214 !streq(verbs
[i
].verb
, "disable") &&
5215 !streq(verbs
[i
].verb
, "is-enabled") &&
5216 !streq(verbs
[i
].verb
, "list-unit-files") &&
5217 !streq(verbs
[i
].verb
, "reenable") &&
5218 !streq(verbs
[i
].verb
, "preset") &&
5219 !streq(verbs
[i
].verb
, "mask") &&
5220 !streq(verbs
[i
].verb
, "unmask") &&
5221 !streq(verbs
[i
].verb
, "link")) {
5223 if (running_in_chroot() > 0) {
5224 log_info("Running in chroot, ignoring request.");
5228 if (((!streq(verbs
[i
].verb
, "reboot") &&
5229 !streq(verbs
[i
].verb
, "halt") &&
5230 !streq(verbs
[i
].verb
, "poweroff")) || arg_force
<= 0) && !bus
) {
5231 log_error("Failed to get D-Bus connection: %s",
5232 dbus_error_is_set(error
) ? error
->message
: "No connection to service manager.");
5238 if (!bus
&& !avoid_bus()) {
5239 log_error("Failed to get D-Bus connection: %s",
5240 dbus_error_is_set(error
) ? error
->message
: "No connection to service manager.");
5245 return verbs
[i
].dispatch(bus
, argv
+ optind
);
5248 static int send_shutdownd(usec_t t
, char mode
, bool dry_run
, bool warn
, const char *message
) {
5250 struct msghdr msghdr
;
5251 struct iovec iovec
[2];
5252 union sockaddr_union sockaddr
;
5253 struct sd_shutdown_command c
;
5255 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
5262 c
.dry_run
= dry_run
;
5266 sockaddr
.sa
.sa_family
= AF_UNIX
;
5267 strncpy(sockaddr
.un
.sun_path
, "/run/systemd/shutdownd", sizeof(sockaddr
.un
.sun_path
));
5270 msghdr
.msg_name
= &sockaddr
;
5271 msghdr
.msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + sizeof("/run/systemd/shutdownd") - 1;
5274 iovec
[0].iov_base
= (char*) &c
;
5275 iovec
[0].iov_len
= offsetof(struct sd_shutdown_command
, wall_message
);
5277 if (isempty(message
))
5278 msghdr
.msg_iovlen
= 1;
5280 iovec
[1].iov_base
= (char*) message
;
5281 iovec
[1].iov_len
= strlen(message
);
5282 msghdr
.msg_iovlen
= 2;
5284 msghdr
.msg_iov
= iovec
;
5286 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) < 0) {
5287 close_nointr_nofail(fd
);
5291 close_nointr_nofail(fd
);
5295 static int reload_with_fallback(DBusConnection
*bus
) {
5298 /* First, try systemd via D-Bus. */
5299 if (daemon_reload(bus
, NULL
) >= 0)
5303 /* Nothing else worked, so let's try signals */
5304 assert(arg_action
== ACTION_RELOAD
|| arg_action
== ACTION_REEXEC
);
5306 if (kill(1, arg_action
== ACTION_RELOAD
? SIGHUP
: SIGTERM
) < 0) {
5307 log_error("kill() failed: %m");
5314 static int start_with_fallback(DBusConnection
*bus
) {
5317 /* First, try systemd via D-Bus. */
5318 if (start_unit(bus
, NULL
) >= 0)
5322 /* Hmm, talking to systemd via D-Bus didn't work. Then
5323 * let's try to talk to Upstart via D-Bus. */
5324 if (talk_upstart() > 0)
5327 /* Nothing else worked, so let's try
5329 if (talk_initctl() > 0)
5332 log_error("Failed to talk to init daemon.");
5336 warn_wall(arg_action
);
5340 static void halt_now(enum action a
) {
5342 /* Make sure C-A-D is handled by the kernel from this
5344 reboot(RB_ENABLE_CAD
);
5349 log_info("Halting.");
5350 reboot(RB_HALT_SYSTEM
);
5353 case ACTION_POWEROFF
:
5354 log_info("Powering off.");
5355 reboot(RB_POWER_OFF
);
5359 log_info("Rebooting.");
5360 reboot(RB_AUTOBOOT
);
5364 assert_not_reached("Unknown halt action.");
5367 assert_not_reached("Uh? This shouldn't happen.");
5370 static int halt_main(DBusConnection
*bus
) {
5373 if (geteuid() != 0) {
5374 /* Try logind if we are a normal user and no special
5375 * mode applies. Maybe PolicyKit allows us to shutdown
5378 if (arg_when
<= 0 &&
5381 (arg_action
== ACTION_POWEROFF
||
5382 arg_action
== ACTION_REBOOT
)) {
5383 r
= reboot_with_logind(bus
, arg_action
);
5388 log_error("Must be root.");
5395 m
= strv_join(arg_wall
, " ");
5396 r
= send_shutdownd(arg_when
,
5397 arg_action
== ACTION_HALT
? 'H' :
5398 arg_action
== ACTION_POWEROFF
? 'P' :
5399 arg_action
== ACTION_KEXEC
? 'K' :
5407 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r
));
5409 char date
[FORMAT_TIMESTAMP_MAX
];
5411 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5412 format_timestamp(date
, sizeof(date
), arg_when
));
5417 if (!arg_dry
&& !arg_force
)
5418 return start_with_fallback(bus
);
5421 if (sd_booted() > 0)
5422 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5424 r
= utmp_put_shutdown();
5426 log_warning("Failed to write utmp record: %s", strerror(-r
));
5436 halt_now(arg_action
);
5437 /* We should never reach this. */
5441 static int runlevel_main(void) {
5442 int r
, runlevel
, previous
;
5444 r
= utmp_get_runlevel(&runlevel
, &previous
);
5451 previous
<= 0 ? 'N' : previous
,
5452 runlevel
<= 0 ? 'N' : runlevel
);
5457 int main(int argc
, char*argv
[]) {
5458 int r
, retval
= EXIT_FAILURE
;
5459 DBusConnection
*bus
= NULL
;
5462 dbus_error_init(&error
);
5464 log_parse_environment();
5467 r
= parse_argv(argc
, argv
);
5471 retval
= EXIT_SUCCESS
;
5475 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5476 * let's shortcut this */
5477 if (arg_action
== ACTION_RUNLEVEL
) {
5478 r
= runlevel_main();
5479 retval
= r
< 0 ? EXIT_FAILURE
: r
;
5483 if (running_in_chroot() > 0 && arg_action
!= ACTION_SYSTEMCTL
) {
5484 log_info("Running in chroot, ignoring request.");
5490 if (arg_transport
== TRANSPORT_NORMAL
)
5491 bus_connect(arg_scope
== UNIT_FILE_SYSTEM
? DBUS_BUS_SYSTEM
: DBUS_BUS_SESSION
, &bus
, &private_bus
, &error
);
5492 else if (arg_transport
== TRANSPORT_POLKIT
) {
5493 bus_connect_system_polkit(&bus
, &error
);
5494 private_bus
= false;
5495 } else if (arg_transport
== TRANSPORT_SSH
) {
5496 bus_connect_system_ssh(NULL
, arg_host
, &bus
, &error
);
5497 private_bus
= false;
5499 assert_not_reached("Uh, invalid transport...");
5502 switch (arg_action
) {
5504 case ACTION_SYSTEMCTL
:
5505 r
= systemctl_main(bus
, argc
, argv
, &error
);
5509 case ACTION_POWEROFF
:
5515 case ACTION_RUNLEVEL2
:
5516 case ACTION_RUNLEVEL3
:
5517 case ACTION_RUNLEVEL4
:
5518 case ACTION_RUNLEVEL5
:
5520 case ACTION_EMERGENCY
:
5521 case ACTION_DEFAULT
:
5522 r
= start_with_fallback(bus
);
5527 r
= reload_with_fallback(bus
);
5530 case ACTION_CANCEL_SHUTDOWN
:
5531 r
= send_shutdownd(0, 0, false, false, NULL
);
5534 case ACTION_INVALID
:
5535 case ACTION_RUNLEVEL
:
5537 assert_not_reached("Unknown action");
5540 retval
= r
< 0 ? EXIT_FAILURE
: r
;
5544 dbus_connection_flush(bus
);
5545 dbus_connection_close(bus
);
5546 dbus_connection_unref(bus
);
5549 dbus_error_free(&error
);
5553 strv_free(arg_property
);
5556 ask_password_agent_close();
5557 polkit_agent_close();