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;
112 ACTION_CANCEL_SHUTDOWN
,
114 } arg_action
= ACTION_SYSTEMCTL
;
120 static enum transport
{
124 } arg_transport
= TRANSPORT_NORMAL
;
125 static const char *arg_host
= NULL
;
126 static bool arg_follow
= false;
127 static unsigned arg_lines
= 10;
128 static OutputMode arg_output
= OUTPUT_SHORT
;
130 static bool private_bus
= false;
132 static int daemon_reload(DBusConnection
*bus
, char **args
);
133 static void halt_now(enum action a
);
135 static bool on_tty(void) {
138 /* Note that this is invoked relatively early, before we start
139 * the pager. That means the value we return reflects whether
140 * we originally were started on a tty, not if we currently
141 * are. But this is intended, since we want colour and so on
142 * when run in our own pager. */
144 if (_unlikely_(t
< 0))
145 t
= isatty(STDOUT_FILENO
) > 0;
150 static void pager_open_if_enabled(void) {
152 /* Cache result before we open the pager */
161 static void ask_password_agent_open_if_enabled(void) {
163 /* Open the password agent as a child process if necessary */
165 if (!arg_ask_password
)
168 if (arg_scope
!= UNIT_FILE_SYSTEM
)
171 ask_password_agent_open();
174 static void polkit_agent_open_if_enabled(void) {
176 /* Open the polkit agent as a child process if necessary */
178 if (!arg_ask_password
)
181 if (arg_scope
!= UNIT_FILE_SYSTEM
)
187 static const char *ansi_highlight_red(bool b
) {
192 return b
? ANSI_HIGHLIGHT_RED_ON
: ANSI_HIGHLIGHT_OFF
;
195 static const char *ansi_highlight_green(bool b
) {
200 return b
? ANSI_HIGHLIGHT_GREEN_ON
: ANSI_HIGHLIGHT_OFF
;
203 static bool error_is_no_service(const DBusError
*error
) {
206 if (!dbus_error_is_set(error
))
209 if (dbus_error_has_name(error
, DBUS_ERROR_NAME_HAS_NO_OWNER
))
212 if (dbus_error_has_name(error
, DBUS_ERROR_SERVICE_UNKNOWN
))
215 return startswith(error
->name
, "org.freedesktop.DBus.Error.Spawn.");
218 static int translate_bus_error_to_exit_status(int r
, const DBusError
*error
) {
221 if (!dbus_error_is_set(error
))
224 if (dbus_error_has_name(error
, DBUS_ERROR_ACCESS_DENIED
) ||
225 dbus_error_has_name(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
) ||
226 dbus_error_has_name(error
, BUS_ERROR_NO_ISOLATION
) ||
227 dbus_error_has_name(error
, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE
))
228 return EXIT_NOPERMISSION
;
230 if (dbus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
))
231 return EXIT_NOTINSTALLED
;
233 if (dbus_error_has_name(error
, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE
) ||
234 dbus_error_has_name(error
, BUS_ERROR_NOT_SUPPORTED
))
235 return EXIT_NOTIMPLEMENTED
;
237 if (dbus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
))
238 return EXIT_NOTCONFIGURED
;
246 static void warn_wall(enum action a
) {
247 static const char *table
[_ACTION_MAX
] = {
248 [ACTION_HALT
] = "The system is going down for system halt NOW!",
249 [ACTION_REBOOT
] = "The system is going down for reboot NOW!",
250 [ACTION_POWEROFF
] = "The system is going down for power-off NOW!",
251 [ACTION_KEXEC
] = "The system is going down for kexec reboot NOW!",
252 [ACTION_RESCUE
] = "The system is going down to rescue mode NOW!",
253 [ACTION_EMERGENCY
] = "The system is going down to emergency mode NOW!"
262 p
= strv_join(arg_wall
, " ");
264 log_error("Failed to join strings.");
280 utmp_wall(table
[a
], NULL
);
283 static bool avoid_bus(void) {
285 if (running_in_chroot() > 0)
288 if (sd_booted() <= 0)
291 if (!isempty(arg_root
))
294 if (arg_scope
== UNIT_FILE_GLOBAL
)
302 const char *description
;
303 const char *load_state
;
304 const char *active_state
;
305 const char *sub_state
;
306 const char *following
;
307 const char *unit_path
;
309 const char *job_type
;
310 const char *job_path
;
313 static int compare_unit_info(const void *a
, const void *b
) {
315 const struct unit_info
*u
= a
, *v
= b
;
317 d1
= strrchr(u
->id
, '.');
318 d2
= strrchr(v
->id
, '.');
323 if ((r
= strcasecmp(d1
, d2
)) != 0)
327 return strcasecmp(u
->id
, v
->id
);
330 static bool output_show_unit(const struct unit_info
*u
) {
334 return streq(u
->active_state
, "failed");
336 return (!arg_type
|| ((dot
= strrchr(u
->id
, '.')) &&
337 streq(dot
+1, arg_type
))) &&
338 (arg_all
|| !(streq(u
->active_state
, "inactive") || u
->following
[0]) || u
->job_id
> 0);
341 static void output_units_list(const struct unit_info
*unit_infos
, unsigned c
) {
342 unsigned id_len
, max_id_len
, active_len
, sub_len
, job_len
, desc_len
, n_shown
= 0;
343 const struct unit_info
*u
;
345 max_id_len
= sizeof("UNIT")-1;
346 active_len
= sizeof("ACTIVE")-1;
347 sub_len
= sizeof("SUB")-1;
348 job_len
= sizeof("JOB")-1;
351 for (u
= unit_infos
; u
< unit_infos
+ c
; u
++) {
352 if (!output_show_unit(u
))
355 max_id_len
= MAX(max_id_len
, strlen(u
->id
));
356 active_len
= MAX(active_len
, strlen(u
->active_state
));
357 sub_len
= MAX(sub_len
, strlen(u
->sub_state
));
359 job_len
= MAX(job_len
, strlen(u
->job_type
));
364 id_len
= MIN(max_id_len
, 25);
365 basic_len
= 5 + id_len
+ 6 + active_len
+ sub_len
+ job_len
;
366 if (basic_len
< (unsigned) columns()) {
367 unsigned extra_len
, incr
;
368 extra_len
= columns() - basic_len
;
369 /* Either UNIT already got 25, or is fully satisfied.
370 * Grant up to 25 to DESC now. */
371 incr
= MIN(extra_len
, 25);
374 /* split the remaining space between UNIT and DESC,
375 * but do not give UNIT more than it needs. */
377 incr
= MIN(extra_len
/ 2, max_id_len
- id_len
);
379 desc_len
+= extra_len
- incr
;
385 if (!arg_no_legend
) {
386 printf("%-*s %-6s %-*s %-*s %-*s ", id_len
, "UNIT", "LOAD",
387 active_len
, "ACTIVE", sub_len
, "SUB", job_len
, "JOB");
388 if (!arg_full
&& arg_no_pager
)
389 printf("%.*s\n", desc_len
, "DESCRIPTION");
391 printf("%s\n", "DESCRIPTION");
394 for (u
= unit_infos
; u
< unit_infos
+ c
; u
++) {
396 const char *on_loaded
, *off_loaded
;
397 const char *on_active
, *off_active
;
399 if (!output_show_unit(u
))
404 if (streq(u
->load_state
, "error")) {
405 on_loaded
= ansi_highlight_red(true);
406 off_loaded
= ansi_highlight_red(false);
408 on_loaded
= off_loaded
= "";
410 if (streq(u
->active_state
, "failed")) {
411 on_active
= ansi_highlight_red(true);
412 off_active
= ansi_highlight_red(false);
414 on_active
= off_active
= "";
416 e
= arg_full
? NULL
: ellipsize(u
->id
, id_len
, 33);
418 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
419 id_len
, e
? e
: u
->id
,
420 on_loaded
, u
->load_state
, off_loaded
,
421 on_active
, active_len
, u
->active_state
,
422 sub_len
, u
->sub_state
, off_active
,
423 job_len
, u
->job_id
? u
->job_type
: "");
424 if (!arg_full
&& arg_no_pager
)
425 printf("%.*s\n", desc_len
, u
->description
);
427 printf("%s\n", u
->description
);
432 if (!arg_no_legend
) {
433 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
434 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
435 "SUB = The low-level unit activation state, values depend on unit type.\n"
436 "JOB = Pending job for the unit.\n");
439 printf("\n%u units listed.\n", n_shown
);
441 printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown
);
445 static int list_units(DBusConnection
*bus
, char **args
) {
446 DBusMessage
*m
= NULL
, *reply
= NULL
;
449 DBusMessageIter iter
, sub
, sub2
;
450 unsigned c
= 0, n_units
= 0;
451 struct unit_info
*unit_infos
= NULL
;
453 dbus_error_init(&error
);
457 pager_open_if_enabled();
459 if (!(m
= dbus_message_new_method_call(
460 "org.freedesktop.systemd1",
461 "/org/freedesktop/systemd1",
462 "org.freedesktop.systemd1.Manager",
464 log_error("Could not allocate message.");
468 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
469 log_error("Failed to issue method call: %s", bus_error_message(&error
));
474 if (!dbus_message_iter_init(reply
, &iter
) ||
475 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
476 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
477 log_error("Failed to parse reply.");
482 dbus_message_iter_recurse(&iter
, &sub
);
484 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
487 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
488 log_error("Failed to parse reply.");
496 n_units
= MAX(2*c
, 16);
497 w
= realloc(unit_infos
, sizeof(struct unit_info
) * n_units
);
500 log_error("Failed to allocate unit array.");
510 dbus_message_iter_recurse(&sub
, &sub2
);
512 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->id
, true) < 0 ||
513 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->description
, true) < 0 ||
514 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->load_state
, true) < 0 ||
515 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->active_state
, true) < 0 ||
516 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->sub_state
, true) < 0 ||
517 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->following
, true) < 0 ||
518 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &u
->unit_path
, true) < 0 ||
519 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &u
->job_id
, true) < 0 ||
520 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->job_type
, true) < 0 ||
521 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &u
->job_path
, false) < 0) {
522 log_error("Failed to parse reply.");
527 dbus_message_iter_next(&sub
);
532 qsort(unit_infos
, c
, sizeof(struct unit_info
), compare_unit_info
);
533 output_units_list(unit_infos
, c
);
540 dbus_message_unref(m
);
543 dbus_message_unref(reply
);
547 dbus_error_free(&error
);
552 static int compare_unit_file_list(const void *a
, const void *b
) {
554 const UnitFileList
*u
= a
, *v
= b
;
556 d1
= strrchr(u
->path
, '.');
557 d2
= strrchr(v
->path
, '.');
562 r
= strcasecmp(d1
, d2
);
567 return strcasecmp(path_get_file_name(u
->path
), path_get_file_name(v
->path
));
570 static bool output_show_unit_file(const UnitFileList
*u
) {
573 return !arg_type
|| ((dot
= strrchr(u
->path
, '.')) && streq(dot
+1, arg_type
));
576 static void output_unit_file_list(const UnitFileList
*units
, unsigned c
) {
577 unsigned max_id_len
, id_cols
, state_cols
, n_shown
= 0;
578 const UnitFileList
*u
;
580 max_id_len
= sizeof("UNIT FILE")-1;
581 state_cols
= sizeof("STATE")-1;
582 for (u
= units
; u
< units
+ c
; u
++) {
583 if (!output_show_unit_file(u
))
586 max_id_len
= MAX(max_id_len
, strlen(path_get_file_name(u
->path
)));
587 state_cols
= MAX(state_cols
, strlen(unit_file_state_to_string(u
->state
)));
592 id_cols
= MIN(max_id_len
, 25);
593 basic_cols
= 1 + id_cols
+ state_cols
;
594 if (basic_cols
< (unsigned) columns())
595 id_cols
+= MIN(columns() - basic_cols
, max_id_len
- id_cols
);
597 id_cols
= max_id_len
;
600 printf("%-*s %-*s\n", id_cols
, "UNIT FILE", state_cols
, "STATE");
602 for (u
= units
; u
< units
+ c
; u
++) {
604 const char *on
, *off
;
607 if (!output_show_unit_file(u
))
612 if (u
->state
== UNIT_FILE_MASKED
||
613 u
->state
== UNIT_FILE_MASKED_RUNTIME
||
614 u
->state
== UNIT_FILE_DISABLED
) {
615 on
= ansi_highlight_red(true);
616 off
= ansi_highlight_red(false);
617 } else if (u
->state
== UNIT_FILE_ENABLED
) {
618 on
= ansi_highlight_green(true);
619 off
= ansi_highlight_green(false);
623 id
= path_get_file_name(u
->path
);
625 e
= arg_full
? NULL
: ellipsize(id
, id_cols
, 33);
627 printf("%-*s %s%-*s%s\n",
629 on
, state_cols
, unit_file_state_to_string(u
->state
), off
);
635 printf("\n%u unit files listed.\n", n_shown
);
638 static int list_unit_files(DBusConnection
*bus
, char **args
) {
639 DBusMessage
*m
= NULL
, *reply
= NULL
;
642 DBusMessageIter iter
, sub
, sub2
;
643 unsigned c
= 0, n_units
= 0;
644 UnitFileList
*units
= NULL
;
646 dbus_error_init(&error
);
648 pager_open_if_enabled();
655 h
= hashmap_new(string_hash_func
, string_compare_func
);
657 log_error("Out of memory");
661 r
= unit_file_get_list(arg_scope
, arg_root
, h
);
663 unit_file_list_free(h
);
664 log_error("Failed to get unit file list: %s", strerror(-r
));
668 n_units
= hashmap_size(h
);
669 units
= new(UnitFileList
, n_units
);
671 unit_file_list_free(h
);
672 log_error("Out of memory");
676 HASHMAP_FOREACH(u
, h
, i
) {
677 memcpy(units
+ c
++, u
, sizeof(UnitFileList
));
685 m
= dbus_message_new_method_call(
686 "org.freedesktop.systemd1",
687 "/org/freedesktop/systemd1",
688 "org.freedesktop.systemd1.Manager",
691 log_error("Could not allocate message.");
695 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
697 log_error("Failed to issue method call: %s", bus_error_message(&error
));
702 if (!dbus_message_iter_init(reply
, &iter
) ||
703 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
704 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
705 log_error("Failed to parse reply.");
710 dbus_message_iter_recurse(&iter
, &sub
);
712 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
716 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
717 log_error("Failed to parse reply.");
725 n_units
= MAX(2*c
, 16);
726 w
= realloc(units
, sizeof(struct UnitFileList
) * n_units
);
729 log_error("Failed to allocate unit array.");
739 dbus_message_iter_recurse(&sub
, &sub2
);
741 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &u
->path
, true) < 0 ||
742 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &state
, false) < 0) {
743 log_error("Failed to parse reply.");
748 u
->state
= unit_file_state_from_string(state
);
750 dbus_message_iter_next(&sub
);
756 qsort(units
, c
, sizeof(UnitFileList
), compare_unit_file_list
);
757 output_unit_file_list(units
, c
);
764 dbus_message_unref(m
);
767 dbus_message_unref(reply
);
771 dbus_error_free(&error
);
776 static int dot_one_property(const char *name
, const char *prop
, DBusMessageIter
*iter
) {
777 static const char * const colors
[] = {
778 "Requires", "[color=\"black\"]",
779 "RequiresOverridable", "[color=\"black\"]",
780 "Requisite", "[color=\"darkblue\"]",
781 "RequisiteOverridable", "[color=\"darkblue\"]",
782 "Wants", "[color=\"darkgrey\"]",
783 "Conflicts", "[color=\"red\"]",
784 "ConflictedBy", "[color=\"red\"]",
785 "After", "[color=\"green\"]"
788 const char *c
= NULL
;
795 for (i
= 0; i
< ELEMENTSOF(colors
); i
+= 2)
796 if (streq(colors
[i
], prop
)) {
804 if (arg_dot
!= DOT_ALL
)
805 if ((arg_dot
== DOT_ORDER
) != streq(prop
, "After"))
808 switch (dbus_message_iter_get_arg_type(iter
)) {
810 case DBUS_TYPE_ARRAY
:
812 if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRING
) {
815 dbus_message_iter_recurse(iter
, &sub
);
817 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
820 assert(dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRING
);
821 dbus_message_iter_get_basic(&sub
, &s
);
822 printf("\t\"%s\"->\"%s\" %s;\n", name
, s
, c
);
824 dbus_message_iter_next(&sub
);
834 static int dot_one(DBusConnection
*bus
, const char *name
, const char *path
) {
835 DBusMessage
*m
= NULL
, *reply
= NULL
;
836 const char *interface
= "org.freedesktop.systemd1.Unit";
839 DBusMessageIter iter
, sub
, sub2
, sub3
;
844 dbus_error_init(&error
);
846 if (!(m
= dbus_message_new_method_call(
847 "org.freedesktop.systemd1",
849 "org.freedesktop.DBus.Properties",
851 log_error("Could not allocate message.");
856 if (!dbus_message_append_args(m
,
857 DBUS_TYPE_STRING
, &interface
,
858 DBUS_TYPE_INVALID
)) {
859 log_error("Could not append arguments to message.");
864 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
865 log_error("Failed to issue method call: %s", bus_error_message(&error
));
870 if (!dbus_message_iter_init(reply
, &iter
) ||
871 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
872 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_DICT_ENTRY
) {
873 log_error("Failed to parse reply.");
878 dbus_message_iter_recurse(&iter
, &sub
);
880 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
883 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_DICT_ENTRY
) {
884 log_error("Failed to parse reply.");
889 dbus_message_iter_recurse(&sub
, &sub2
);
891 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &prop
, true) < 0) {
892 log_error("Failed to parse reply.");
897 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_VARIANT
) {
898 log_error("Failed to parse reply.");
903 dbus_message_iter_recurse(&sub2
, &sub3
);
905 if (dot_one_property(name
, prop
, &sub3
)) {
906 log_error("Failed to parse reply.");
911 dbus_message_iter_next(&sub
);
918 dbus_message_unref(m
);
921 dbus_message_unref(reply
);
923 dbus_error_free(&error
);
928 static int dot(DBusConnection
*bus
, char **args
) {
929 DBusMessage
*m
= NULL
, *reply
= NULL
;
932 DBusMessageIter iter
, sub
, sub2
;
934 dbus_error_init(&error
);
938 if (!(m
= dbus_message_new_method_call(
939 "org.freedesktop.systemd1",
940 "/org/freedesktop/systemd1",
941 "org.freedesktop.systemd1.Manager",
943 log_error("Could not allocate message.");
947 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
948 log_error("Failed to issue method call: %s", bus_error_message(&error
));
953 if (!dbus_message_iter_init(reply
, &iter
) ||
954 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
955 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
956 log_error("Failed to parse reply.");
961 printf("digraph systemd {\n");
963 dbus_message_iter_recurse(&iter
, &sub
);
964 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
965 const char *id
, *description
, *load_state
, *active_state
, *sub_state
, *following
, *unit_path
;
967 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
968 log_error("Failed to parse reply.");
973 dbus_message_iter_recurse(&sub
, &sub2
);
975 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &id
, true) < 0 ||
976 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &description
, true) < 0 ||
977 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &load_state
, true) < 0 ||
978 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &active_state
, true) < 0 ||
979 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &sub_state
, true) < 0 ||
980 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &following
, true) < 0 ||
981 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &unit_path
, true) < 0) {
982 log_error("Failed to parse reply.");
987 if ((r
= dot_one(bus
, id
, unit_path
)) < 0)
990 /* printf("\t\"%s\";\n", id); */
991 dbus_message_iter_next(&sub
);
996 log_info(" Color legend: black = Requires\n"
997 " dark blue = Requisite\n"
998 " dark grey = Wants\n"
1000 " green = After\n");
1003 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
1004 "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
1010 dbus_message_unref(m
);
1013 dbus_message_unref(reply
);
1015 dbus_error_free(&error
);
1020 static int list_jobs(DBusConnection
*bus
, char **args
) {
1021 DBusMessage
*m
= NULL
, *reply
= NULL
;
1024 DBusMessageIter iter
, sub
, sub2
;
1027 dbus_error_init(&error
);
1031 pager_open_if_enabled();
1033 if (!(m
= dbus_message_new_method_call(
1034 "org.freedesktop.systemd1",
1035 "/org/freedesktop/systemd1",
1036 "org.freedesktop.systemd1.Manager",
1038 log_error("Could not allocate message.");
1042 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1043 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1048 if (!dbus_message_iter_init(reply
, &iter
) ||
1049 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
1050 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
1051 log_error("Failed to parse reply.");
1056 dbus_message_iter_recurse(&iter
, &sub
);
1059 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1061 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
1062 const char *name
, *type
, *state
, *job_path
, *unit_path
;
1066 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
1067 log_error("Failed to parse reply.");
1072 dbus_message_iter_recurse(&sub
, &sub2
);
1074 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &id
, true) < 0 ||
1075 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &name
, true) < 0 ||
1076 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) < 0 ||
1077 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &state
, true) < 0 ||
1078 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &job_path
, true) < 0 ||
1079 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &unit_path
, false) < 0) {
1080 log_error("Failed to parse reply.");
1085 e
= arg_full
? NULL
: ellipsize(name
, 25, 33);
1086 printf("%4u %-25s %-15s %-7s\n", id
, e
? e
: name
, type
, state
);
1091 dbus_message_iter_next(&sub
);
1095 printf("\n%u jobs listed.\n", k
);
1101 dbus_message_unref(m
);
1104 dbus_message_unref(reply
);
1106 dbus_error_free(&error
);
1111 static int load_unit(DBusConnection
*bus
, char **args
) {
1112 DBusMessage
*m
= NULL
;
1117 dbus_error_init(&error
);
1122 STRV_FOREACH(name
, args
+1) {
1125 if (!(m
= dbus_message_new_method_call(
1126 "org.freedesktop.systemd1",
1127 "/org/freedesktop/systemd1",
1128 "org.freedesktop.systemd1.Manager",
1130 log_error("Could not allocate message.");
1135 if (!dbus_message_append_args(m
,
1136 DBUS_TYPE_STRING
, name
,
1137 DBUS_TYPE_INVALID
)) {
1138 log_error("Could not append arguments to message.");
1143 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1144 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1149 dbus_message_unref(m
);
1150 dbus_message_unref(reply
);
1159 dbus_message_unref(m
);
1161 dbus_error_free(&error
);
1166 static int cancel_job(DBusConnection
*bus
, char **args
) {
1167 DBusMessage
*m
= NULL
, *reply
= NULL
;
1172 dbus_error_init(&error
);
1177 if (strv_length(args
) <= 1)
1178 return daemon_reload(bus
, args
);
1180 STRV_FOREACH(name
, args
+1) {
1184 if (!(m
= dbus_message_new_method_call(
1185 "org.freedesktop.systemd1",
1186 "/org/freedesktop/systemd1",
1187 "org.freedesktop.systemd1.Manager",
1189 log_error("Could not allocate message.");
1194 if ((r
= safe_atou(*name
, &id
)) < 0) {
1195 log_error("Failed to parse job id: %s", strerror(-r
));
1199 assert_cc(sizeof(uint32_t) == sizeof(id
));
1200 if (!dbus_message_append_args(m
,
1201 DBUS_TYPE_UINT32
, &id
,
1202 DBUS_TYPE_INVALID
)) {
1203 log_error("Could not append arguments to message.");
1208 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1209 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1214 if (!dbus_message_get_args(reply
, &error
,
1215 DBUS_TYPE_OBJECT_PATH
, &path
,
1216 DBUS_TYPE_INVALID
)) {
1217 log_error("Failed to parse reply: %s", bus_error_message(&error
));
1222 dbus_message_unref(m
);
1223 if (!(m
= dbus_message_new_method_call(
1224 "org.freedesktop.systemd1",
1226 "org.freedesktop.systemd1.Job",
1228 log_error("Could not allocate message.");
1233 dbus_message_unref(reply
);
1234 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1235 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1240 dbus_message_unref(m
);
1241 dbus_message_unref(reply
);
1249 dbus_message_unref(m
);
1252 dbus_message_unref(reply
);
1254 dbus_error_free(&error
);
1259 static bool need_daemon_reload(DBusConnection
*bus
, const char *unit
) {
1260 DBusMessage
*m
= NULL
, *reply
= NULL
;
1261 dbus_bool_t b
= FALSE
;
1262 DBusMessageIter iter
, sub
;
1264 *interface
= "org.freedesktop.systemd1.Unit",
1265 *property
= "NeedDaemonReload",
1268 /* We ignore all errors here, since this is used to show a warning only */
1270 if (!(m
= dbus_message_new_method_call(
1271 "org.freedesktop.systemd1",
1272 "/org/freedesktop/systemd1",
1273 "org.freedesktop.systemd1.Manager",
1277 if (!dbus_message_append_args(m
,
1278 DBUS_TYPE_STRING
, &unit
,
1282 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, NULL
)))
1285 if (!dbus_message_get_args(reply
, NULL
,
1286 DBUS_TYPE_OBJECT_PATH
, &path
,
1290 dbus_message_unref(m
);
1291 if (!(m
= dbus_message_new_method_call(
1292 "org.freedesktop.systemd1",
1294 "org.freedesktop.DBus.Properties",
1298 if (!dbus_message_append_args(m
,
1299 DBUS_TYPE_STRING
, &interface
,
1300 DBUS_TYPE_STRING
, &property
,
1301 DBUS_TYPE_INVALID
)) {
1305 dbus_message_unref(reply
);
1306 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, NULL
)))
1309 if (!dbus_message_iter_init(reply
, &iter
) ||
1310 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
)
1313 dbus_message_iter_recurse(&iter
, &sub
);
1315 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_BOOLEAN
)
1318 dbus_message_iter_get_basic(&sub
, &b
);
1322 dbus_message_unref(m
);
1325 dbus_message_unref(reply
);
1330 typedef struct WaitData
{
1335 static DBusHandlerResult
wait_filter(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
1343 dbus_error_init(&error
);
1345 log_debug("Got D-Bus request: %s.%s() on %s",
1346 dbus_message_get_interface(message
),
1347 dbus_message_get_member(message
),
1348 dbus_message_get_path(message
));
1350 if (dbus_message_is_signal(message
, DBUS_INTERFACE_LOCAL
, "Disconnected")) {
1351 log_error("Warning! D-Bus connection terminated.");
1352 dbus_connection_close(connection
);
1354 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1356 const char *path
, *result
, *unit
;
1357 dbus_bool_t success
= true;
1359 if (dbus_message_get_args(message
, &error
,
1360 DBUS_TYPE_UINT32
, &id
,
1361 DBUS_TYPE_OBJECT_PATH
, &path
,
1362 DBUS_TYPE_STRING
, &unit
,
1363 DBUS_TYPE_STRING
, &result
,
1364 DBUS_TYPE_INVALID
)) {
1367 p
= set_remove(d
->set
, (char*) path
);
1371 d
->result
= strdup(result
);
1376 dbus_error_free(&error
);
1377 if (dbus_message_get_args(message
, &error
,
1378 DBUS_TYPE_UINT32
, &id
,
1379 DBUS_TYPE_OBJECT_PATH
, &path
,
1380 DBUS_TYPE_STRING
, &result
,
1381 DBUS_TYPE_INVALID
)) {
1384 /* Compatibility with older systemd versions <
1385 * 183 during upgrades. This should be dropped
1387 p
= set_remove(d
->set
, (char*) path
);
1391 d
->result
= strdup(result
);
1396 dbus_error_free(&error
);
1397 if (dbus_message_get_args(message
, &error
,
1398 DBUS_TYPE_UINT32
, &id
,
1399 DBUS_TYPE_OBJECT_PATH
, &path
,
1400 DBUS_TYPE_BOOLEAN
, &success
,
1401 DBUS_TYPE_INVALID
)) {
1404 /* Compatibility with older systemd versions <
1405 * 19 during upgrades. This should be dropped
1408 p
= set_remove(d
->set
, (char*) path
);
1412 d
->result
= strdup("failed");
1418 log_error("Failed to parse message: %s", bus_error_message(&error
));
1422 dbus_error_free(&error
);
1423 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
1426 static int enable_wait_for_jobs(DBusConnection
*bus
) {
1434 dbus_error_init(&error
);
1435 dbus_bus_add_match(bus
,
1437 "sender='org.freedesktop.systemd1',"
1438 "interface='org.freedesktop.systemd1.Manager',"
1439 "member='JobRemoved',"
1440 "path='/org/freedesktop/systemd1'",
1443 if (dbus_error_is_set(&error
)) {
1444 log_error("Failed to add match: %s", bus_error_message(&error
));
1445 dbus_error_free(&error
);
1449 /* This is slightly dirty, since we don't undo the match registrations. */
1453 static int wait_for_jobs(DBusConnection
*bus
, Set
*s
) {
1463 if (!dbus_connection_add_filter(bus
, wait_filter
, &d
, NULL
)) {
1464 log_error("Failed to add filter.");
1469 while (!set_isempty(s
) &&
1470 dbus_connection_read_write_dispatch(bus
, -1))
1473 if (!arg_quiet
&& d
.result
) {
1474 if (streq(d
.result
, "timeout"))
1475 log_error("Job timed out.");
1476 else if (streq(d
.result
, "canceled"))
1477 log_error("Job canceled.");
1478 else if (streq(d
.result
, "dependency"))
1479 log_error("A dependency job failed. See system journal for details.");
1480 else if (!streq(d
.result
, "done") && !streq(d
.result
, "skipped"))
1481 log_error("Job failed. See system journal and 'systemctl status' for details.");
1484 if (streq_ptr(d
.result
, "timeout"))
1486 else if (streq_ptr(d
.result
, "canceled"))
1488 else if (!streq_ptr(d
.result
, "done") && !streq_ptr(d
.result
, "skipped"))
1496 /* This is slightly dirty, since we don't undo the filter registration. */
1501 static int start_unit_one(
1502 DBusConnection
*bus
,
1509 DBusMessage
*m
= NULL
, *reply
= NULL
;
1518 assert(arg_no_block
|| s
);
1520 if (!(m
= dbus_message_new_method_call(
1521 "org.freedesktop.systemd1",
1522 "/org/freedesktop/systemd1",
1523 "org.freedesktop.systemd1.Manager",
1525 log_error("Could not allocate message.");
1530 if (!dbus_message_append_args(m
,
1531 DBUS_TYPE_STRING
, &name
,
1532 DBUS_TYPE_STRING
, &mode
,
1533 DBUS_TYPE_INVALID
)) {
1534 log_error("Could not append arguments to message.");
1539 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, error
))) {
1541 if (arg_action
!= ACTION_SYSTEMCTL
&& error_is_no_service(error
)) {
1542 /* There's always a fallback possible for
1543 * legacy actions. */
1548 log_error("Failed to issue method call: %s", bus_error_message(error
));
1553 if (!dbus_message_get_args(reply
, error
,
1554 DBUS_TYPE_OBJECT_PATH
, &path
,
1555 DBUS_TYPE_INVALID
)) {
1556 log_error("Failed to parse reply: %s", bus_error_message(error
));
1561 if (need_daemon_reload(bus
, name
))
1562 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1563 arg_scope
== UNIT_FILE_SYSTEM
? "--system" : "--user");
1565 if (!arg_no_block
) {
1568 if (!(p
= strdup(path
))) {
1569 log_error("Failed to duplicate path.");
1574 if ((r
= set_put(s
, p
)) < 0) {
1576 log_error("Failed to add path to set.");
1585 dbus_message_unref(m
);
1588 dbus_message_unref(reply
);
1593 static enum action
verb_to_action(const char *verb
) {
1594 if (streq(verb
, "halt"))
1596 else if (streq(verb
, "poweroff"))
1597 return ACTION_POWEROFF
;
1598 else if (streq(verb
, "reboot"))
1599 return ACTION_REBOOT
;
1600 else if (streq(verb
, "kexec"))
1601 return ACTION_KEXEC
;
1602 else if (streq(verb
, "rescue"))
1603 return ACTION_RESCUE
;
1604 else if (streq(verb
, "emergency"))
1605 return ACTION_EMERGENCY
;
1606 else if (streq(verb
, "default"))
1607 return ACTION_DEFAULT
;
1608 else if (streq(verb
, "exit"))
1610 else if (streq(verb
, "suspend"))
1611 return ACTION_SUSPEND
;
1612 else if (streq(verb
, "hibernate"))
1613 return ACTION_HIBERNATE
;
1615 return ACTION_INVALID
;
1618 static int start_unit(DBusConnection
*bus
, char **args
) {
1620 static const char * const table
[_ACTION_MAX
] = {
1621 [ACTION_HALT
] = SPECIAL_HALT_TARGET
,
1622 [ACTION_POWEROFF
] = SPECIAL_POWEROFF_TARGET
,
1623 [ACTION_REBOOT
] = SPECIAL_REBOOT_TARGET
,
1624 [ACTION_KEXEC
] = SPECIAL_KEXEC_TARGET
,
1625 [ACTION_RUNLEVEL2
] = SPECIAL_RUNLEVEL2_TARGET
,
1626 [ACTION_RUNLEVEL3
] = SPECIAL_RUNLEVEL3_TARGET
,
1627 [ACTION_RUNLEVEL4
] = SPECIAL_RUNLEVEL4_TARGET
,
1628 [ACTION_RUNLEVEL5
] = SPECIAL_RUNLEVEL5_TARGET
,
1629 [ACTION_RESCUE
] = SPECIAL_RESCUE_TARGET
,
1630 [ACTION_EMERGENCY
] = SPECIAL_EMERGENCY_TARGET
,
1631 [ACTION_DEFAULT
] = SPECIAL_DEFAULT_TARGET
,
1632 [ACTION_EXIT
] = SPECIAL_EXIT_TARGET
,
1633 [ACTION_SUSPEND
] = SPECIAL_SUSPEND_TARGET
,
1634 [ACTION_HIBERNATE
] = SPECIAL_HIBERNATE_TARGET
1638 const char *method
, *mode
, *one_name
;
1643 dbus_error_init(&error
);
1647 ask_password_agent_open_if_enabled();
1649 if (arg_action
== ACTION_SYSTEMCTL
) {
1651 streq(args
[0], "stop") ||
1652 streq(args
[0], "condstop") ? "StopUnit" :
1653 streq(args
[0], "reload") ? "ReloadUnit" :
1654 streq(args
[0], "restart") ? "RestartUnit" :
1656 streq(args
[0], "try-restart") ||
1657 streq(args
[0], "condrestart") ? "TryRestartUnit" :
1659 streq(args
[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1661 streq(args
[0], "reload-or-try-restart") ||
1662 streq(args
[0], "condreload") ||
1664 streq(args
[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1668 (streq(args
[0], "isolate") ||
1669 streq(args
[0], "rescue") ||
1670 streq(args
[0], "emergency")) ? "isolate" : arg_job_mode
;
1672 one_name
= table
[verb_to_action(args
[0])];
1675 assert(arg_action
< ELEMENTSOF(table
));
1676 assert(table
[arg_action
]);
1678 method
= "StartUnit";
1680 mode
= (arg_action
== ACTION_EMERGENCY
||
1681 arg_action
== ACTION_RESCUE
||
1682 arg_action
== ACTION_RUNLEVEL2
||
1683 arg_action
== ACTION_RUNLEVEL3
||
1684 arg_action
== ACTION_RUNLEVEL4
||
1685 arg_action
== ACTION_RUNLEVEL5
) ? "isolate" : "replace";
1687 one_name
= table
[arg_action
];
1690 if (!arg_no_block
) {
1691 if ((ret
= enable_wait_for_jobs(bus
)) < 0) {
1692 log_error("Could not watch jobs: %s", strerror(-ret
));
1696 if (!(s
= set_new(string_hash_func
, string_compare_func
))) {
1697 log_error("Failed to allocate set.");
1704 if ((ret
= start_unit_one(bus
, method
, one_name
, mode
, &error
, s
)) <= 0)
1707 STRV_FOREACH(name
, args
+1)
1708 if ((r
= start_unit_one(bus
, method
, *name
, mode
, &error
, s
)) != 0) {
1709 ret
= translate_bus_error_to_exit_status(r
, &error
);
1710 dbus_error_free(&error
);
1715 if ((r
= wait_for_jobs(bus
, s
)) < 0) {
1724 dbus_error_free(&error
);
1729 /* Ask systemd-logind, which might grant access to unprivileged users
1730 * through PolicyKit */
1731 static int reboot_with_logind(DBusConnection
*bus
, enum action a
) {
1734 DBusMessage
*m
= NULL
, *reply
= NULL
;
1736 dbus_bool_t interactive
= true;
1739 dbus_error_init(&error
);
1741 polkit_agent_open_if_enabled();
1749 case ACTION_POWEROFF
:
1750 method
= "PowerOff";
1753 case ACTION_SUSPEND
:
1757 case ACTION_HIBERNATE
:
1758 method
= "Hibernate";
1765 m
= dbus_message_new_method_call(
1766 "org.freedesktop.login1",
1767 "/org/freedesktop/login1",
1768 "org.freedesktop.login1.Manager",
1771 log_error("Could not allocate message.");
1776 if (!dbus_message_append_args(m
,
1777 DBUS_TYPE_BOOLEAN
, &interactive
,
1778 DBUS_TYPE_INVALID
)) {
1779 log_error("Could not append arguments to message.");
1784 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
1786 if (error_is_no_service(&error
)) {
1787 log_debug("Failed to issue method call: %s", bus_error_message(&error
));
1792 if (dbus_error_has_name(&error
, DBUS_ERROR_ACCESS_DENIED
)) {
1793 log_debug("Failed to issue method call: %s", bus_error_message(&error
));
1798 log_info("Failed to issue method call: %s", bus_error_message(&error
));
1807 dbus_message_unref(m
);
1810 dbus_message_unref(reply
);
1812 dbus_error_free(&error
);
1820 static int start_special(DBusConnection
*bus
, char **args
) {
1826 a
= verb_to_action(args
[0]);
1828 if (arg_force
>= 2 && geteuid() != 0) {
1829 log_error("Must be root.");
1833 if (arg_force
>= 2 &&
1834 (a
== ACTION_HALT
||
1835 a
== ACTION_POWEROFF
||
1836 a
== ACTION_REBOOT
))
1839 if (arg_force
>= 1 &&
1840 (a
== ACTION_HALT
||
1841 a
== ACTION_POWEROFF
||
1842 a
== ACTION_REBOOT
||
1843 a
== ACTION_KEXEC
||
1845 return daemon_reload(bus
, args
);
1847 /* first try logind, to allow authentication with polkit */
1848 if (geteuid() != 0 &&
1849 (a
== ACTION_POWEROFF
||
1850 a
== ACTION_REBOOT
||
1851 a
== ACTION_SUSPEND
||
1852 a
== ACTION_HIBERNATE
)) {
1853 r
= reboot_with_logind(bus
, a
);
1858 r
= start_unit(bus
, args
);
1865 static int check_unit(DBusConnection
*bus
, char **args
) {
1866 DBusMessage
*m
= NULL
, *reply
= NULL
;
1868 *interface
= "org.freedesktop.systemd1.Unit",
1869 *property
= "ActiveState";
1870 int r
= 3; /* According to LSB: "program is not running" */
1877 dbus_error_init(&error
);
1879 STRV_FOREACH(name
, args
+1) {
1880 const char *path
= NULL
;
1882 DBusMessageIter iter
, sub
;
1884 if (!(m
= dbus_message_new_method_call(
1885 "org.freedesktop.systemd1",
1886 "/org/freedesktop/systemd1",
1887 "org.freedesktop.systemd1.Manager",
1889 log_error("Could not allocate message.");
1894 if (!dbus_message_append_args(m
,
1895 DBUS_TYPE_STRING
, name
,
1896 DBUS_TYPE_INVALID
)) {
1897 log_error("Could not append arguments to message.");
1902 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1904 /* Hmm, cannot figure out anything about this unit... */
1908 dbus_error_free(&error
);
1909 dbus_message_unref(m
);
1914 if (!dbus_message_get_args(reply
, &error
,
1915 DBUS_TYPE_OBJECT_PATH
, &path
,
1916 DBUS_TYPE_INVALID
)) {
1917 log_error("Failed to parse reply: %s", bus_error_message(&error
));
1922 dbus_message_unref(m
);
1923 if (!(m
= dbus_message_new_method_call(
1924 "org.freedesktop.systemd1",
1926 "org.freedesktop.DBus.Properties",
1928 log_error("Could not allocate message.");
1933 if (!dbus_message_append_args(m
,
1934 DBUS_TYPE_STRING
, &interface
,
1935 DBUS_TYPE_STRING
, &property
,
1936 DBUS_TYPE_INVALID
)) {
1937 log_error("Could not append arguments to message.");
1942 dbus_message_unref(reply
);
1943 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1944 log_error("Failed to issue method call: %s", bus_error_message(&error
));
1949 if (!dbus_message_iter_init(reply
, &iter
) ||
1950 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
1951 log_error("Failed to parse reply.");
1956 dbus_message_iter_recurse(&iter
, &sub
);
1958 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRING
) {
1959 log_error("Failed to parse reply.");
1964 dbus_message_iter_get_basic(&sub
, &state
);
1969 if (streq(state
, "active") || streq(state
, "reloading"))
1972 dbus_message_unref(m
);
1973 dbus_message_unref(reply
);
1979 dbus_message_unref(m
);
1982 dbus_message_unref(reply
);
1984 dbus_error_free(&error
);
1989 static int kill_unit(DBusConnection
*bus
, char **args
) {
1990 DBusMessage
*m
= NULL
;
1998 dbus_error_init(&error
);
2001 arg_kill_who
= "all";
2004 arg_kill_mode
= streq(arg_kill_who
, "all") ? "control-group" : "process";
2006 STRV_FOREACH(name
, args
+1) {
2009 if (!(m
= dbus_message_new_method_call(
2010 "org.freedesktop.systemd1",
2011 "/org/freedesktop/systemd1",
2012 "org.freedesktop.systemd1.Manager",
2014 log_error("Could not allocate message.");
2019 if (!dbus_message_append_args(m
,
2020 DBUS_TYPE_STRING
, name
,
2021 DBUS_TYPE_STRING
, &arg_kill_who
,
2022 DBUS_TYPE_STRING
, &arg_kill_mode
,
2023 DBUS_TYPE_INT32
, &arg_signal
,
2024 DBUS_TYPE_INVALID
)) {
2025 log_error("Could not append arguments to message.");
2030 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
2031 log_error("Failed to issue method call: %s", bus_error_message(&error
));
2032 dbus_error_free(&error
);
2036 dbus_message_unref(m
);
2039 dbus_message_unref(reply
);
2045 dbus_message_unref(m
);
2047 dbus_error_free(&error
);
2052 typedef struct ExecStatusInfo
{
2060 usec_t start_timestamp
;
2061 usec_t exit_timestamp
;
2066 LIST_FIELDS(struct ExecStatusInfo
, exec
);
2069 static void exec_status_info_free(ExecStatusInfo
*i
) {
2078 static int exec_status_info_deserialize(DBusMessageIter
*sub
, ExecStatusInfo
*i
) {
2079 uint64_t start_timestamp
, exit_timestamp
, start_timestamp_monotonic
, exit_timestamp_monotonic
;
2080 DBusMessageIter sub2
, sub3
;
2084 int32_t code
, status
;
2090 if (dbus_message_iter_get_arg_type(sub
) != DBUS_TYPE_STRUCT
)
2093 dbus_message_iter_recurse(sub
, &sub2
);
2095 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0)
2098 if (!(i
->path
= strdup(path
)))
2101 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_ARRAY
||
2102 dbus_message_iter_get_element_type(&sub2
) != DBUS_TYPE_STRING
)
2106 dbus_message_iter_recurse(&sub2
, &sub3
);
2107 while (dbus_message_iter_get_arg_type(&sub3
) != DBUS_TYPE_INVALID
) {
2108 assert(dbus_message_iter_get_arg_type(&sub3
) == DBUS_TYPE_STRING
);
2109 dbus_message_iter_next(&sub3
);
2114 if (!(i
->argv
= new0(char*, n
+1)))
2118 dbus_message_iter_recurse(&sub2
, &sub3
);
2119 while (dbus_message_iter_get_arg_type(&sub3
) != DBUS_TYPE_INVALID
) {
2122 assert(dbus_message_iter_get_arg_type(&sub3
) == DBUS_TYPE_STRING
);
2123 dbus_message_iter_get_basic(&sub3
, &s
);
2124 dbus_message_iter_next(&sub3
);
2126 if (!(i
->argv
[n
++] = strdup(s
)))
2130 if (!dbus_message_iter_next(&sub2
) ||
2131 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_BOOLEAN
, &ignore
, true) < 0 ||
2132 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &start_timestamp
, true) < 0 ||
2133 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &start_timestamp_monotonic
, true) < 0 ||
2134 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &exit_timestamp
, true) < 0 ||
2135 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &exit_timestamp_monotonic
, true) < 0 ||
2136 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &pid
, true) < 0 ||
2137 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_INT32
, &code
, true) < 0 ||
2138 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_INT32
, &status
, false) < 0)
2142 i
->start_timestamp
= (usec_t
) start_timestamp
;
2143 i
->exit_timestamp
= (usec_t
) exit_timestamp
;
2144 i
->pid
= (pid_t
) pid
;
2151 typedef struct UnitStatusInfo
{
2153 const char *load_state
;
2154 const char *active_state
;
2155 const char *sub_state
;
2156 const char *unit_file_state
;
2158 const char *description
;
2159 const char *following
;
2162 const char *default_control_group
;
2164 const char *load_error
;
2167 usec_t inactive_exit_timestamp
;
2168 usec_t inactive_exit_timestamp_monotonic
;
2169 usec_t active_enter_timestamp
;
2170 usec_t active_exit_timestamp
;
2171 usec_t inactive_enter_timestamp
;
2173 bool need_daemon_reload
;
2178 const char *status_text
;
2180 #ifdef HAVE_SYSV_COMPAT
2184 usec_t start_timestamp
;
2185 usec_t exit_timestamp
;
2187 int exit_code
, exit_status
;
2189 usec_t condition_timestamp
;
2190 bool condition_result
;
2193 unsigned n_accepted
;
2194 unsigned n_connections
;
2198 const char *sysfs_path
;
2200 /* Mount, Automount */
2206 LIST_HEAD(ExecStatusInfo
, exec
);
2209 static void print_status_info(UnitStatusInfo
*i
) {
2211 const char *on
, *off
, *ss
;
2213 char since1
[FORMAT_TIMESTAMP_PRETTY_MAX
], *s1
;
2214 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
2218 /* This shows pretty information about a unit. See
2219 * print_property() for a low-level property printer */
2221 printf("%s", strna(i
->id
));
2223 if (i
->description
&& !streq_ptr(i
->id
, i
->description
))
2224 printf(" - %s", i
->description
);
2229 printf("\t Follow: unit currently follows state of %s\n", i
->following
);
2231 if (streq_ptr(i
->load_state
, "error")) {
2232 on
= ansi_highlight_red(true);
2233 off
= ansi_highlight_red(false);
2238 printf("\t Loaded: %s%s%s (Reason: %s)\n", on
, strna(i
->load_state
), off
, i
->load_error
);
2239 else if (i
->path
&& i
->unit_file_state
)
2240 printf("\t Loaded: %s%s%s (%s; %s)\n", on
, strna(i
->load_state
), off
, i
->path
, i
->unit_file_state
);
2242 printf("\t Loaded: %s%s%s (%s)\n", on
, strna(i
->load_state
), off
, i
->path
);
2244 printf("\t Loaded: %s%s%s\n", on
, strna(i
->load_state
), off
);
2246 ss
= streq_ptr(i
->active_state
, i
->sub_state
) ? NULL
: i
->sub_state
;
2248 if (streq_ptr(i
->active_state
, "failed")) {
2249 on
= ansi_highlight_red(true);
2250 off
= ansi_highlight_red(false);
2251 } else if (streq_ptr(i
->active_state
, "active") || streq_ptr(i
->active_state
, "reloading")) {
2252 on
= ansi_highlight_green(true);
2253 off
= ansi_highlight_green(false);
2258 printf("\t Active: %s%s (%s)%s",
2260 strna(i
->active_state
),
2264 printf("\t Active: %s%s%s",
2266 strna(i
->active_state
),
2269 if (!isempty(i
->result
) && !streq(i
->result
, "success"))
2270 printf(" (Result: %s)", i
->result
);
2272 timestamp
= (streq_ptr(i
->active_state
, "active") ||
2273 streq_ptr(i
->active_state
, "reloading")) ? i
->active_enter_timestamp
:
2274 (streq_ptr(i
->active_state
, "inactive") ||
2275 streq_ptr(i
->active_state
, "failed")) ? i
->inactive_enter_timestamp
:
2276 streq_ptr(i
->active_state
, "activating") ? i
->inactive_exit_timestamp
:
2277 i
->active_exit_timestamp
;
2279 s1
= format_timestamp_pretty(since1
, sizeof(since1
), timestamp
);
2280 s2
= format_timestamp(since2
, sizeof(since2
), timestamp
);
2283 printf(" since %s; %s\n", s2
, s1
);
2285 printf(" since %s\n", s2
);
2289 if (!i
->condition_result
&& i
->condition_timestamp
> 0) {
2290 s1
= format_timestamp_pretty(since1
, sizeof(since1
), i
->condition_timestamp
);
2291 s2
= format_timestamp(since2
, sizeof(since2
), i
->condition_timestamp
);
2294 printf("\t start condition failed at %s; %s\n", s2
, s1
);
2296 printf("\t start condition failed at %s\n", s2
);
2300 printf("\t Device: %s\n", i
->sysfs_path
);
2302 printf("\t Where: %s\n", i
->where
);
2304 printf("\t What: %s\n", i
->what
);
2307 printf("\tAccepted: %u; Connected: %u\n", i
->n_accepted
, i
->n_connections
);
2309 LIST_FOREACH(exec
, p
, i
->exec
) {
2313 /* Only show exited processes here */
2317 t
= strv_join(p
->argv
, " ");
2318 printf("\t Process: %u %s=%s ", p
->pid
, p
->name
, strna(t
));
2321 #ifdef HAVE_SYSV_COMPAT
2323 good
= is_clean_exit_lsb(p
->code
, p
->status
);
2326 good
= is_clean_exit(p
->code
, p
->status
);
2329 on
= ansi_highlight_red(true);
2330 off
= ansi_highlight_red(false);
2334 printf("%s(code=%s, ", on
, sigchld_code_to_string(p
->code
));
2336 if (p
->code
== CLD_EXITED
) {
2339 printf("status=%i", p
->status
);
2341 #ifdef HAVE_SYSV_COMPAT
2342 if ((c
= exit_status_to_string(p
->status
, i
->is_sysv
? EXIT_STATUS_LSB
: EXIT_STATUS_SYSTEMD
)))
2344 if ((c
= exit_status_to_string(p
->status
, EXIT_STATUS_SYSTEMD
)))
2349 printf("signal=%s", signal_to_string(p
->status
));
2351 printf(")%s\n", off
);
2353 if (i
->main_pid
== p
->pid
&&
2354 i
->start_timestamp
== p
->start_timestamp
&&
2355 i
->exit_timestamp
== p
->start_timestamp
)
2356 /* Let's not show this twice */
2359 if (p
->pid
== i
->control_pid
)
2363 if (i
->main_pid
> 0 || i
->control_pid
> 0) {
2366 if (i
->main_pid
> 0) {
2367 printf("Main PID: %u", (unsigned) i
->main_pid
);
2371 get_process_comm(i
->main_pid
, &t
);
2376 } else if (i
->exit_code
> 0) {
2377 printf(" (code=%s, ", sigchld_code_to_string(i
->exit_code
));
2379 if (i
->exit_code
== CLD_EXITED
) {
2382 printf("status=%i", i
->exit_status
);
2384 #ifdef HAVE_SYSV_COMPAT
2385 if ((c
= exit_status_to_string(i
->exit_status
, i
->is_sysv
? EXIT_STATUS_LSB
: EXIT_STATUS_SYSTEMD
)))
2387 if ((c
= exit_status_to_string(i
->exit_status
, EXIT_STATUS_SYSTEMD
)))
2392 printf("signal=%s", signal_to_string(i
->exit_status
));
2397 if (i
->main_pid
> 0 && i
->control_pid
> 0)
2400 if (i
->control_pid
> 0) {
2403 printf(" Control: %u", (unsigned) i
->control_pid
);
2405 get_process_comm(i
->control_pid
, &t
);
2416 printf("\t Status: \"%s\"\n", i
->status_text
);
2418 if (i
->default_control_group
) {
2421 printf("\t CGroup: %s\n", i
->default_control_group
);
2423 if (arg_transport
!= TRANSPORT_SSH
) {
2433 if (i
->main_pid
> 0)
2434 extra
[k
++] = i
->main_pid
;
2436 if (i
->control_pid
> 0)
2437 extra
[k
++] = i
->control_pid
;
2439 show_cgroup_and_extra_by_spec(i
->default_control_group
, "\t\t ", c
, false, arg_all
, extra
, k
);
2443 if (i
->id
&& arg_transport
!= TRANSPORT_SSH
) {
2445 show_journal_by_unit(i
->id
, arg_output
, 0, i
->inactive_exit_timestamp_monotonic
, arg_lines
, arg_all
, arg_follow
);
2448 if (i
->need_daemon_reload
)
2449 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2450 ansi_highlight_red(true),
2451 ansi_highlight_red(false),
2452 arg_scope
== UNIT_FILE_SYSTEM
? "--system" : "--user");
2455 static int status_property(const char *name
, DBusMessageIter
*iter
, UnitStatusInfo
*i
) {
2461 switch (dbus_message_iter_get_arg_type(iter
)) {
2463 case DBUS_TYPE_STRING
: {
2466 dbus_message_iter_get_basic(iter
, &s
);
2469 if (streq(name
, "Id"))
2471 else if (streq(name
, "LoadState"))
2473 else if (streq(name
, "ActiveState"))
2474 i
->active_state
= s
;
2475 else if (streq(name
, "SubState"))
2477 else if (streq(name
, "Description"))
2479 else if (streq(name
, "FragmentPath"))
2481 #ifdef HAVE_SYSV_COMPAT
2482 else if (streq(name
, "SysVPath")) {
2487 else if (streq(name
, "DefaultControlGroup"))
2488 i
->default_control_group
= s
;
2489 else if (streq(name
, "StatusText"))
2491 else if (streq(name
, "SysFSPath"))
2493 else if (streq(name
, "Where"))
2495 else if (streq(name
, "What"))
2497 else if (streq(name
, "Following"))
2499 else if (streq(name
, "UnitFileState"))
2500 i
->unit_file_state
= s
;
2501 else if (streq(name
, "Result"))
2508 case DBUS_TYPE_BOOLEAN
: {
2511 dbus_message_iter_get_basic(iter
, &b
);
2513 if (streq(name
, "Accept"))
2515 else if (streq(name
, "NeedDaemonReload"))
2516 i
->need_daemon_reload
= b
;
2517 else if (streq(name
, "ConditionResult"))
2518 i
->condition_result
= b
;
2523 case DBUS_TYPE_UINT32
: {
2526 dbus_message_iter_get_basic(iter
, &u
);
2528 if (streq(name
, "MainPID")) {
2530 i
->main_pid
= (pid_t
) u
;
2533 } else if (streq(name
, "ControlPID"))
2534 i
->control_pid
= (pid_t
) u
;
2535 else if (streq(name
, "ExecMainPID")) {
2537 i
->main_pid
= (pid_t
) u
;
2538 } else if (streq(name
, "NAccepted"))
2540 else if (streq(name
, "NConnections"))
2541 i
->n_connections
= u
;
2546 case DBUS_TYPE_INT32
: {
2549 dbus_message_iter_get_basic(iter
, &j
);
2551 if (streq(name
, "ExecMainCode"))
2552 i
->exit_code
= (int) j
;
2553 else if (streq(name
, "ExecMainStatus"))
2554 i
->exit_status
= (int) j
;
2559 case DBUS_TYPE_UINT64
: {
2562 dbus_message_iter_get_basic(iter
, &u
);
2564 if (streq(name
, "ExecMainStartTimestamp"))
2565 i
->start_timestamp
= (usec_t
) u
;
2566 else if (streq(name
, "ExecMainExitTimestamp"))
2567 i
->exit_timestamp
= (usec_t
) u
;
2568 else if (streq(name
, "ActiveEnterTimestamp"))
2569 i
->active_enter_timestamp
= (usec_t
) u
;
2570 else if (streq(name
, "InactiveEnterTimestamp"))
2571 i
->inactive_enter_timestamp
= (usec_t
) u
;
2572 else if (streq(name
, "InactiveExitTimestamp"))
2573 i
->inactive_exit_timestamp
= (usec_t
) u
;
2574 else if (streq(name
, "InactiveExitTimestampMonotonic"))
2575 i
->inactive_exit_timestamp_monotonic
= (usec_t
) u
;
2576 else if (streq(name
, "ActiveExitTimestamp"))
2577 i
->active_exit_timestamp
= (usec_t
) u
;
2578 else if (streq(name
, "ConditionTimestamp"))
2579 i
->condition_timestamp
= (usec_t
) u
;
2584 case DBUS_TYPE_ARRAY
: {
2586 if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&&
2587 startswith(name
, "Exec")) {
2588 DBusMessageIter sub
;
2590 dbus_message_iter_recurse(iter
, &sub
);
2591 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2592 ExecStatusInfo
*info
;
2595 if (!(info
= new0(ExecStatusInfo
, 1)))
2598 if (!(info
->name
= strdup(name
))) {
2603 if ((r
= exec_status_info_deserialize(&sub
, info
)) < 0) {
2608 LIST_PREPEND(ExecStatusInfo
, exec
, i
->exec
, info
);
2610 dbus_message_iter_next(&sub
);
2617 case DBUS_TYPE_STRUCT
: {
2619 if (streq(name
, "LoadError")) {
2620 DBusMessageIter sub
;
2621 const char *n
, *message
;
2624 dbus_message_iter_recurse(iter
, &sub
);
2626 r
= bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &n
, true);
2630 r
= bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &message
, false);
2634 if (!isempty(message
))
2635 i
->load_error
= message
;
2645 static int print_property(const char *name
, DBusMessageIter
*iter
) {
2649 /* This is a low-level property printer, see
2650 * print_status_info() for the nicer output */
2652 if (arg_property
&& !strv_find(arg_property
, name
))
2655 switch (dbus_message_iter_get_arg_type(iter
)) {
2657 case DBUS_TYPE_STRUCT
: {
2658 DBusMessageIter sub
;
2659 dbus_message_iter_recurse(iter
, &sub
);
2661 if (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_UINT32
&& streq(name
, "Job")) {
2664 dbus_message_iter_get_basic(&sub
, &u
);
2667 printf("%s=%u\n", name
, (unsigned) u
);
2669 printf("%s=\n", name
);
2672 } else if (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRING
&& streq(name
, "Unit")) {
2675 dbus_message_iter_get_basic(&sub
, &s
);
2677 if (arg_all
|| s
[0])
2678 printf("%s=%s\n", name
, s
);
2681 } else if (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRING
&& streq(name
, "LoadError")) {
2682 const char *a
= NULL
, *b
= NULL
;
2684 if (bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &a
, true) >= 0)
2685 bus_iter_get_basic_and_next(&sub
, DBUS_TYPE_STRING
, &b
, false);
2687 if (arg_all
|| !isempty(a
) || !isempty(b
))
2688 printf("%s=%s \"%s\"\n", name
, strempty(a
), strempty(b
));
2696 case DBUS_TYPE_ARRAY
:
2698 if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "EnvironmentFiles")) {
2699 DBusMessageIter sub
, sub2
;
2701 dbus_message_iter_recurse(iter
, &sub
);
2702 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2706 dbus_message_iter_recurse(&sub
, &sub2
);
2708 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) >= 0 &&
2709 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_BOOLEAN
, &ignore
, false) >= 0)
2710 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path
, yes_no(ignore
));
2712 dbus_message_iter_next(&sub
);
2717 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "Paths")) {
2718 DBusMessageIter sub
, sub2
;
2720 dbus_message_iter_recurse(iter
, &sub
);
2721 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2722 const char *type
, *path
;
2724 dbus_message_iter_recurse(&sub
, &sub2
);
2726 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) >= 0 &&
2727 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, false) >= 0)
2728 printf("%s=%s\n", type
, path
);
2730 dbus_message_iter_next(&sub
);
2735 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "Timers")) {
2736 DBusMessageIter sub
, sub2
;
2738 dbus_message_iter_recurse(iter
, &sub
);
2739 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2741 uint64_t value
, next_elapse
;
2743 dbus_message_iter_recurse(&sub
, &sub2
);
2745 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &base
, true) >= 0 &&
2746 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &value
, true) >= 0 &&
2747 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT64
, &next_elapse
, false) >= 0) {
2748 char timespan1
[FORMAT_TIMESPAN_MAX
], timespan2
[FORMAT_TIMESPAN_MAX
];
2750 printf("%s={ value=%s ; next_elapse=%s }\n",
2752 format_timespan(timespan1
, sizeof(timespan1
), value
),
2753 format_timespan(timespan2
, sizeof(timespan2
), next_elapse
));
2756 dbus_message_iter_next(&sub
);
2761 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& streq(name
, "ControlGroupAttributes")) {
2762 DBusMessageIter sub
, sub2
;
2764 dbus_message_iter_recurse(iter
, &sub
);
2765 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2766 const char *controller
, *attr
, *value
;
2768 dbus_message_iter_recurse(&sub
, &sub2
);
2770 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &controller
, true) >= 0 &&
2771 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &attr
, true) >= 0 &&
2772 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &value
, false) >= 0) {
2774 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2780 dbus_message_iter_next(&sub
);
2785 } else if (dbus_message_iter_get_element_type(iter
) == DBUS_TYPE_STRUCT
&& startswith(name
, "Exec")) {
2786 DBusMessageIter sub
;
2788 dbus_message_iter_recurse(iter
, &sub
);
2789 while (dbus_message_iter_get_arg_type(&sub
) == DBUS_TYPE_STRUCT
) {
2790 ExecStatusInfo info
;
2793 if (exec_status_info_deserialize(&sub
, &info
) >= 0) {
2794 char timestamp1
[FORMAT_TIMESTAMP_MAX
], timestamp2
[FORMAT_TIMESTAMP_MAX
];
2797 t
= strv_join(info
.argv
, " ");
2799 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2803 yes_no(info
.ignore
),
2804 strna(format_timestamp(timestamp1
, sizeof(timestamp1
), info
.start_timestamp
)),
2805 strna(format_timestamp(timestamp2
, sizeof(timestamp2
), info
.exit_timestamp
)),
2806 (unsigned) info
. pid
,
2807 sigchld_code_to_string(info
.code
),
2809 info
.code
== CLD_EXITED
? "" : "/",
2810 strempty(info
.code
== CLD_EXITED
? NULL
: signal_to_string(info
.status
)));
2816 strv_free(info
.argv
);
2818 dbus_message_iter_next(&sub
);
2827 if (generic_print_property(name
, iter
, arg_all
) > 0)
2831 printf("%s=[unprintable]\n", name
);
2836 static int show_one(const char *verb
, DBusConnection
*bus
, const char *path
, bool show_properties
, bool *new_line
) {
2837 DBusMessage
*m
= NULL
, *reply
= NULL
;
2838 const char *interface
= "";
2841 DBusMessageIter iter
, sub
, sub2
, sub3
;
2842 UnitStatusInfo info
;
2850 dbus_error_init(&error
);
2852 if (!(m
= dbus_message_new_method_call(
2853 "org.freedesktop.systemd1",
2855 "org.freedesktop.DBus.Properties",
2857 log_error("Could not allocate message.");
2862 if (!dbus_message_append_args(m
,
2863 DBUS_TYPE_STRING
, &interface
,
2864 DBUS_TYPE_INVALID
)) {
2865 log_error("Could not append arguments to message.");
2870 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
2871 log_error("Failed to issue method call: %s", bus_error_message(&error
));
2876 if (!dbus_message_iter_init(reply
, &iter
) ||
2877 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
2878 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_DICT_ENTRY
) {
2879 log_error("Failed to parse reply.");
2884 dbus_message_iter_recurse(&iter
, &sub
);
2891 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
2894 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_DICT_ENTRY
) {
2895 log_error("Failed to parse reply.");
2900 dbus_message_iter_recurse(&sub
, &sub2
);
2902 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &name
, true) < 0) {
2903 log_error("Failed to parse reply.");
2908 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_VARIANT
) {
2909 log_error("Failed to parse reply.");
2914 dbus_message_iter_recurse(&sub2
, &sub3
);
2916 if (show_properties
)
2917 r
= print_property(name
, &sub3
);
2919 r
= status_property(name
, &sub3
, &info
);
2922 log_error("Failed to parse reply.");
2927 dbus_message_iter_next(&sub
);
2932 if (!show_properties
)
2933 print_status_info(&info
);
2935 if (!streq_ptr(info
.active_state
, "active") &&
2936 !streq_ptr(info
.active_state
, "reloading") &&
2937 streq(verb
, "status"))
2938 /* According to LSB: "program not running" */
2941 while ((p
= info
.exec
)) {
2942 LIST_REMOVE(ExecStatusInfo
, exec
, info
.exec
, p
);
2943 exec_status_info_free(p
);
2948 dbus_message_unref(m
);
2951 dbus_message_unref(reply
);
2953 dbus_error_free(&error
);
2958 static int show_one_by_pid(const char *verb
, DBusConnection
*bus
, uint32_t pid
, bool *new_line
) {
2959 DBusMessage
*m
= NULL
, *reply
= NULL
;
2960 const char *path
= NULL
;
2964 dbus_error_init(&error
);
2966 m
= dbus_message_new_method_call(
2967 "org.freedesktop.systemd1",
2968 "/org/freedesktop/systemd1",
2969 "org.freedesktop.systemd1.Manager",
2972 log_error("Could not allocate message.");
2977 if (!dbus_message_append_args(m
,
2978 DBUS_TYPE_UINT32
, &pid
,
2979 DBUS_TYPE_INVALID
)) {
2980 log_error("Could not append arguments to message.");
2985 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
2987 log_error("Failed to issue method call: %s", bus_error_message(&error
));
2992 if (!dbus_message_get_args(reply
, &error
,
2993 DBUS_TYPE_OBJECT_PATH
, &path
,
2994 DBUS_TYPE_INVALID
)) {
2995 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3000 r
= show_one(verb
, bus
, path
, false, new_line
);
3004 dbus_message_unref(m
);
3007 dbus_message_unref(reply
);
3009 dbus_error_free(&error
);
3014 static int show(DBusConnection
*bus
, char **args
) {
3016 bool show_properties
, new_line
= false;
3022 show_properties
= !streq(args
[0], "status");
3024 if (show_properties
)
3025 pager_open_if_enabled();
3027 if (show_properties
&& strv_length(args
) <= 1) {
3028 /* If not argument is specified inspect the manager
3031 return show_one(args
[0], bus
, "/org/freedesktop/systemd1", show_properties
, &new_line
);
3034 STRV_FOREACH(name
, args
+1) {
3037 if (safe_atou32(*name
, &id
) < 0) {
3039 /* Interpret as unit name */
3042 e
= bus_path_escape(*name
);
3045 p
= strappend("/org/freedesktop/systemd1/unit/", e
);
3050 r
= show_one(args
[0], bus
, p
, show_properties
, &new_line
);
3056 } else if (show_properties
) {
3058 /* Interpret as job id */
3061 if (asprintf(&p
, "/org/freedesktop/systemd1/job/%u", id
) < 0)
3064 r
= show_one(args
[0], bus
, p
, show_properties
, &new_line
);
3072 /* Interpret as PID */
3074 r
= show_one_by_pid(args
[0], bus
, id
, &new_line
);
3083 static int dump(DBusConnection
*bus
, char **args
) {
3084 DBusMessage
*m
= NULL
, *reply
= NULL
;
3089 dbus_error_init(&error
);
3091 pager_open_if_enabled();
3093 if (!(m
= dbus_message_new_method_call(
3094 "org.freedesktop.systemd1",
3095 "/org/freedesktop/systemd1",
3096 "org.freedesktop.systemd1.Manager",
3098 log_error("Could not allocate message.");
3102 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3103 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3108 if (!dbus_message_get_args(reply
, &error
,
3109 DBUS_TYPE_STRING
, &text
,
3110 DBUS_TYPE_INVALID
)) {
3111 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3116 fputs(text
, stdout
);
3122 dbus_message_unref(m
);
3125 dbus_message_unref(reply
);
3127 dbus_error_free(&error
);
3132 static int snapshot(DBusConnection
*bus
, char **args
) {
3133 DBusMessage
*m
= NULL
, *reply
= NULL
;
3136 const char *name
= "", *path
, *id
;
3137 dbus_bool_t cleanup
= FALSE
;
3138 DBusMessageIter iter
, sub
;
3140 *interface
= "org.freedesktop.systemd1.Unit",
3143 dbus_error_init(&error
);
3145 if (!(m
= dbus_message_new_method_call(
3146 "org.freedesktop.systemd1",
3147 "/org/freedesktop/systemd1",
3148 "org.freedesktop.systemd1.Manager",
3149 "CreateSnapshot"))) {
3150 log_error("Could not allocate message.");
3154 if (strv_length(args
) > 1)
3157 if (!dbus_message_append_args(m
,
3158 DBUS_TYPE_STRING
, &name
,
3159 DBUS_TYPE_BOOLEAN
, &cleanup
,
3160 DBUS_TYPE_INVALID
)) {
3161 log_error("Could not append arguments to message.");
3166 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3167 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3172 if (!dbus_message_get_args(reply
, &error
,
3173 DBUS_TYPE_OBJECT_PATH
, &path
,
3174 DBUS_TYPE_INVALID
)) {
3175 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3180 dbus_message_unref(m
);
3181 if (!(m
= dbus_message_new_method_call(
3182 "org.freedesktop.systemd1",
3184 "org.freedesktop.DBus.Properties",
3186 log_error("Could not allocate message.");
3190 if (!dbus_message_append_args(m
,
3191 DBUS_TYPE_STRING
, &interface
,
3192 DBUS_TYPE_STRING
, &property
,
3193 DBUS_TYPE_INVALID
)) {
3194 log_error("Could not append arguments to message.");
3199 dbus_message_unref(reply
);
3200 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3201 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3206 if (!dbus_message_iter_init(reply
, &iter
) ||
3207 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
3208 log_error("Failed to parse reply.");
3213 dbus_message_iter_recurse(&iter
, &sub
);
3215 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRING
) {
3216 log_error("Failed to parse reply.");
3221 dbus_message_iter_get_basic(&sub
, &id
);
3229 dbus_message_unref(m
);
3232 dbus_message_unref(reply
);
3234 dbus_error_free(&error
);
3239 static int delete_snapshot(DBusConnection
*bus
, char **args
) {
3240 DBusMessage
*m
= NULL
, *reply
= NULL
;
3248 dbus_error_init(&error
);
3250 STRV_FOREACH(name
, args
+1) {
3251 const char *path
= NULL
;
3253 if (!(m
= dbus_message_new_method_call(
3254 "org.freedesktop.systemd1",
3255 "/org/freedesktop/systemd1",
3256 "org.freedesktop.systemd1.Manager",
3258 log_error("Could not allocate message.");
3263 if (!dbus_message_append_args(m
,
3264 DBUS_TYPE_STRING
, name
,
3265 DBUS_TYPE_INVALID
)) {
3266 log_error("Could not append arguments to message.");
3271 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3272 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3277 if (!dbus_message_get_args(reply
, &error
,
3278 DBUS_TYPE_OBJECT_PATH
, &path
,
3279 DBUS_TYPE_INVALID
)) {
3280 log_error("Failed to parse reply: %s", bus_error_message(&error
));
3285 dbus_message_unref(m
);
3286 if (!(m
= dbus_message_new_method_call(
3287 "org.freedesktop.systemd1",
3289 "org.freedesktop.systemd1.Snapshot",
3291 log_error("Could not allocate message.");
3296 dbus_message_unref(reply
);
3297 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3298 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3303 dbus_message_unref(m
);
3304 dbus_message_unref(reply
);
3312 dbus_message_unref(m
);
3315 dbus_message_unref(reply
);
3317 dbus_error_free(&error
);
3322 static int daemon_reload(DBusConnection
*bus
, char **args
) {
3323 DBusMessage
*m
= NULL
, *reply
= NULL
;
3328 dbus_error_init(&error
);
3330 if (arg_action
== ACTION_RELOAD
)
3332 else if (arg_action
== ACTION_REEXEC
)
3333 method
= "Reexecute";
3335 assert(arg_action
== ACTION_SYSTEMCTL
);
3338 streq(args
[0], "clear-jobs") ||
3339 streq(args
[0], "cancel") ? "ClearJobs" :
3340 streq(args
[0], "daemon-reexec") ? "Reexecute" :
3341 streq(args
[0], "reset-failed") ? "ResetFailed" :
3342 streq(args
[0], "halt") ? "Halt" :
3343 streq(args
[0], "poweroff") ? "PowerOff" :
3344 streq(args
[0], "reboot") ? "Reboot" :
3345 streq(args
[0], "kexec") ? "KExec" :
3346 streq(args
[0], "exit") ? "Exit" :
3347 /* "daemon-reload" */ "Reload";
3350 if (!(m
= dbus_message_new_method_call(
3351 "org.freedesktop.systemd1",
3352 "/org/freedesktop/systemd1",
3353 "org.freedesktop.systemd1.Manager",
3355 log_error("Could not allocate message.");
3359 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3361 if (arg_action
!= ACTION_SYSTEMCTL
&& error_is_no_service(&error
)) {
3362 /* There's always a fallback possible for
3363 * legacy actions. */
3368 if (streq(method
, "Reexecute") && dbus_error_has_name(&error
, DBUS_ERROR_NO_REPLY
)) {
3369 /* On reexecution, we expect a disconnect, not
3375 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3384 dbus_message_unref(m
);
3387 dbus_message_unref(reply
);
3389 dbus_error_free(&error
);
3394 static int reset_failed(DBusConnection
*bus
, char **args
) {
3395 DBusMessage
*m
= NULL
;
3401 dbus_error_init(&error
);
3403 if (strv_length(args
) <= 1)
3404 return daemon_reload(bus
, args
);
3406 STRV_FOREACH(name
, args
+1) {
3409 if (!(m
= dbus_message_new_method_call(
3410 "org.freedesktop.systemd1",
3411 "/org/freedesktop/systemd1",
3412 "org.freedesktop.systemd1.Manager",
3413 "ResetFailedUnit"))) {
3414 log_error("Could not allocate message.");
3419 if (!dbus_message_append_args(m
,
3420 DBUS_TYPE_STRING
, name
,
3421 DBUS_TYPE_INVALID
)) {
3422 log_error("Could not append arguments to message.");
3427 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3428 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3433 dbus_message_unref(m
);
3434 dbus_message_unref(reply
);
3442 dbus_message_unref(m
);
3444 dbus_error_free(&error
);
3449 static int show_enviroment(DBusConnection
*bus
, char **args
) {
3450 DBusMessage
*m
= NULL
, *reply
= NULL
;
3452 DBusMessageIter iter
, sub
, sub2
;
3455 *interface
= "org.freedesktop.systemd1.Manager",
3456 *property
= "Environment";
3458 dbus_error_init(&error
);
3460 pager_open_if_enabled();
3462 if (!(m
= dbus_message_new_method_call(
3463 "org.freedesktop.systemd1",
3464 "/org/freedesktop/systemd1",
3465 "org.freedesktop.DBus.Properties",
3467 log_error("Could not allocate message.");
3471 if (!dbus_message_append_args(m
,
3472 DBUS_TYPE_STRING
, &interface
,
3473 DBUS_TYPE_STRING
, &property
,
3474 DBUS_TYPE_INVALID
)) {
3475 log_error("Could not append arguments to message.");
3480 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3481 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3486 if (!dbus_message_iter_init(reply
, &iter
) ||
3487 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
3488 log_error("Failed to parse reply.");
3493 dbus_message_iter_recurse(&iter
, &sub
);
3495 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_ARRAY
||
3496 dbus_message_iter_get_element_type(&sub
) != DBUS_TYPE_STRING
) {
3497 log_error("Failed to parse reply.");
3502 dbus_message_iter_recurse(&sub
, &sub2
);
3504 while (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_INVALID
) {
3507 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_STRING
) {
3508 log_error("Failed to parse reply.");
3513 dbus_message_iter_get_basic(&sub2
, &text
);
3514 printf("%s\n", text
);
3516 dbus_message_iter_next(&sub2
);
3523 dbus_message_unref(m
);
3526 dbus_message_unref(reply
);
3528 dbus_error_free(&error
);
3533 static int switch_root(DBusConnection
*bus
, char **args
) {
3534 DBusMessage
*m
= NULL
, *reply
= NULL
;
3536 const char *root
, *init
;
3540 dbus_error_init(&error
);
3542 l
= strv_length(args
);
3543 if (l
< 2 || l
> 3) {
3544 log_error("Wrong number of arguments.");
3549 init
= l
>= 3 ? args
[2] : "";
3551 m
= dbus_message_new_method_call(
3552 "org.freedesktop.systemd1",
3553 "/org/freedesktop/systemd1",
3554 "org.freedesktop.systemd1.Manager",
3557 log_error("Could not allocate message.");
3561 if (!dbus_message_append_args(
3563 DBUS_TYPE_STRING
, &root
,
3564 DBUS_TYPE_STRING
, &init
,
3565 DBUS_TYPE_INVALID
)) {
3566 log_error("Could not append arguments to message.");
3571 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
3573 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3582 dbus_message_unref(m
);
3585 dbus_message_unref(reply
);
3587 dbus_error_free(&error
);
3592 static int set_environment(DBusConnection
*bus
, char **args
) {
3593 DBusMessage
*m
= NULL
, *reply
= NULL
;
3597 DBusMessageIter iter
, sub
;
3600 dbus_error_init(&error
);
3602 method
= streq(args
[0], "set-environment")
3604 : "UnsetEnvironment";
3606 if (!(m
= dbus_message_new_method_call(
3607 "org.freedesktop.systemd1",
3608 "/org/freedesktop/systemd1",
3609 "org.freedesktop.systemd1.Manager",
3612 log_error("Could not allocate message.");
3616 dbus_message_iter_init_append(m
, &iter
);
3618 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "s", &sub
)) {
3619 log_error("Could not append arguments to message.");
3624 STRV_FOREACH(name
, args
+1)
3625 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, name
)) {
3626 log_error("Could not append arguments to message.");
3631 if (!dbus_message_iter_close_container(&iter
, &sub
)) {
3632 log_error("Could not append arguments to message.");
3637 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
3638 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3647 dbus_message_unref(m
);
3650 dbus_message_unref(reply
);
3652 dbus_error_free(&error
);
3657 static int enable_sysv_units(char **args
) {
3660 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3661 const char *verb
= args
[0];
3662 unsigned f
= 1, t
= 1;
3665 if (arg_scope
!= UNIT_FILE_SYSTEM
)
3668 if (!streq(verb
, "enable") &&
3669 !streq(verb
, "disable") &&
3670 !streq(verb
, "is-enabled"))
3673 /* Processes all SysV units, and reshuffles the array so that
3674 * afterwards only the native units remain */
3677 r
= lookup_paths_init(&paths
, MANAGER_SYSTEM
, false);
3683 for (f
= 1; args
[f
]; f
++) {
3686 bool found_native
= false, found_sysv
;
3688 const char *argv
[6] = { "/sbin/chkconfig", NULL
, NULL
, NULL
, NULL
};
3689 char **k
, *l
, *q
= NULL
;
3696 if (!endswith(name
, ".service"))
3699 if (path_is_absolute(name
))
3702 STRV_FOREACH(k
, paths
.unit_path
) {
3705 if (!isempty(arg_root
))
3706 asprintf(&p
, "%s/%s/%s", arg_root
, *k
, name
);
3708 asprintf(&p
, "%s/%s", *k
, name
);
3711 log_error("No memory");
3716 found_native
= access(p
, F_OK
) >= 0;
3727 if (!isempty(arg_root
))
3728 asprintf(&p
, "%s/" SYSTEM_SYSVINIT_PATH
"/%s", arg_root
, name
);
3730 asprintf(&p
, SYSTEM_SYSVINIT_PATH
"/%s", name
);
3732 log_error("No memory");
3737 p
[strlen(p
) - sizeof(".service") + 1] = 0;
3738 found_sysv
= access(p
, F_OK
) >= 0;
3745 /* Mark this entry, so that we don't try enabling it as native unit */
3746 args
[f
] = (char*) "";
3748 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name
);
3750 if (!isempty(arg_root
))
3751 argv
[c
++] = q
= strappend("--root=", arg_root
);
3753 argv
[c
++] = path_get_file_name(p
);
3755 streq(verb
, "enable") ? "on" :
3756 streq(verb
, "disable") ? "off" : "--level=5";
3759 l
= strv_join((char**)argv
, " ");
3761 log_error("No memory.");
3768 log_info("Executing %s", l
);
3773 log_error("Failed to fork: %m");
3778 } else if (pid
== 0) {
3781 execv(argv
[0], (char**) argv
);
3782 _exit(EXIT_FAILURE
);
3788 j
= wait_for_terminate(pid
, &status
);
3790 log_error("Failed to wait for child: %s", strerror(-r
));
3795 if (status
.si_code
== CLD_EXITED
) {
3796 if (streq(verb
, "is-enabled")) {
3797 if (status
.si_status
== 0) {
3806 } else if (status
.si_status
!= 0) {
3817 lookup_paths_free(&paths
);
3819 /* Drop all SysV units */
3820 for (f
= 1, t
= 1; args
[f
]; f
++) {
3822 if (isempty(args
[f
]))
3825 args
[t
++] = args
[f
];
3834 static int enable_unit(DBusConnection
*bus
, char **args
) {
3835 const char *verb
= args
[0];
3836 UnitFileChange
*changes
= NULL
;
3837 unsigned n_changes
= 0, i
;
3838 int carries_install_info
= -1;
3839 DBusMessage
*m
= NULL
, *reply
= NULL
;
3843 r
= enable_sysv_units(args
);
3850 dbus_error_init(&error
);
3852 if (!bus
|| avoid_bus()) {
3853 if (streq(verb
, "enable")) {
3854 r
= unit_file_enable(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3855 carries_install_info
= r
;
3856 } else if (streq(verb
, "disable"))
3857 r
= unit_file_disable(arg_scope
, arg_runtime
, arg_root
, args
+1, &changes
, &n_changes
);
3858 else if (streq(verb
, "reenable")) {
3859 r
= unit_file_reenable(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3860 carries_install_info
= r
;
3861 } else if (streq(verb
, "link"))
3862 r
= unit_file_link(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3863 else if (streq(verb
, "preset")) {
3864 r
= unit_file_preset(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3865 carries_install_info
= r
;
3866 } else if (streq(verb
, "mask"))
3867 r
= unit_file_mask(arg_scope
, arg_runtime
, arg_root
, args
+1, arg_force
, &changes
, &n_changes
);
3868 else if (streq(verb
, "unmask"))
3869 r
= unit_file_unmask(arg_scope
, arg_runtime
, arg_root
, args
+1, &changes
, &n_changes
);
3871 assert_not_reached("Unknown verb");
3874 log_error("Operation failed: %s", strerror(-r
));
3879 for (i
= 0; i
< n_changes
; i
++) {
3880 if (changes
[i
].type
== UNIT_FILE_SYMLINK
)
3881 log_info("ln -s '%s' '%s'", changes
[i
].source
, changes
[i
].path
);
3883 log_info("rm '%s'", changes
[i
].path
);
3889 bool send_force
= true, expect_carries_install_info
= false;
3891 DBusMessageIter iter
, sub
, sub2
;
3893 if (streq(verb
, "enable")) {
3894 method
= "EnableUnitFiles";
3895 expect_carries_install_info
= true;
3896 } else if (streq(verb
, "disable")) {
3897 method
= "DisableUnitFiles";
3899 } else if (streq(verb
, "reenable")) {
3900 method
= "ReenableUnitFiles";
3901 expect_carries_install_info
= true;
3902 } else if (streq(verb
, "link"))
3903 method
= "LinkUnitFiles";
3904 else if (streq(verb
, "preset")) {
3905 method
= "PresetUnitFiles";
3906 expect_carries_install_info
= true;
3907 } else if (streq(verb
, "mask"))
3908 method
= "MaskUnitFiles";
3909 else if (streq(verb
, "unmask")) {
3910 method
= "UnmaskUnitFiles";
3913 assert_not_reached("Unknown verb");
3915 m
= dbus_message_new_method_call(
3916 "org.freedesktop.systemd1",
3917 "/org/freedesktop/systemd1",
3918 "org.freedesktop.systemd1.Manager",
3921 log_error("Out of memory");
3926 dbus_message_iter_init_append(m
, &iter
);
3928 r
= bus_append_strv_iter(&iter
, args
+1);
3930 log_error("Failed to append unit files.");
3935 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &a
)) {
3936 log_error("Failed to append runtime boolean.");
3944 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &b
)) {
3945 log_error("Failed to append force boolean.");
3951 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
3953 log_error("Failed to issue method call: %s", bus_error_message(&error
));
3958 if (!dbus_message_iter_init(reply
, &iter
)) {
3959 log_error("Failed to initialize iterator.");
3963 if (expect_carries_install_info
) {
3964 r
= bus_iter_get_basic_and_next(&iter
, DBUS_TYPE_BOOLEAN
, &b
, true);
3966 log_error("Failed to parse reply.");
3970 carries_install_info
= b
;
3973 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
3974 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
3975 log_error("Failed to parse reply.");
3980 dbus_message_iter_recurse(&iter
, &sub
);
3981 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
3982 const char *type
, *path
, *source
;
3984 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
3985 log_error("Failed to parse reply.");
3990 dbus_message_iter_recurse(&sub
, &sub2
);
3992 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) < 0 ||
3993 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &path
, true) < 0 ||
3994 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &source
, false) < 0) {
3995 log_error("Failed to parse reply.");
4001 if (streq(type
, "symlink"))
4002 log_info("ln -s '%s' '%s'", source
, path
);
4004 log_info("rm '%s'", path
);
4007 dbus_message_iter_next(&sub
);
4010 /* Try to reload if enabeld */
4012 r
= daemon_reload(bus
, args
);
4015 if (carries_install_info
== 0)
4016 log_warning("Warning: unit files do not carry install information. No operation executed.");
4020 dbus_message_unref(m
);
4023 dbus_message_unref(reply
);
4025 unit_file_changes_free(changes
, n_changes
);
4027 dbus_error_free(&error
);
4031 static int unit_is_enabled(DBusConnection
*bus
, char **args
) {
4034 DBusMessage
*m
= NULL
, *reply
= NULL
;
4038 dbus_error_init(&error
);
4040 r
= enable_sysv_units(args
);
4046 if (!bus
|| avoid_bus()) {
4048 STRV_FOREACH(name
, args
+1) {
4049 UnitFileState state
;
4051 state
= unit_file_get_state(arg_scope
, arg_root
, *name
);
4057 if (state
== UNIT_FILE_ENABLED
||
4058 state
== UNIT_FILE_ENABLED_RUNTIME
||
4059 state
== UNIT_FILE_STATIC
)
4063 puts(unit_file_state_to_string(state
));
4067 STRV_FOREACH(name
, args
+1) {
4070 m
= dbus_message_new_method_call(
4071 "org.freedesktop.systemd1",
4072 "/org/freedesktop/systemd1",
4073 "org.freedesktop.systemd1.Manager",
4074 "GetUnitFileState");
4076 log_error("Out of memory");
4081 if (!dbus_message_append_args(m
,
4082 DBUS_TYPE_STRING
, name
,
4083 DBUS_TYPE_INVALID
)) {
4084 log_error("Could not append arguments to message.");
4089 reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
);
4091 log_error("Failed to issue method call: %s", bus_error_message(&error
));
4096 if (!dbus_message_get_args(reply
, &error
,
4097 DBUS_TYPE_STRING
, &s
,
4098 DBUS_TYPE_INVALID
)) {
4099 log_error("Failed to parse reply: %s", bus_error_message(&error
));
4104 dbus_message_unref(m
);
4105 dbus_message_unref(reply
);
4108 if (streq(s
, "enabled") ||
4109 streq(s
, "enabled-runtime") ||
4118 r
= enabled
? 0 : 1;
4122 dbus_message_unref(m
);
4125 dbus_message_unref(reply
);
4127 dbus_error_free(&error
);
4131 static int systemctl_help(void) {
4133 pager_open_if_enabled();
4135 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4136 "Query or send control commands to the systemd manager.\n\n"
4137 " -h --help Show this help\n"
4138 " --version Show package version\n"
4139 " -t --type=TYPE List only units of a particular type\n"
4140 " -p --property=NAME Show only properties by this name\n"
4141 " -a --all Show all units/properties, including dead/empty ones\n"
4142 " --failed Show only failed units\n"
4143 " --full Don't ellipsize unit names on output\n"
4144 " --fail When queueing a new job, fail if conflicting jobs are\n"
4146 " --ignore-dependencies\n"
4147 " When queueing a new job, ignore all its dependencies\n"
4148 " --kill-who=WHO Who to send signal to\n"
4149 " -s --signal=SIGNAL Which signal to send\n"
4150 " -H --host=[USER@]HOST\n"
4151 " Show information for remote host\n"
4152 " -P --privileged Acquire privileges before execution\n"
4153 " -q --quiet Suppress output\n"
4154 " --no-block Do not wait until operation finished\n"
4155 " --no-wall Don't send wall message before halt/power-off/reboot\n"
4156 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4158 " --no-legend Do not print a legend (column headers and hints)\n"
4159 " --no-pager Do not pipe output into a pager\n"
4160 " --no-ask-password\n"
4161 " Do not ask for system passwords\n"
4162 " --order When generating graph for dot, show only order\n"
4163 " --require When generating graph for dot, show only requirement\n"
4164 " --system Connect to system manager\n"
4165 " --user Connect to user service manager\n"
4166 " --global Enable/disable unit files globally\n"
4167 " -f --force When enabling unit files, override existing symlinks\n"
4168 " When shutting down, execute action immediately\n"
4169 " --root=PATH Enable unit files in the specified root directory\n"
4170 " --runtime Enable unit files only temporarily until next reboot\n"
4171 " -n --lines=INTEGER Journal entries to show\n"
4172 " --follow Follow journal\n"
4173 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
4174 " verbose, export, json, cat)\n\n"
4176 " list-units List loaded units\n"
4177 " start [NAME...] Start (activate) one or more units\n"
4178 " stop [NAME...] Stop (deactivate) one or more units\n"
4179 " reload [NAME...] Reload one or more units\n"
4180 " restart [NAME...] Start or restart one or more units\n"
4181 " try-restart [NAME...] Restart one or more units if active\n"
4182 " reload-or-restart [NAME...] Reload one or more units is possible,\n"
4183 " otherwise start or restart\n"
4184 " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4185 " otherwise restart if active\n"
4186 " isolate [NAME] Start one unit and stop all others\n"
4187 " kill [NAME...] Send signal to processes of a unit\n"
4188 " is-active [NAME...] Check whether units are active\n"
4189 " status [NAME...|PID...] Show runtime status of one or more units\n"
4190 " show [NAME...|JOB...] Show properties of one or more\n"
4191 " units/jobs or the manager\n"
4192 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4194 " load [NAME...] Load one or more units\n\n"
4195 "Unit File Commands:\n"
4196 " list-unit-files List installed unit files\n"
4197 " enable [NAME...] Enable one or more unit files\n"
4198 " disable [NAME...] Disable one or more unit files\n"
4199 " reenable [NAME...] Reenable one or more unit files\n"
4200 " preset [NAME...] Enable/disable one or more unit files\n"
4201 " based on preset configuration\n"
4202 " mask [NAME...] Mask one or more units\n"
4203 " unmask [NAME...] Unmask one or more units\n"
4204 " link [PATH...] Link one or more units files into\n"
4205 " the search path\n"
4206 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
4208 " list-jobs List jobs\n"
4209 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
4210 "Status Commands:\n"
4211 " dump Dump server status\n"
4212 " dot Dump dependency graph for dot(1)\n\n"
4213 "Snapshot Commands:\n"
4214 " snapshot [NAME] Create a snapshot\n"
4215 " delete [NAME...] Remove one or more snapshots\n\n"
4216 "Environment Commands:\n"
4217 " show-environment Dump environment\n"
4218 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
4219 " unset-environment [NAME...] Unset one or more environment variables\n\n"
4220 "Manager Lifecycle Commands:\n"
4221 " daemon-reload Reload systemd manager configuration\n"
4222 " daemon-reexec Reexecute systemd manager\n\n"
4223 "System Commands:\n"
4224 " default Enter system default mode\n"
4225 " rescue Enter system rescue mode\n"
4226 " emergency Enter system emergency mode\n"
4227 " halt Shut down and halt the system\n"
4228 " poweroff Shut down and power-off the system\n"
4229 " reboot Shut down and reboot the system\n"
4230 " kexec Shut down and reboot the system with kexec\n"
4231 " exit Request user instance exit\n"
4232 " switch-root [ROOT] [INIT] Change to a different root file system\n"
4233 " suspend Suspend the system\n"
4234 " hibernate Hibernate the system\n",
4235 program_invocation_short_name
);
4240 static int halt_help(void) {
4242 printf("%s [OPTIONS...]\n\n"
4243 "%s the system.\n\n"
4244 " --help Show this help\n"
4245 " --halt Halt the machine\n"
4246 " -p --poweroff Switch off the machine\n"
4247 " --reboot Reboot the machine\n"
4248 " -f --force Force immediate halt/power-off/reboot\n"
4249 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4250 " -d --no-wtmp Don't write wtmp record\n"
4251 " -n --no-sync Don't sync before halt/power-off/reboot\n"
4252 " --no-wall Don't send wall message before halt/power-off/reboot\n",
4253 program_invocation_short_name
,
4254 arg_action
== ACTION_REBOOT
? "Reboot" :
4255 arg_action
== ACTION_POWEROFF
? "Power off" :
4261 static int shutdown_help(void) {
4263 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4264 "Shut down the system.\n\n"
4265 " --help Show this help\n"
4266 " -H --halt Halt the machine\n"
4267 " -P --poweroff Power-off the machine\n"
4268 " -r --reboot Reboot the machine\n"
4269 " -h Equivalent to --poweroff, overriden by --halt\n"
4270 " -k Don't halt/power-off/reboot, just send warnings\n"
4271 " --no-wall Don't send wall message before halt/power-off/reboot\n"
4272 " -c Cancel a pending shutdown\n",
4273 program_invocation_short_name
);
4278 static int telinit_help(void) {
4280 printf("%s [OPTIONS...] {COMMAND}\n\n"
4281 "Send control commands to the init daemon.\n\n"
4282 " --help Show this help\n"
4283 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
4285 " 0 Power-off the machine\n"
4286 " 6 Reboot the machine\n"
4287 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4288 " 1, s, S Enter rescue mode\n"
4289 " q, Q Reload init daemon configuration\n"
4290 " u, U Reexecute init daemon\n",
4291 program_invocation_short_name
);
4296 static int runlevel_help(void) {
4298 printf("%s [OPTIONS...]\n\n"
4299 "Prints the previous and current runlevel of the init system.\n\n"
4300 " --help Show this help\n",
4301 program_invocation_short_name
);
4306 static int systemctl_parse_argv(int argc
, char *argv
[]) {
4310 ARG_IGNORE_DEPENDENCIES
,
4326 ARG_NO_ASK_PASSWORD
,
4333 static const struct option options
[] = {
4334 { "help", no_argument
, NULL
, 'h' },
4335 { "version", no_argument
, NULL
, ARG_VERSION
},
4336 { "type", required_argument
, NULL
, 't' },
4337 { "property", required_argument
, NULL
, 'p' },
4338 { "all", no_argument
, NULL
, 'a' },
4339 { "failed", no_argument
, NULL
, ARG_FAILED
},
4340 { "full", no_argument
, NULL
, ARG_FULL
},
4341 { "fail", no_argument
, NULL
, ARG_FAIL
},
4342 { "ignore-dependencies", no_argument
, NULL
, ARG_IGNORE_DEPENDENCIES
},
4343 { "user", no_argument
, NULL
, ARG_USER
},
4344 { "system", no_argument
, NULL
, ARG_SYSTEM
},
4345 { "global", no_argument
, NULL
, ARG_GLOBAL
},
4346 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
4347 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
4348 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
4349 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4350 { "quiet", no_argument
, NULL
, 'q' },
4351 { "order", no_argument
, NULL
, ARG_ORDER
},
4352 { "require", no_argument
, NULL
, ARG_REQUIRE
},
4353 { "root", required_argument
, NULL
, ARG_ROOT
},
4354 { "force", no_argument
, NULL
, ARG_FORCE
},
4355 { "no-reload", no_argument
, NULL
, ARG_NO_RELOAD
},
4356 { "kill-mode", required_argument
, NULL
, ARG_KILL_MODE
}, /* undocumented on purpose */
4357 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
4358 { "signal", required_argument
, NULL
, 's' },
4359 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
4360 { "host", required_argument
, NULL
, 'H' },
4361 { "privileged",no_argument
, NULL
, 'P' },
4362 { "runtime", no_argument
, NULL
, ARG_RUNTIME
},
4363 { "lines", required_argument
, NULL
, 'n' },
4364 { "follow", no_argument
, NULL
, ARG_FOLLOW
},
4365 { "output", required_argument
, NULL
, 'o' },
4366 { NULL
, 0, NULL
, 0 }
4374 while ((c
= getopt_long(argc
, argv
, "ht:p:aqfs:H:Pn:o:", options
, NULL
)) >= 0) {
4383 puts(PACKAGE_STRING
);
4385 puts(SYSTEMD_FEATURES
);
4395 if (!(l
= strv_append(arg_property
, optarg
)))
4398 strv_free(arg_property
);
4401 /* If the user asked for a particular
4402 * property, show it to him, even if it is
4413 arg_job_mode
= "fail";
4416 case ARG_IGNORE_DEPENDENCIES
:
4417 arg_job_mode
= "ignore-dependencies";
4421 arg_scope
= UNIT_FILE_USER
;
4425 arg_scope
= UNIT_FILE_SYSTEM
;
4429 arg_scope
= UNIT_FILE_GLOBAL
;
4433 arg_no_block
= true;
4437 arg_no_legend
= true;
4441 arg_no_pager
= true;
4449 arg_dot
= DOT_ORDER
;
4453 arg_dot
= DOT_REQUIRE
;
4481 /* -f is short for both --follow and --force! */
4487 arg_no_reload
= true;
4491 arg_kill_who
= optarg
;
4495 arg_kill_mode
= optarg
;
4499 if ((arg_signal
= signal_from_string_try_harder(optarg
)) < 0) {
4500 log_error("Failed to parse signal string %s.", optarg
);
4505 case ARG_NO_ASK_PASSWORD
:
4506 arg_ask_password
= false;
4510 arg_transport
= TRANSPORT_POLKIT
;
4514 arg_transport
= TRANSPORT_SSH
;
4523 if (safe_atou(optarg
, &arg_lines
) < 0) {
4524 log_error("Failed to parse lines '%s'", optarg
);
4530 arg_output
= output_mode_from_string(optarg
);
4531 if (arg_output
< 0) {
4532 log_error("Unknown output '%s'.", optarg
);
4541 log_error("Unknown option code %c", c
);
4546 if (arg_transport
!= TRANSPORT_NORMAL
&& arg_scope
!= UNIT_FILE_SYSTEM
) {
4547 log_error("Cannot access user instance remotely.");
4554 static int halt_parse_argv(int argc
, char *argv
[]) {
4563 static const struct option options
[] = {
4564 { "help", no_argument
, NULL
, ARG_HELP
},
4565 { "halt", no_argument
, NULL
, ARG_HALT
},
4566 { "poweroff", no_argument
, NULL
, 'p' },
4567 { "reboot", no_argument
, NULL
, ARG_REBOOT
},
4568 { "force", no_argument
, NULL
, 'f' },
4569 { "wtmp-only", no_argument
, NULL
, 'w' },
4570 { "no-wtmp", no_argument
, NULL
, 'd' },
4571 { "no-sync", no_argument
, NULL
, 'n' },
4572 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4573 { NULL
, 0, NULL
, 0 }
4581 if (utmp_get_runlevel(&runlevel
, NULL
) >= 0)
4582 if (runlevel
== '0' || runlevel
== '6')
4585 while ((c
= getopt_long(argc
, argv
, "pfwdnih", options
, NULL
)) >= 0) {
4593 arg_action
= ACTION_HALT
;
4597 if (arg_action
!= ACTION_REBOOT
)
4598 arg_action
= ACTION_POWEROFF
;
4602 arg_action
= ACTION_REBOOT
;
4627 /* Compatibility nops */
4634 log_error("Unknown option code %c", c
);
4639 if (optind
< argc
) {
4640 log_error("Too many arguments.");
4647 static int parse_time_spec(const char *t
, usec_t
*_u
) {
4651 if (streq(t
, "now"))
4653 else if (!strchr(t
, ':')) {
4656 if (safe_atou64(t
, &u
) < 0)
4659 *_u
= now(CLOCK_REALTIME
) + USEC_PER_MINUTE
* u
;
4668 hour
= strtol(t
, &e
, 10);
4669 if (errno
!= 0 || *e
!= ':' || hour
< 0 || hour
> 23)
4672 minute
= strtol(e
+1, &e
, 10);
4673 if (errno
!= 0 || *e
!= 0 || minute
< 0 || minute
> 59)
4676 n
= now(CLOCK_REALTIME
);
4677 s
= (time_t) (n
/ USEC_PER_SEC
);
4680 assert_se(localtime_r(&s
, &tm
));
4682 tm
.tm_hour
= (int) hour
;
4683 tm
.tm_min
= (int) minute
;
4686 assert_se(s
= mktime(&tm
));
4688 *_u
= (usec_t
) s
* USEC_PER_SEC
;
4691 *_u
+= USEC_PER_DAY
;
4697 static int shutdown_parse_argv(int argc
, char *argv
[]) {
4704 static const struct option options
[] = {
4705 { "help", no_argument
, NULL
, ARG_HELP
},
4706 { "halt", no_argument
, NULL
, 'H' },
4707 { "poweroff", no_argument
, NULL
, 'P' },
4708 { "reboot", no_argument
, NULL
, 'r' },
4709 { "kexec", no_argument
, NULL
, 'K' }, /* not documented extension */
4710 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4711 { NULL
, 0, NULL
, 0 }
4719 while ((c
= getopt_long(argc
, argv
, "HPrhkt:afFc", options
, NULL
)) >= 0) {
4727 arg_action
= ACTION_HALT
;
4731 arg_action
= ACTION_POWEROFF
;
4736 arg_action
= ACTION_KEXEC
;
4738 arg_action
= ACTION_REBOOT
;
4742 arg_action
= ACTION_KEXEC
;
4746 if (arg_action
!= ACTION_HALT
)
4747 arg_action
= ACTION_POWEROFF
;
4760 /* Compatibility nops */
4764 arg_action
= ACTION_CANCEL_SHUTDOWN
;
4771 log_error("Unknown option code %c", c
);
4776 if (argc
> optind
) {
4777 r
= parse_time_spec(argv
[optind
], &arg_when
);
4779 log_error("Failed to parse time specification: %s", argv
[optind
]);
4783 arg_when
= now(CLOCK_REALTIME
) + USEC_PER_MINUTE
;
4785 /* We skip the time argument */
4786 if (argc
> optind
+ 1)
4787 arg_wall
= argv
+ optind
+ 1;
4794 static int telinit_parse_argv(int argc
, char *argv
[]) {
4801 static const struct option options
[] = {
4802 { "help", no_argument
, NULL
, ARG_HELP
},
4803 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
4804 { NULL
, 0, NULL
, 0 }
4807 static const struct {
4811 { '0', ACTION_POWEROFF
},
4812 { '6', ACTION_REBOOT
},
4813 { '1', ACTION_RESCUE
},
4814 { '2', ACTION_RUNLEVEL2
},
4815 { '3', ACTION_RUNLEVEL3
},
4816 { '4', ACTION_RUNLEVEL4
},
4817 { '5', ACTION_RUNLEVEL5
},
4818 { 's', ACTION_RESCUE
},
4819 { 'S', ACTION_RESCUE
},
4820 { 'q', ACTION_RELOAD
},
4821 { 'Q', ACTION_RELOAD
},
4822 { 'u', ACTION_REEXEC
},
4823 { 'U', ACTION_REEXEC
}
4832 while ((c
= getopt_long(argc
, argv
, "", options
, NULL
)) >= 0) {
4847 log_error("Unknown option code %c", c
);
4852 if (optind
>= argc
) {
4857 if (optind
+ 1 < argc
) {
4858 log_error("Too many arguments.");
4862 if (strlen(argv
[optind
]) != 1) {
4863 log_error("Expected single character argument.");
4867 for (i
= 0; i
< ELEMENTSOF(table
); i
++)
4868 if (table
[i
].from
== argv
[optind
][0])
4871 if (i
>= ELEMENTSOF(table
)) {
4872 log_error("Unknown command %s.", argv
[optind
]);
4876 arg_action
= table
[i
].to
;
4883 static int runlevel_parse_argv(int argc
, char *argv
[]) {
4889 static const struct option options
[] = {
4890 { "help", no_argument
, NULL
, ARG_HELP
},
4891 { NULL
, 0, NULL
, 0 }
4899 while ((c
= getopt_long(argc
, argv
, "", options
, NULL
)) >= 0) {
4910 log_error("Unknown option code %c", c
);
4915 if (optind
< argc
) {
4916 log_error("Too many arguments.");
4923 static int parse_argv(int argc
, char *argv
[]) {
4927 if (program_invocation_short_name
) {
4929 if (strstr(program_invocation_short_name
, "halt")) {
4930 arg_action
= ACTION_HALT
;
4931 return halt_parse_argv(argc
, argv
);
4932 } else if (strstr(program_invocation_short_name
, "poweroff")) {
4933 arg_action
= ACTION_POWEROFF
;
4934 return halt_parse_argv(argc
, argv
);
4935 } else if (strstr(program_invocation_short_name
, "reboot")) {
4937 arg_action
= ACTION_KEXEC
;
4939 arg_action
= ACTION_REBOOT
;
4940 return halt_parse_argv(argc
, argv
);
4941 } else if (strstr(program_invocation_short_name
, "shutdown")) {
4942 arg_action
= ACTION_POWEROFF
;
4943 return shutdown_parse_argv(argc
, argv
);
4944 } else if (strstr(program_invocation_short_name
, "init")) {
4946 if (sd_booted() > 0) {
4947 arg_action
= ACTION_INVALID
;
4948 return telinit_parse_argv(argc
, argv
);
4950 /* Hmm, so some other init system is
4951 * running, we need to forward this
4952 * request to it. For now we simply
4953 * guess that it is Upstart. */
4955 execv("/lib/upstart/telinit", argv
);
4957 log_error("Couldn't find an alternative telinit implementation to spawn.");
4961 } else if (strstr(program_invocation_short_name
, "runlevel")) {
4962 arg_action
= ACTION_RUNLEVEL
;
4963 return runlevel_parse_argv(argc
, argv
);
4967 arg_action
= ACTION_SYSTEMCTL
;
4968 return systemctl_parse_argv(argc
, argv
);
4971 static int action_to_runlevel(void) {
4973 static const char table
[_ACTION_MAX
] = {
4974 [ACTION_HALT
] = '0',
4975 [ACTION_POWEROFF
] = '0',
4976 [ACTION_REBOOT
] = '6',
4977 [ACTION_RUNLEVEL2
] = '2',
4978 [ACTION_RUNLEVEL3
] = '3',
4979 [ACTION_RUNLEVEL4
] = '4',
4980 [ACTION_RUNLEVEL5
] = '5',
4981 [ACTION_RESCUE
] = '1'
4984 assert(arg_action
< _ACTION_MAX
);
4986 return table
[arg_action
];
4989 static int talk_upstart(void) {
4990 DBusMessage
*m
= NULL
, *reply
= NULL
;
4992 int previous
, rl
, r
;
4994 env1_buf
[] = "RUNLEVEL=X",
4995 env2_buf
[] = "PREVLEVEL=X";
4996 char *env1
= env1_buf
, *env2
= env2_buf
;
4997 const char *emit
= "runlevel";
4998 dbus_bool_t b_false
= FALSE
;
4999 DBusMessageIter iter
, sub
;
5000 DBusConnection
*bus
;
5002 dbus_error_init(&error
);
5004 if (!(rl
= action_to_runlevel()))
5007 if (utmp_get_runlevel(&previous
, NULL
) < 0)
5010 if (!(bus
= dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error
))) {
5011 if (dbus_error_has_name(&error
, DBUS_ERROR_NO_SERVER
)) {
5016 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error
));
5021 if ((r
= bus_check_peercred(bus
)) < 0) {
5022 log_error("Failed to verify owner of bus.");
5026 if (!(m
= dbus_message_new_method_call(
5027 "com.ubuntu.Upstart",
5028 "/com/ubuntu/Upstart",
5029 "com.ubuntu.Upstart0_6",
5032 log_error("Could not allocate message.");
5037 dbus_message_iter_init_append(m
, &iter
);
5039 env1_buf
[sizeof(env1_buf
)-2] = rl
;
5040 env2_buf
[sizeof(env2_buf
)-2] = previous
;
5042 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_STRING
, &emit
) ||
5043 !dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "s", &sub
) ||
5044 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &env1
) ||
5045 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &env2
) ||
5046 !dbus_message_iter_close_container(&iter
, &sub
) ||
5047 !dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &b_false
)) {
5048 log_error("Could not append arguments to message.");
5053 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
5055 if (error_is_no_service(&error
)) {
5060 log_error("Failed to issue method call: %s", bus_error_message(&error
));
5069 dbus_message_unref(m
);
5072 dbus_message_unref(reply
);
5075 dbus_connection_flush(bus
);
5076 dbus_connection_close(bus
);
5077 dbus_connection_unref(bus
);
5080 dbus_error_free(&error
);
5085 static int talk_initctl(void) {
5086 struct init_request request
;
5090 if (!(rl
= action_to_runlevel()))
5094 request
.magic
= INIT_MAGIC
;
5095 request
.sleeptime
= 0;
5096 request
.cmd
= INIT_CMD_RUNLVL
;
5097 request
.runlevel
= rl
;
5099 if ((fd
= open(INIT_FIFO
, O_WRONLY
|O_NDELAY
|O_CLOEXEC
|O_NOCTTY
)) < 0) {
5101 if (errno
== ENOENT
)
5104 log_error("Failed to open "INIT_FIFO
": %m");
5109 r
= loop_write(fd
, &request
, sizeof(request
), false) != sizeof(request
);
5110 close_nointr_nofail(fd
);
5113 log_error("Failed to write to "INIT_FIFO
": %m");
5114 return errno
? -errno
: -EIO
;
5120 static int systemctl_main(DBusConnection
*bus
, int argc
, char *argv
[], DBusError
*error
) {
5122 static const struct {
5130 int (* const dispatch
)(DBusConnection
*bus
, char **args
);
5132 { "list-units", LESS
, 1, list_units
},
5133 { "list-unit-files", EQUAL
, 1, list_unit_files
},
5134 { "list-jobs", EQUAL
, 1, list_jobs
},
5135 { "clear-jobs", EQUAL
, 1, daemon_reload
},
5136 { "load", MORE
, 2, load_unit
},
5137 { "cancel", MORE
, 2, cancel_job
},
5138 { "start", MORE
, 2, start_unit
},
5139 { "stop", MORE
, 2, start_unit
},
5140 { "condstop", MORE
, 2, start_unit
}, /* For compatibility with ALTLinux */
5141 { "reload", MORE
, 2, start_unit
},
5142 { "restart", MORE
, 2, start_unit
},
5143 { "try-restart", MORE
, 2, start_unit
},
5144 { "reload-or-restart", MORE
, 2, start_unit
},
5145 { "reload-or-try-restart", MORE
, 2, start_unit
},
5146 { "force-reload", MORE
, 2, start_unit
}, /* For compatibility with SysV */
5147 { "condreload", MORE
, 2, start_unit
}, /* For compatibility with ALTLinux */
5148 { "condrestart", MORE
, 2, start_unit
}, /* For compatibility with RH */
5149 { "isolate", EQUAL
, 2, start_unit
},
5150 { "kill", MORE
, 2, kill_unit
},
5151 { "is-active", MORE
, 2, check_unit
},
5152 { "check", MORE
, 2, check_unit
},
5153 { "show", MORE
, 1, show
},
5154 { "status", MORE
, 2, show
},
5155 { "dump", EQUAL
, 1, dump
},
5156 { "dot", EQUAL
, 1, dot
},
5157 { "snapshot", LESS
, 2, snapshot
},
5158 { "delete", MORE
, 2, delete_snapshot
},
5159 { "daemon-reload", EQUAL
, 1, daemon_reload
},
5160 { "daemon-reexec", EQUAL
, 1, daemon_reload
},
5161 { "show-environment", EQUAL
, 1, show_enviroment
},
5162 { "set-environment", MORE
, 2, set_environment
},
5163 { "unset-environment", MORE
, 2, set_environment
},
5164 { "halt", EQUAL
, 1, start_special
},
5165 { "poweroff", EQUAL
, 1, start_special
},
5166 { "reboot", EQUAL
, 1, start_special
},
5167 { "kexec", EQUAL
, 1, start_special
},
5168 { "suspend", EQUAL
, 1, start_special
},
5169 { "hibernate", EQUAL
, 1, start_special
},
5170 { "default", EQUAL
, 1, start_special
},
5171 { "rescue", EQUAL
, 1, start_special
},
5172 { "emergency", EQUAL
, 1, start_special
},
5173 { "exit", EQUAL
, 1, start_special
},
5174 { "reset-failed", MORE
, 1, reset_failed
},
5175 { "enable", MORE
, 2, enable_unit
},
5176 { "disable", MORE
, 2, enable_unit
},
5177 { "is-enabled", MORE
, 2, unit_is_enabled
},
5178 { "reenable", MORE
, 2, enable_unit
},
5179 { "preset", MORE
, 2, enable_unit
},
5180 { "mask", MORE
, 2, enable_unit
},
5181 { "unmask", MORE
, 2, enable_unit
},
5182 { "link", MORE
, 2, enable_unit
},
5183 { "switch-root", MORE
, 2, switch_root
},
5193 left
= argc
- optind
;
5196 /* Special rule: no arguments means "list-units" */
5199 if (streq(argv
[optind
], "help")) {
5204 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
5205 if (streq(argv
[optind
], verbs
[i
].verb
))
5208 if (i
>= ELEMENTSOF(verbs
)) {
5209 log_error("Unknown operation %s", argv
[optind
]);
5214 switch (verbs
[i
].argc_cmp
) {
5217 if (left
!= verbs
[i
].argc
) {
5218 log_error("Invalid number of arguments.");
5225 if (left
< verbs
[i
].argc
) {
5226 log_error("Too few arguments.");
5233 if (left
> verbs
[i
].argc
) {
5234 log_error("Too many arguments.");
5241 assert_not_reached("Unknown comparison operator.");
5244 /* Require a bus connection for all operations but
5246 if (!streq(verbs
[i
].verb
, "enable") &&
5247 !streq(verbs
[i
].verb
, "disable") &&
5248 !streq(verbs
[i
].verb
, "is-enabled") &&
5249 !streq(verbs
[i
].verb
, "list-unit-files") &&
5250 !streq(verbs
[i
].verb
, "reenable") &&
5251 !streq(verbs
[i
].verb
, "preset") &&
5252 !streq(verbs
[i
].verb
, "mask") &&
5253 !streq(verbs
[i
].verb
, "unmask") &&
5254 !streq(verbs
[i
].verb
, "link")) {
5256 if (running_in_chroot() > 0) {
5257 log_info("Running in chroot, ignoring request.");
5261 if (((!streq(verbs
[i
].verb
, "reboot") &&
5262 !streq(verbs
[i
].verb
, "halt") &&
5263 !streq(verbs
[i
].verb
, "poweroff")) || arg_force
<= 0) && !bus
) {
5264 log_error("Failed to get D-Bus connection: %s",
5265 dbus_error_is_set(error
) ? error
->message
: "No connection to service manager.");
5271 if (!bus
&& !avoid_bus()) {
5272 log_error("Failed to get D-Bus connection: %s",
5273 dbus_error_is_set(error
) ? error
->message
: "No connection to service manager.");
5278 return verbs
[i
].dispatch(bus
, argv
+ optind
);
5281 static int send_shutdownd(usec_t t
, char mode
, bool dry_run
, bool warn
, const char *message
) {
5283 struct msghdr msghdr
;
5284 struct iovec iovec
[2];
5285 union sockaddr_union sockaddr
;
5286 struct sd_shutdown_command c
;
5288 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
5295 c
.dry_run
= dry_run
;
5299 sockaddr
.sa
.sa_family
= AF_UNIX
;
5300 strncpy(sockaddr
.un
.sun_path
, "/run/systemd/shutdownd", sizeof(sockaddr
.un
.sun_path
));
5303 msghdr
.msg_name
= &sockaddr
;
5304 msghdr
.msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + sizeof("/run/systemd/shutdownd") - 1;
5307 iovec
[0].iov_base
= (char*) &c
;
5308 iovec
[0].iov_len
= offsetof(struct sd_shutdown_command
, wall_message
);
5310 if (isempty(message
))
5311 msghdr
.msg_iovlen
= 1;
5313 iovec
[1].iov_base
= (char*) message
;
5314 iovec
[1].iov_len
= strlen(message
);
5315 msghdr
.msg_iovlen
= 2;
5317 msghdr
.msg_iov
= iovec
;
5319 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) < 0) {
5320 close_nointr_nofail(fd
);
5324 close_nointr_nofail(fd
);
5328 static int reload_with_fallback(DBusConnection
*bus
) {
5331 /* First, try systemd via D-Bus. */
5332 if (daemon_reload(bus
, NULL
) >= 0)
5336 /* Nothing else worked, so let's try signals */
5337 assert(arg_action
== ACTION_RELOAD
|| arg_action
== ACTION_REEXEC
);
5339 if (kill(1, arg_action
== ACTION_RELOAD
? SIGHUP
: SIGTERM
) < 0) {
5340 log_error("kill() failed: %m");
5347 static int start_with_fallback(DBusConnection
*bus
) {
5350 /* First, try systemd via D-Bus. */
5351 if (start_unit(bus
, NULL
) >= 0)
5355 /* Hmm, talking to systemd via D-Bus didn't work. Then
5356 * let's try to talk to Upstart via D-Bus. */
5357 if (talk_upstart() > 0)
5360 /* Nothing else worked, so let's try
5362 if (talk_initctl() > 0)
5365 log_error("Failed to talk to init daemon.");
5369 warn_wall(arg_action
);
5373 static void halt_now(enum action a
) {
5375 /* Make sure C-A-D is handled by the kernel from this
5377 reboot(RB_ENABLE_CAD
);
5382 log_info("Halting.");
5383 reboot(RB_HALT_SYSTEM
);
5386 case ACTION_POWEROFF
:
5387 log_info("Powering off.");
5388 reboot(RB_POWER_OFF
);
5392 log_info("Rebooting.");
5393 reboot(RB_AUTOBOOT
);
5397 assert_not_reached("Unknown halt action.");
5400 assert_not_reached("Uh? This shouldn't happen.");
5403 static int halt_main(DBusConnection
*bus
) {
5406 if (geteuid() != 0) {
5407 /* Try logind if we are a normal user and no special
5408 * mode applies. Maybe PolicyKit allows us to shutdown
5411 if (arg_when
<= 0 &&
5414 (arg_action
== ACTION_POWEROFF
||
5415 arg_action
== ACTION_REBOOT
)) {
5416 r
= reboot_with_logind(bus
, arg_action
);
5421 log_error("Must be root.");
5428 m
= strv_join(arg_wall
, " ");
5429 r
= send_shutdownd(arg_when
,
5430 arg_action
== ACTION_HALT
? 'H' :
5431 arg_action
== ACTION_POWEROFF
? 'P' :
5432 arg_action
== ACTION_KEXEC
? 'K' :
5440 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r
));
5442 char date
[FORMAT_TIMESTAMP_MAX
];
5444 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5445 format_timestamp(date
, sizeof(date
), arg_when
));
5450 if (!arg_dry
&& !arg_force
)
5451 return start_with_fallback(bus
);
5454 if (sd_booted() > 0)
5455 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5457 r
= utmp_put_shutdown();
5459 log_warning("Failed to write utmp record: %s", strerror(-r
));
5469 halt_now(arg_action
);
5470 /* We should never reach this. */
5474 static int runlevel_main(void) {
5475 int r
, runlevel
, previous
;
5477 r
= utmp_get_runlevel(&runlevel
, &previous
);
5484 previous
<= 0 ? 'N' : previous
,
5485 runlevel
<= 0 ? 'N' : runlevel
);
5490 int main(int argc
, char*argv
[]) {
5491 int r
, retval
= EXIT_FAILURE
;
5492 DBusConnection
*bus
= NULL
;
5495 dbus_error_init(&error
);
5497 log_parse_environment();
5500 r
= parse_argv(argc
, argv
);
5504 retval
= EXIT_SUCCESS
;
5508 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5509 * let's shortcut this */
5510 if (arg_action
== ACTION_RUNLEVEL
) {
5511 r
= runlevel_main();
5512 retval
= r
< 0 ? EXIT_FAILURE
: r
;
5516 if (running_in_chroot() > 0 && arg_action
!= ACTION_SYSTEMCTL
) {
5517 log_info("Running in chroot, ignoring request.");
5523 if (arg_transport
== TRANSPORT_NORMAL
)
5524 bus_connect(arg_scope
== UNIT_FILE_SYSTEM
? DBUS_BUS_SYSTEM
: DBUS_BUS_SESSION
, &bus
, &private_bus
, &error
);
5525 else if (arg_transport
== TRANSPORT_POLKIT
) {
5526 bus_connect_system_polkit(&bus
, &error
);
5527 private_bus
= false;
5528 } else if (arg_transport
== TRANSPORT_SSH
) {
5529 bus_connect_system_ssh(NULL
, arg_host
, &bus
, &error
);
5530 private_bus
= false;
5532 assert_not_reached("Uh, invalid transport...");
5535 switch (arg_action
) {
5537 case ACTION_SYSTEMCTL
:
5538 r
= systemctl_main(bus
, argc
, argv
, &error
);
5542 case ACTION_POWEROFF
:
5548 case ACTION_RUNLEVEL2
:
5549 case ACTION_RUNLEVEL3
:
5550 case ACTION_RUNLEVEL4
:
5551 case ACTION_RUNLEVEL5
:
5553 case ACTION_EMERGENCY
:
5554 case ACTION_DEFAULT
:
5555 r
= start_with_fallback(bus
);
5560 r
= reload_with_fallback(bus
);
5563 case ACTION_CANCEL_SHUTDOWN
:
5564 r
= send_shutdownd(0, 0, false, false, NULL
);
5567 case ACTION_INVALID
:
5568 case ACTION_RUNLEVEL
:
5570 assert_not_reached("Unknown action");
5573 retval
= r
< 0 ? EXIT_FAILURE
: r
;
5577 dbus_connection_flush(bus
);
5578 dbus_connection_close(bus
);
5579 dbus_connection_unref(bus
);
5582 dbus_error_free(&error
);
5586 strv_free(arg_property
);
5589 ask_password_agent_close();
5590 polkit_agent_close();