1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/reboot.h>
28 #include <sys/ioctl.h>
33 #include <dbus/dbus.h>
39 #include "utmp-wtmp.h"
44 static const char *arg_type
= NULL
;
45 static bool arg_all
= false;
46 static bool arg_replace
= false;
47 static bool arg_session
= false;
48 static bool arg_block
= false;
49 static bool arg_immediate
= false;
50 static bool arg_no_wtmp
= false;
51 static bool arg_no_sync
= false;
52 static bool arg_no_wall
= false;
53 static bool arg_dry
= false;
54 static char **arg_wall
= NULL
;
72 } arg_action
= ACTION_SYSTEMCTL
;
74 static bool error_is_no_service(DBusError
*error
) {
78 if (!dbus_error_is_set(error
))
81 if (dbus_error_has_name(error
, DBUS_ERROR_NAME_HAS_NO_OWNER
))
84 if (dbus_error_has_name(error
, DBUS_ERROR_SERVICE_UNKNOWN
))
87 return startswith(error
->name
, "org.freedesktop.DBus.Error.Spawn.");
90 static int bus_iter_get_basic_and_next(DBusMessageIter
*iter
, int type
, void *data
, bool next
) {
95 if (dbus_message_iter_get_arg_type(iter
) != type
)
98 dbus_message_iter_get_basic(iter
, data
);
100 if (!dbus_message_iter_next(iter
) != !next
)
106 static int columns(void) {
107 static int parsed_columns
= 0;
110 if (parsed_columns
> 0)
111 return parsed_columns
;
113 if ((e
= getenv("COLUMNS")))
114 parsed_columns
= atoi(e
);
116 if (parsed_columns
<= 0) {
120 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) >= 0)
121 parsed_columns
= ws
.ws_col
;
124 if (parsed_columns
<= 0)
127 return parsed_columns
;
131 static void warn_wall(enum action action
) {
132 static const char *table
[_ACTION_MAX
] = {
133 [ACTION_HALT
] = "The system is going down for system halt NOW!",
134 [ACTION_REBOOT
] = "The system is going down for reboot NOW!",
135 [ACTION_POWEROFF
] = "The system is going down for power-off NOW!",
136 [ACTION_RESCUE
] = "The system is going down to rescue mode NOW!",
137 [ACTION_EMERGENCY
] = "The system is going down to emergency mode NOW!"
146 if (!(p
= strv_join(arg_wall
, " "))) {
147 log_error("Failed to join strings.");
163 utmp_wall(table
[action
]);
166 static int list_units(DBusConnection
*bus
, char **args
, unsigned n
) {
167 DBusMessage
*m
= NULL
, *reply
= NULL
;
170 DBusMessageIter iter
, sub
, sub2
;
173 dbus_error_init(&error
);
177 if (!(m
= dbus_message_new_method_call(
178 "org.freedesktop.systemd1",
179 "/org/freedesktop/systemd1",
180 "org.freedesktop.systemd1.Manager",
182 log_error("Could not allocate message.");
186 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
187 log_error("Failed to issue method call: %s", error
.message
);
192 if (!dbus_message_iter_init(reply
, &iter
) ||
193 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
194 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
195 log_error("Failed to parse reply.");
200 dbus_message_iter_recurse(&iter
, &sub
);
202 printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
204 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
205 const char *id
, *description
, *load_state
, *active_state
, *sub_state
, *unit_state
, *job_type
, *job_path
, *dot
;
208 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
209 log_error("Failed to parse reply.");
214 dbus_message_iter_recurse(&sub
, &sub2
);
216 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &id
, true) < 0 ||
217 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &description
, true) < 0 ||
218 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &load_state
, true) < 0 ||
219 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &active_state
, true) < 0 ||
220 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &sub_state
, true) < 0 ||
221 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &unit_state
, true) < 0 ||
222 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &job_id
, true) < 0 ||
223 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &job_type
, true) < 0 ||
224 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &job_path
, false) < 0) {
225 log_error("Failed to parse reply.");
230 if ((!arg_type
|| ((dot
= strrchr(id
, '.')) &&
231 streq(dot
+1, arg_type
))) &&
232 (arg_all
|| !streq(active_state
, "inactive"))) {
236 printf("%-45s %-6s %-12s %-12s%n", id
, load_state
, active_state
, sub_state
, &a
);
239 printf(" %-15s%n", job_type
, &b
);
243 if (a
+ b
+ 2 < columns()) {
247 printf("%.*s", columns() - a
- b
- 2, description
);
254 dbus_message_iter_next(&sub
);
258 printf("\n%u units listed.\n", k
);
260 printf("\n%u live units listed. Pass --all to see dead units, too.\n", k
);
266 dbus_message_unref(m
);
269 dbus_message_unref(reply
);
271 dbus_error_free(&error
);
276 static int list_jobs(DBusConnection
*bus
, char **args
, unsigned n
) {
277 DBusMessage
*m
= NULL
, *reply
= NULL
;
280 DBusMessageIter iter
, sub
, sub2
;
283 dbus_error_init(&error
);
287 if (!(m
= dbus_message_new_method_call(
288 "org.freedesktop.systemd1",
289 "/org/freedesktop/systemd1",
290 "org.freedesktop.systemd1.Manager",
292 log_error("Could not allocate message.");
296 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
297 log_error("Failed to issue method call: %s", error
.message
);
302 if (!dbus_message_iter_init(reply
, &iter
) ||
303 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
304 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRUCT
) {
305 log_error("Failed to parse reply.");
310 dbus_message_iter_recurse(&iter
, &sub
);
312 printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
314 while (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_INVALID
) {
315 const char *name
, *type
, *state
, *job_path
, *unit_path
;
318 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRUCT
) {
319 log_error("Failed to parse reply.");
324 dbus_message_iter_recurse(&sub
, &sub2
);
326 if (bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_UINT32
, &id
, true) < 0 ||
327 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &name
, true) < 0 ||
328 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &type
, true) < 0 ||
329 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_STRING
, &state
, true) < 0 ||
330 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &job_path
, true) < 0 ||
331 bus_iter_get_basic_and_next(&sub2
, DBUS_TYPE_OBJECT_PATH
, &unit_path
, false) < 0) {
332 log_error("Failed to parse reply.");
337 printf("%4u %-45s %-17s %-7s\n", id
, name
, type
, state
);
340 dbus_message_iter_next(&sub
);
343 printf("\n%u jobs listed.\n", k
);
348 dbus_message_unref(m
);
351 dbus_message_unref(reply
);
353 dbus_error_free(&error
);
358 static int load_unit(DBusConnection
*bus
, char **args
, unsigned n
) {
359 DBusMessage
*m
= NULL
, *reply
= NULL
;
364 dbus_error_init(&error
);
369 for (i
= 1; i
< n
; i
++) {
371 if (!(m
= dbus_message_new_method_call(
372 "org.freedesktop.systemd1",
373 "/org/freedesktop/systemd1",
374 "org.freedesktop.systemd1.Manager",
376 log_error("Could not allocate message.");
381 if (!dbus_message_append_args(m
,
382 DBUS_TYPE_STRING
, &args
[i
],
383 DBUS_TYPE_INVALID
)) {
384 log_error("Could not append arguments to message.");
389 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
390 log_error("Failed to issue method call: %s", error
.message
);
395 dbus_message_unref(m
);
396 dbus_message_unref(reply
);
405 dbus_message_unref(m
);
408 dbus_message_unref(reply
);
410 dbus_error_free(&error
);
415 static int cancel_job(DBusConnection
*bus
, char **args
, unsigned n
) {
416 DBusMessage
*m
= NULL
, *reply
= NULL
;
421 dbus_error_init(&error
);
426 for (i
= 1; i
< n
; i
++) {
430 if (!(m
= dbus_message_new_method_call(
431 "org.freedesktop.systemd1",
432 "/org/freedesktop/systemd1",
433 "org.freedesktop.systemd1.Manager",
435 log_error("Could not allocate message.");
440 if ((r
= safe_atou(args
[i
], &id
)) < 0) {
441 log_error("Failed to parse job id: %s", strerror(-r
));
445 assert_cc(sizeof(uint32_t) == sizeof(id
));
446 if (!dbus_message_append_args(m
,
447 DBUS_TYPE_UINT32
, &id
,
448 DBUS_TYPE_INVALID
)) {
449 log_error("Could not append arguments to message.");
454 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
455 log_error("Failed to issue method call: %s", error
.message
);
460 if (!dbus_message_get_args(reply
, &error
,
461 DBUS_TYPE_OBJECT_PATH
, &path
,
462 DBUS_TYPE_INVALID
)) {
463 log_error("Failed to parse reply: %s", error
.message
);
468 dbus_message_unref(m
);
469 if (!(m
= dbus_message_new_method_call(
470 "org.freedesktop.systemd1",
472 "org.freedesktop.systemd1.Job",
474 log_error("Could not allocate message.");
479 dbus_message_unref(reply
);
480 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
481 log_error("Failed to issue method call: %s", error
.message
);
486 dbus_message_unref(m
);
487 dbus_message_unref(reply
);
495 dbus_message_unref(m
);
498 dbus_message_unref(reply
);
500 dbus_error_free(&error
);
505 static DBusHandlerResult
wait_filter(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
513 dbus_error_init(&error
);
515 /* log_debug("Got D-Bus request: %s.%s() on %s", */
516 /* dbus_message_get_interface(message), */
517 /* dbus_message_get_member(message), */
518 /* dbus_message_get_path(message)); */
520 if (dbus_message_is_signal(message
, DBUS_INTERFACE_LOCAL
, "Disconnected")) {
521 log_error("Warning! D-Bus connection terminated.");
522 dbus_connection_close(connection
);
524 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
528 if (!dbus_message_get_args(message
, &error
,
529 DBUS_TYPE_UINT32
, &id
,
530 DBUS_TYPE_OBJECT_PATH
, &path
,
532 log_error("Failed to parse message: %s", error
.message
);
536 if ((p
= set_remove(s
, (char*) path
)))
541 dbus_error_free(&error
);
542 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
545 static int enable_wait_for_jobs(DBusConnection
*bus
) {
547 DBusMessage
*m
= NULL
, *reply
= NULL
;
552 dbus_error_init(&error
);
554 dbus_bus_add_match(bus
,
556 "sender='org.freedesktop.systemd1',"
557 "interface='org.freedesktop.systemd1.Manager',"
558 "member='JobRemoved',"
559 "path='/org/freedesktop/systemd1'",
562 if (dbus_error_is_set(&error
)) {
563 log_error("Failed to add match: %s", error
.message
);
568 if (!(m
= dbus_message_new_method_call(
569 "org.freedesktop.systemd1",
570 "/org/freedesktop/systemd1",
571 "org.freedesktop.systemd1.Manager",
573 log_error("Could not allocate message.");
578 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
579 log_error("Failed to issue method call: %s", error
.message
);
587 /* This is slightly dirty, since we don't undo the match registrations. */
590 dbus_message_unref(m
);
593 dbus_message_unref(reply
);
595 dbus_error_free(&error
);
600 static int wait_for_jobs(DBusConnection
*bus
, Set
*s
) {
606 if (!dbus_connection_add_filter(bus
, wait_filter
, s
, NULL
)) {
607 log_error("Failed to add filter.");
612 while (!set_isempty(s
) &&
613 dbus_connection_read_write_dispatch(bus
, -1))
619 /* This is slightly dirty, since we don't undo the filter registration. */
624 static int start_unit_one(
631 DBusMessage
*m
= NULL
, *reply
= NULL
;
639 assert(!arg_block
|| s
);
641 dbus_error_init(&error
);
643 if (!(m
= dbus_message_new_method_call(
644 "org.freedesktop.systemd1",
645 "/org/freedesktop/systemd1",
646 "org.freedesktop.systemd1.Manager",
648 log_error("Could not allocate message.");
653 if (!dbus_message_append_args(m
,
654 DBUS_TYPE_STRING
, &name
,
655 DBUS_TYPE_STRING
, &mode
,
656 DBUS_TYPE_INVALID
)) {
657 log_error("Could not append arguments to message.");
662 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
664 if (arg_action
!= ACTION_SYSTEMCTL
&& error_is_no_service(&error
)) {
665 /* There's always a fallback possible for
671 log_error("Failed to issue method call: %s", error
.message
);
680 if (!dbus_message_get_args(reply
, &error
,
681 DBUS_TYPE_OBJECT_PATH
, &path
,
682 DBUS_TYPE_INVALID
)) {
683 log_error("Failed to parse reply: %s", error
.message
);
688 if (!(p
= strdup(path
))) {
689 log_error("Failed to duplicate path.");
694 if ((r
= set_put(s
, p
)) < 0) {
696 log_error("Failed to add path to set.");
705 dbus_message_unref(m
);
708 dbus_message_unref(reply
);
710 dbus_error_free(&error
);
715 static enum action
verb_to_action(const char *verb
) {
716 if (streq(verb
, "halt"))
718 else if (streq(verb
, "poweroff"))
719 return ACTION_POWEROFF
;
720 else if (streq(verb
, "reboot"))
721 return ACTION_REBOOT
;
722 else if (streq(verb
, "rescue"))
723 return ACTION_RESCUE
;
724 else if (streq(verb
, "emergency"))
725 return ACTION_EMERGENCY
;
726 else if (streq(verb
, "default"))
727 return ACTION_DEFAULT
;
729 return ACTION_INVALID
;
732 static int start_unit(DBusConnection
*bus
, char **args
, unsigned n
) {
734 static const char * const table
[_ACTION_MAX
] = {
735 [ACTION_HALT
] = SPECIAL_HALT_TARGET
,
736 [ACTION_POWEROFF
] = SPECIAL_POWEROFF_TARGET
,
737 [ACTION_REBOOT
] = SPECIAL_REBOOT_TARGET
,
738 [ACTION_RUNLEVEL2
] = SPECIAL_RUNLEVEL2_TARGET
,
739 [ACTION_RUNLEVEL3
] = SPECIAL_RUNLEVEL3_TARGET
,
740 [ACTION_RUNLEVEL4
] = SPECIAL_RUNLEVEL4_TARGET
,
741 [ACTION_RUNLEVEL5
] = SPECIAL_RUNLEVEL5_TARGET
,
742 [ACTION_RESCUE
] = SPECIAL_RESCUE_TARGET
,
743 [ACTION_EMERGENCY
] = SPECIAL_EMERGENCY_SERVICE
,
744 [ACTION_DEFAULT
] = SPECIAL_DEFAULT_TARGET
749 const char *method
, *mode
, *one_name
;
754 if (arg_action
== ACTION_SYSTEMCTL
) {
756 streq(args
[0], "stop") ? "StopUnit" :
757 streq(args
[0], "reload") ? "ReloadUnit" :
758 streq(args
[0], "restart") ? "RestartUnit" :
762 (streq(args
[0], "isolate") ||
763 streq(args
[0], "rescue") ||
764 streq(args
[0], "emergency")) ? "isolate" :
765 arg_replace
? "replace" :
768 one_name
= table
[verb_to_action(args
[0])];
771 assert(arg_action
< ELEMENTSOF(table
));
772 assert(table
[arg_action
]);
774 method
= "StartUnit";
776 mode
= (arg_action
== ACTION_EMERGENCY
||
777 arg_action
== ACTION_RESCUE
) ? "isolate" : "replace";
779 one_name
= table
[arg_action
];
783 if ((r
= enable_wait_for_jobs(bus
)) < 0) {
784 log_error("Could not watch jobs: %s", strerror(-r
));
788 if (!(s
= set_new(string_hash_func
, string_compare_func
))) {
789 log_error("Failed to allocate set.");
798 if ((r
= start_unit_one(bus
, method
, one_name
, mode
, s
)) <= 0)
801 for (i
= 1; i
< n
; i
++)
802 if ((r
= start_unit_one(bus
, method
, args
[i
], mode
, s
)) < 0)
807 r
= wait_for_jobs(bus
, s
);
816 static int start_special(DBusConnection
*bus
, char **args
, unsigned n
) {
820 warn_wall(verb_to_action(args
[0]));
822 return start_unit(bus
, args
, n
);
825 static DBusHandlerResult
monitor_filter(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
827 DBusMessage
*m
= NULL
, *reply
= NULL
;
832 dbus_error_init(&error
);
834 /* log_debug("Got D-Bus request: %s.%s() on %s", */
835 /* dbus_message_get_interface(message), */
836 /* dbus_message_get_member(message), */
837 /* dbus_message_get_path(message)); */
839 if (dbus_message_is_signal(message
, DBUS_INTERFACE_LOCAL
, "Disconnected")) {
840 log_error("Warning! D-Bus connection terminated.");
841 dbus_connection_close(connection
);
843 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "UnitNew") ||
844 dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
845 const char *id
, *path
;
847 if (!dbus_message_get_args(message
, &error
,
848 DBUS_TYPE_STRING
, &id
,
849 DBUS_TYPE_OBJECT_PATH
, &path
,
851 log_error("Failed to parse message: %s", error
.message
);
852 else if (streq(dbus_message_get_member(message
), "UnitNew"))
853 printf("Unit %s added.\n", id
);
855 printf("Unit %s removed.\n", id
);
857 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "JobNew") ||
858 dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
862 if (!dbus_message_get_args(message
, &error
,
863 DBUS_TYPE_UINT32
, &id
,
864 DBUS_TYPE_OBJECT_PATH
, &path
,
866 log_error("Failed to parse message: %s", error
.message
);
867 else if (streq(dbus_message_get_member(message
), "JobNew"))
868 printf("Job %u added.\n", id
);
870 printf("Job %u removed.\n", id
);
873 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Unit", "Changed") ||
874 dbus_message_is_signal(message
, "org.freedesktop.systemd1.Job", "Changed")) {
876 const char *path
, *interface
, *property
= "Id";
877 DBusMessageIter iter
, sub
;
879 path
= dbus_message_get_path(message
);
880 interface
= dbus_message_get_interface(message
);
882 if (!(m
= dbus_message_new_method_call(
883 "org.freedesktop.systemd1",
885 "org.freedesktop.DBus.Properties",
887 log_error("Could not allocate message.");
891 if (!dbus_message_append_args(m
,
892 DBUS_TYPE_STRING
, &interface
,
893 DBUS_TYPE_STRING
, &property
,
894 DBUS_TYPE_INVALID
)) {
895 log_error("Could not append arguments to message.");
899 if (!(reply
= dbus_connection_send_with_reply_and_block(connection
, m
, -1, &error
))) {
900 log_error("Failed to issue method call: %s", error
.message
);
904 if (!dbus_message_iter_init(reply
, &iter
) ||
905 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
906 log_error("Failed to parse reply.");
910 dbus_message_iter_recurse(&iter
, &sub
);
912 if (streq(interface
, "org.freedesktop.systemd1.Unit")) {
915 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRING
) {
916 log_error("Failed to parse reply.");
920 dbus_message_iter_get_basic(&sub
, &id
);
921 printf("Unit %s changed.\n", id
);
925 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_UINT32
) {
926 log_error("Failed to parse reply.");
930 dbus_message_iter_get_basic(&sub
, &id
);
931 printf("Job %u changed.\n", id
);
937 dbus_message_unref(m
);
940 dbus_message_unref(reply
);
942 dbus_error_free(&error
);
943 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
947 dbus_message_unref(m
);
950 dbus_message_unref(reply
);
952 dbus_error_free(&error
);
953 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
956 static int monitor(DBusConnection
*bus
, char **args
, unsigned n
) {
957 DBusMessage
*m
= NULL
, *reply
= NULL
;
961 dbus_error_init(&error
);
963 dbus_bus_add_match(bus
,
965 "sender='org.freedesktop.systemd1',"
966 "interface='org.freedesktop.systemd1.Manager',"
967 "path='/org/freedesktop/systemd1'",
970 if (dbus_error_is_set(&error
)) {
971 log_error("Failed to add match: %s", error
.message
);
976 dbus_bus_add_match(bus
,
978 "sender='org.freedesktop.systemd1',"
979 "interface='org.freedesktop.systemd1.Unit',"
983 if (dbus_error_is_set(&error
)) {
984 log_error("Failed to add match: %s", error
.message
);
989 dbus_bus_add_match(bus
,
991 "sender='org.freedesktop.systemd1',"
992 "interface='org.freedesktop.systemd1.Job',"
996 if (dbus_error_is_set(&error
)) {
997 log_error("Failed to add match: %s", error
.message
);
1002 if (!dbus_connection_add_filter(bus
, monitor_filter
, NULL
, NULL
)) {
1003 log_error("Failed to add filter.");
1008 if (!(m
= dbus_message_new_method_call(
1009 "org.freedesktop.systemd1",
1010 "/org/freedesktop/systemd1",
1011 "org.freedesktop.systemd1.Manager",
1013 log_error("Could not allocate message.");
1018 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1019 log_error("Failed to issue method call: %s", error
.message
);
1024 while (dbus_connection_read_write_dispatch(bus
, -1))
1031 /* This is slightly dirty, since we don't undo the filter or the matches. */
1034 dbus_message_unref(m
);
1037 dbus_message_unref(reply
);
1039 dbus_error_free(&error
);
1044 static int dump(DBusConnection
*bus
, char **args
, unsigned n
) {
1045 DBusMessage
*m
= NULL
, *reply
= NULL
;
1050 dbus_error_init(&error
);
1052 if (!(m
= dbus_message_new_method_call(
1053 "org.freedesktop.systemd1",
1054 "/org/freedesktop/systemd1",
1055 "org.freedesktop.systemd1.Manager",
1057 log_error("Could not allocate message.");
1061 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1062 log_error("Failed to issue method call: %s", error
.message
);
1067 if (!dbus_message_get_args(reply
, &error
,
1068 DBUS_TYPE_STRING
, &text
,
1069 DBUS_TYPE_INVALID
)) {
1070 log_error("Failed to parse reply: %s", error
.message
);
1075 fputs(text
, stdout
);
1081 dbus_message_unref(m
);
1084 dbus_message_unref(reply
);
1086 dbus_error_free(&error
);
1091 static int snapshot(DBusConnection
*bus
, char **args
, unsigned n
) {
1092 DBusMessage
*m
= NULL
, *reply
= NULL
;
1095 const char *name
= "", *path
, *id
;
1096 dbus_bool_t cleanup
= FALSE
;
1097 DBusMessageIter iter
, sub
;
1099 *interface
= "org.freedesktop.systemd1.Unit",
1102 dbus_error_init(&error
);
1104 if (!(m
= dbus_message_new_method_call(
1105 "org.freedesktop.systemd1",
1106 "/org/freedesktop/systemd1",
1107 "org.freedesktop.systemd1.Manager",
1108 "CreateSnapshot"))) {
1109 log_error("Could not allocate message.");
1116 if (!dbus_message_append_args(m
,
1117 DBUS_TYPE_STRING
, &name
,
1118 DBUS_TYPE_BOOLEAN
, &cleanup
,
1119 DBUS_TYPE_INVALID
)) {
1120 log_error("Could not append arguments to message.");
1125 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1126 log_error("Failed to issue method call: %s", error
.message
);
1131 if (!dbus_message_get_args(reply
, &error
,
1132 DBUS_TYPE_OBJECT_PATH
, &path
,
1133 DBUS_TYPE_INVALID
)) {
1134 log_error("Failed to parse reply: %s", error
.message
);
1139 dbus_message_unref(m
);
1140 if (!(m
= dbus_message_new_method_call(
1141 "org.freedesktop.systemd1",
1143 "org.freedesktop.DBus.Properties",
1145 log_error("Could not allocate message.");
1149 if (!dbus_message_append_args(m
,
1150 DBUS_TYPE_STRING
, &interface
,
1151 DBUS_TYPE_STRING
, &property
,
1152 DBUS_TYPE_INVALID
)) {
1153 log_error("Could not append arguments to message.");
1158 dbus_message_unref(reply
);
1159 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1160 log_error("Failed to issue method call: %s", error
.message
);
1165 if (!dbus_message_iter_init(reply
, &iter
) ||
1166 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
1167 log_error("Failed to parse reply.");
1172 dbus_message_iter_recurse(&iter
, &sub
);
1174 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_STRING
) {
1175 log_error("Failed to parse reply.");
1180 dbus_message_iter_get_basic(&sub
, &id
);
1186 dbus_message_unref(m
);
1189 dbus_message_unref(reply
);
1191 dbus_error_free(&error
);
1196 static int clear_jobs(DBusConnection
*bus
, char **args
, unsigned n
) {
1197 DBusMessage
*m
= NULL
, *reply
= NULL
;
1202 dbus_error_init(&error
);
1204 if (arg_action
== ACTION_RELOAD
)
1206 else if (arg_action
== ACTION_REEXEC
)
1207 method
= "Reexecute";
1209 assert(arg_action
== ACTION_SYSTEMCTL
);
1212 streq(args
[0], "clear-jobs") ? "ClearJobs" :
1213 streq(args
[0], "daemon-reload") ? "Reload" :
1214 streq(args
[0], "daemon-reexec") ? "Reexecute" :
1218 if (!(m
= dbus_message_new_method_call(
1219 "org.freedesktop.systemd1",
1220 "/org/freedesktop/systemd1",
1221 "org.freedesktop.systemd1.Manager",
1223 log_error("Could not allocate message.");
1227 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1229 if (arg_action
!= ACTION_SYSTEMCTL
&& error_is_no_service(&error
)) {
1230 /* There's always a fallback possible for
1231 * legacy actions. */
1236 log_error("Failed to issue method call: %s", error
.message
);
1245 dbus_message_unref(m
);
1248 dbus_message_unref(reply
);
1250 dbus_error_free(&error
);
1255 static int show_enviroment(DBusConnection
*bus
, char **args
, unsigned n
) {
1256 DBusMessage
*m
= NULL
, *reply
= NULL
;
1258 DBusMessageIter iter
, sub
, sub2
;
1261 *interface
= "org.freedesktop.systemd1.Manager",
1262 *property
= "Environment";
1264 dbus_error_init(&error
);
1266 if (!(m
= dbus_message_new_method_call(
1267 "org.freedesktop.systemd1",
1268 "/org/freedesktop/systemd1",
1269 "org.freedesktop.DBus.Properties",
1271 log_error("Could not allocate message.");
1275 if (!dbus_message_append_args(m
,
1276 DBUS_TYPE_STRING
, &interface
,
1277 DBUS_TYPE_STRING
, &property
,
1278 DBUS_TYPE_INVALID
)) {
1279 log_error("Could not append arguments to message.");
1284 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1285 log_error("Failed to issue method call: %s", error
.message
);
1290 if (!dbus_message_iter_init(reply
, &iter
) ||
1291 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_VARIANT
) {
1292 log_error("Failed to parse reply.");
1297 dbus_message_iter_recurse(&iter
, &sub
);
1299 if (dbus_message_iter_get_arg_type(&sub
) != DBUS_TYPE_ARRAY
||
1300 dbus_message_iter_get_element_type(&sub
) != DBUS_TYPE_STRING
) {
1301 log_error("Failed to parse reply.");
1306 dbus_message_iter_recurse(&sub
, &sub2
);
1308 while (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_INVALID
) {
1311 if (dbus_message_iter_get_arg_type(&sub2
) != DBUS_TYPE_STRING
) {
1312 log_error("Failed to parse reply.");
1317 dbus_message_iter_get_basic(&sub2
, &text
);
1318 printf("%s\n", text
);
1320 dbus_message_iter_next(&sub2
);
1327 dbus_message_unref(m
);
1330 dbus_message_unref(reply
);
1332 dbus_error_free(&error
);
1337 static int set_environment(DBusConnection
*bus
, char **args
, unsigned n
) {
1338 DBusMessage
*m
= NULL
, *reply
= NULL
;
1342 DBusMessageIter iter
, sub
;
1345 dbus_error_init(&error
);
1347 method
= streq(args
[0], "set-environment")
1349 : "UnsetEnvironment";
1351 if (!(m
= dbus_message_new_method_call(
1352 "org.freedesktop.systemd1",
1353 "/org/freedesktop/systemd1",
1354 "org.freedesktop.systemd1.Manager",
1357 log_error("Could not allocate message.");
1361 dbus_message_iter_init_append(m
, &iter
);
1363 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "s", &sub
)) {
1364 log_error("Could not append arguments to message.");
1369 for (i
= 1; i
< n
; i
++)
1370 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &args
[i
])) {
1371 log_error("Could not append arguments to message.");
1376 if (!dbus_message_iter_close_container(&iter
, &sub
)) {
1377 log_error("Could not append arguments to message.");
1382 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1383 log_error("Failed to issue method call: %s", error
.message
);
1392 dbus_message_unref(m
);
1395 dbus_message_unref(reply
);
1397 dbus_error_free(&error
);
1402 static int systemctl_help(void) {
1404 printf("%s [options]\n\n"
1405 "Send control commands to the init daemon.\n\n"
1406 " -h --help Show this help\n"
1407 " -t --type=TYPE List only units of a particular type\n"
1408 " -a --all Show all units, including dead ones\n"
1409 " --replace When installing a new job, replace existing conflicting ones\n"
1410 " --system Connect to system bus\n"
1411 " --session Connect to session bus\n"
1412 " --block Wait until operation finished\n"
1413 " --no-wall Don't send wall message before reboot/halt/power-off\n\n"
1415 " list-units List units\n"
1416 " list-jobs List jobs\n"
1417 " clear-jobs Cancel all jobs\n"
1418 " load [NAME...] Load one or more units\n"
1419 " cancel [JOB...] Cancel one or more jobs\n"
1420 " start [NAME...] Start one or more units\n"
1421 " stop [NAME...] Stop one or more units\n"
1422 " restart [NAME...] Restart one or more units\n"
1423 " reload [NAME...] Reload one or more units\n"
1424 " isolate [NAME] Start one unit and stop all others\n"
1425 " monitor Monitor unit/job changes\n"
1426 " dump Dump server status\n"
1427 " snapshot [NAME] Create a snapshot\n"
1428 " daemon-reload Reload init daemon configuration\n"
1429 " daemon-reexecute Reexecute init daemon\n"
1430 " daemon-exit Ask the init daemon to quit\n"
1431 " show-environment Dump environment\n"
1432 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
1433 " unset-environment [NAME...] Unset one or more environment variables\n"
1434 " halt Shut down and halt the system\n"
1435 " reboot Shut down and reboot the system\n"
1436 " poweroff Shut down and power off the system\n"
1437 " default Enter default mode\n"
1438 " rescue Enter rescue mode\n"
1439 " emergency Enter emergency mode\n",
1440 program_invocation_short_name
);
1445 static int halt_help(void) {
1447 printf("%s [options]\n\n"
1448 "%s the system.\n\n"
1449 " --help Show this help\n"
1450 " --halt Halt the machine\n"
1451 " -p --poweroff Switch off the machine\n"
1452 " --reboot Reboot the machine\n"
1453 " -f --force Force immediate reboot/halt/power-off\n"
1454 " -w --wtmp-only Don't reboot/halt/power-off, just write wtmp record\n"
1455 " -d --no-wtmp Don't write wtmp record\n"
1456 " -n --no-sync Don't sync before reboot/halt/power-off\n"
1457 " --no-wall Don't send wall message before reboot/halt/power-off\n",
1458 program_invocation_short_name
,
1459 arg_action
== ACTION_REBOOT
? "Reboot" :
1460 arg_action
== ACTION_POWEROFF
? "Power off" :
1466 static int shutdown_help(void) {
1468 printf("%s [options] [now] [WALL...]\n\n"
1469 "Shut down the system.\n\n"
1470 " --help Show this help\n"
1471 " -H --halt Halt the machine\n"
1472 " -P --poweroff Power-off the machine\n"
1473 " -r --reboot Reboot the machine\n"
1474 " -h Equivalent to --poweroff, overriden by --halt\n"
1475 " -k Don't reboot/halt/power-off, just send warnings\n"
1476 " --no-wall Don't send wall message before reboot/halt/power-off\n",
1477 program_invocation_short_name
);
1482 static int telinit_help(void) {
1484 printf("%s [options]\n\n"
1485 "Send control commands to the init daemon.\n\n"
1486 " --help Show this help\n"
1487 " --no-wall Don't send wall message before reboot/halt/power-off\n\n"
1489 " 0 Power-off the machine\n"
1490 " 6 Reboot the machine\n"
1491 " 2, 3, 4, 5 Start runlevelX.target unit\n"
1492 " 1, s, S Enter rescue mode\n"
1493 " q, Q Reload init daemon configuration\n"
1494 " u, U Reexecute init daemon\n",
1495 program_invocation_short_name
);
1500 static int runlevel_help(void) {
1502 printf("%s [options]\n\n"
1503 "Prints the previous and current runlevel of the init system.\n\n"
1504 " --help Show this help\n",
1505 program_invocation_short_name
);
1510 static int systemctl_parse_argv(int argc
, char *argv
[]) {
1513 ARG_REPLACE
= 0x100,
1520 static const struct option options
[] = {
1521 { "help", no_argument
, NULL
, 'h' },
1522 { "type", required_argument
, NULL
, 't' },
1523 { "all", no_argument
, NULL
, 'a' },
1524 { "replace", no_argument
, NULL
, ARG_REPLACE
},
1525 { "session", no_argument
, NULL
, ARG_SESSION
},
1526 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1527 { "block", no_argument
, NULL
, ARG_BLOCK
},
1528 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
1529 { NULL
, 0, NULL
, 0 }
1537 while ((c
= getopt_long(argc
, argv
, "hta", options
, NULL
)) >= 0) {
1562 arg_session
= false;
1577 log_error("Unknown option code %c", c
);
1585 static int halt_parse_argv(int argc
, char *argv
[]) {
1594 static const struct option options
[] = {
1595 { "help", no_argument
, NULL
, ARG_HELP
},
1596 { "halt", no_argument
, NULL
, ARG_HALT
},
1597 { "poweroff", no_argument
, NULL
, 'p' },
1598 { "reboot", no_argument
, NULL
, ARG_REBOOT
},
1599 { "force", no_argument
, NULL
, 'f' },
1600 { "wtmp-only", no_argument
, NULL
, 'w' },
1601 { "no-wtmp", no_argument
, NULL
, 'd' },
1602 { "no-sync", no_argument
, NULL
, 'n' },
1603 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
1604 { NULL
, 0, NULL
, 0 }
1612 if (utmp_get_runlevel(&runlevel
, NULL
) >= 0)
1613 if (runlevel
== '0' || runlevel
== '6')
1614 arg_immediate
= true;
1616 while ((c
= getopt_long(argc
, argv
, "pfwdnih", options
, NULL
)) >= 0) {
1624 arg_action
= ACTION_HALT
;
1628 arg_action
= ACTION_POWEROFF
;
1632 arg_action
= ACTION_REBOOT
;
1636 arg_immediate
= true;
1657 /* Compatibility nops */
1664 log_error("Unknown option code %c", c
);
1669 if (optind
< argc
) {
1670 log_error("Too many arguments.");
1677 static int shutdown_parse_argv(int argc
, char *argv
[]) {
1684 static const struct option options
[] = {
1685 { "help", no_argument
, NULL
, ARG_HELP
},
1686 { "halt", no_argument
, NULL
, 'H' },
1687 { "poweroff", no_argument
, NULL
, 'P' },
1688 { "reboot", no_argument
, NULL
, 'r' },
1689 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
1690 { NULL
, 0, NULL
, 0 }
1698 while ((c
= getopt_long(argc
, argv
, "HPrhkt:a", options
, NULL
)) >= 0) {
1706 arg_action
= ACTION_HALT
;
1710 arg_action
= ACTION_POWEROFF
;
1714 arg_action
= ACTION_REBOOT
;
1718 if (arg_action
!= ACTION_HALT
)
1719 arg_action
= ACTION_POWEROFF
;
1732 /* Compatibility nops */
1739 log_error("Unknown option code %c", c
);
1744 if (argc
> optind
&& !streq(argv
[optind
], "now"))
1745 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv
[optind
]);
1747 /* We ignore the time argument */
1748 if (argc
> optind
+ 1)
1749 arg_wall
= argv
+ optind
+ 1;
1756 static int telinit_parse_argv(int argc
, char *argv
[]) {
1763 static const struct option options
[] = {
1764 { "help", no_argument
, NULL
, ARG_HELP
},
1765 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
1766 { NULL
, 0, NULL
, 0 }
1769 static const struct {
1773 { '0', ACTION_POWEROFF
},
1774 { '6', ACTION_REBOOT
},
1775 { '1', ACTION_RESCUE
},
1776 { '2', ACTION_RUNLEVEL2
},
1777 { '3', ACTION_RUNLEVEL3
},
1778 { '4', ACTION_RUNLEVEL4
},
1779 { '5', ACTION_RUNLEVEL5
},
1780 { 's', ACTION_RESCUE
},
1781 { 'S', ACTION_RESCUE
},
1782 { 'q', ACTION_RELOAD
},
1783 { 'Q', ACTION_RELOAD
},
1784 { 'u', ACTION_REEXEC
},
1785 { 'U', ACTION_REEXEC
}
1794 while ((c
= getopt_long(argc
, argv
, "", options
, NULL
)) >= 0) {
1809 log_error("Unknown option code %c", c
);
1814 if (optind
>= argc
) {
1815 log_error("Argument missing.");
1819 if (optind
+ 1 < argc
) {
1820 log_error("Too many arguments.");
1824 if (strlen(argv
[optind
]) != 1) {
1825 log_error("Expected single character argument.");
1829 for (i
= 0; i
< ELEMENTSOF(table
); i
++)
1830 if (table
[i
].from
== argv
[optind
][0])
1833 if (i
>= ELEMENTSOF(table
)) {
1834 log_error("Unknown command %s.", argv
[optind
]);
1838 arg_action
= table
[i
].to
;
1845 static int runlevel_parse_argv(int argc
, char *argv
[]) {
1851 static const struct option options
[] = {
1852 { "help", no_argument
, NULL
, ARG_HELP
},
1853 { NULL
, 0, NULL
, 0 }
1861 while ((c
= getopt_long(argc
, argv
, "", options
, NULL
)) >= 0) {
1872 log_error("Unknown option code %c", c
);
1877 if (optind
< argc
) {
1878 log_error("Too many arguments.");
1885 static int parse_argv(int argc
, char *argv
[]) {
1889 if (program_invocation_short_name
) {
1891 if (strstr(program_invocation_short_name
, "halt")) {
1892 arg_action
= ACTION_HALT
;
1893 return halt_parse_argv(argc
, argv
);
1894 } else if (strstr(program_invocation_short_name
, "poweroff")) {
1895 arg_action
= ACTION_POWEROFF
;
1896 return halt_parse_argv(argc
, argv
);
1897 } else if (strstr(program_invocation_short_name
, "reboot")) {
1898 arg_action
= ACTION_REBOOT
;
1899 return halt_parse_argv(argc
, argv
);
1900 } else if (strstr(program_invocation_short_name
, "shutdown")) {
1901 arg_action
= ACTION_POWEROFF
;
1902 return shutdown_parse_argv(argc
, argv
);
1903 } else if (strstr(program_invocation_short_name
, "init")) {
1904 arg_action
= ACTION_INVALID
;
1905 return telinit_parse_argv(argc
, argv
);
1906 } else if (strstr(program_invocation_short_name
, "runlevel")) {
1907 arg_action
= ACTION_RUNLEVEL
;
1908 return runlevel_parse_argv(argc
, argv
);
1912 arg_action
= ACTION_SYSTEMCTL
;
1913 return systemctl_parse_argv(argc
, argv
);
1916 static int action_to_runlevel(void) {
1918 static const char table
[_ACTION_MAX
] = {
1919 [ACTION_HALT
] = '0',
1920 [ACTION_POWEROFF
] = '0',
1921 [ACTION_REBOOT
] = '6',
1922 [ACTION_RUNLEVEL2
] = '2',
1923 [ACTION_RUNLEVEL3
] = '3',
1924 [ACTION_RUNLEVEL4
] = '4',
1925 [ACTION_RUNLEVEL5
] = '5',
1926 [ACTION_RESCUE
] = '1'
1929 assert(arg_action
< _ACTION_MAX
);
1931 return table
[arg_action
];
1934 static int talk_upstart(DBusConnection
*bus
) {
1935 DBusMessage
*m
= NULL
, *reply
= NULL
;
1937 int previous
, rl
, r
;
1939 env1_buf
[] = "RUNLEVEL=X",
1940 env2_buf
[] = "PREVLEVEL=X";
1941 char *env1
= env1_buf
, *env2
= env2_buf
;
1942 const char *emit
= "runlevel";
1943 dbus_bool_t b_false
= FALSE
;
1944 DBusMessageIter iter
, sub
;
1946 dbus_error_init(&error
);
1948 if (!(rl
= action_to_runlevel()))
1951 if (utmp_get_runlevel(&previous
, NULL
) < 0)
1954 if (!(m
= dbus_message_new_method_call(
1955 "com.ubuntu.Upstart",
1956 "/com/ubuntu/Upstart",
1957 "com.ubuntu.Upstart0_6",
1960 log_error("Could not allocate message.");
1964 dbus_message_iter_init_append(m
, &iter
);
1966 env1_buf
[sizeof(env1_buf
)-2] = rl
;
1967 env2_buf
[sizeof(env2_buf
)-2] = previous
;
1969 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_STRING
, &emit
) ||
1970 !dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "s", &sub
) ||
1971 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &env1
) ||
1972 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &env2
) ||
1973 !dbus_message_iter_close_container(&iter
, &sub
) ||
1974 !dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &b_false
)) {
1975 log_error("Could not append arguments to message.");
1980 if (!(reply
= dbus_connection_send_with_reply_and_block(bus
, m
, -1, &error
))) {
1982 if (error_is_no_service(&error
)) {
1987 log_error("Failed to issue method call: %s", error
.message
);
1996 dbus_message_unref(m
);
1999 dbus_message_unref(reply
);
2001 dbus_error_free(&error
);
2006 static int talk_initctl(void) {
2007 struct init_request request
;
2011 if (!(rl
= action_to_runlevel()))
2015 request
.magic
= INIT_MAGIC
;
2016 request
.sleeptime
= 0;
2017 request
.cmd
= INIT_CMD_RUNLVL
;
2018 request
.runlevel
= rl
;
2020 if ((fd
= open(INIT_FIFO
, O_WRONLY
|O_NDELAY
|O_CLOEXEC
|O_NOCTTY
)) < 0) {
2022 if (errno
== ENOENT
)
2025 log_error("Failed to open "INIT_FIFO
": %m");
2030 r
= loop_write(fd
, &request
, sizeof(request
), false) != sizeof(request
);
2031 close_nointr_nofail(fd
);
2034 log_error("Failed to write to "INIT_FIFO
": %m");
2035 return errno
? -errno
: -EIO
;
2041 static int systemctl_main(DBusConnection
*bus
, int argc
, char *argv
[]) {
2043 static const struct {
2051 int (* const dispatch
)(DBusConnection
*bus
, char **args
, unsigned n
);
2053 { "list-units", LESS
, 1, list_units
},
2054 { "list-jobs", EQUAL
, 1, list_jobs
},
2055 { "clear-jobs", EQUAL
, 1, clear_jobs
},
2056 { "load", MORE
, 2, load_unit
},
2057 { "cancel", MORE
, 2, cancel_job
},
2058 { "start", MORE
, 2, start_unit
},
2059 { "stop", MORE
, 2, start_unit
},
2060 { "reload", MORE
, 2, start_unit
},
2061 { "restart", MORE
, 2, start_unit
},
2062 { "isolate", EQUAL
, 2, start_unit
},
2063 { "monitor", EQUAL
, 1, monitor
},
2064 { "dump", EQUAL
, 1, dump
},
2065 { "snapshot", LESS
, 2, snapshot
},
2066 { "daemon-reload", EQUAL
, 1, clear_jobs
},
2067 { "daemon-reexec", EQUAL
, 1, clear_jobs
},
2068 { "daemon-exit", EQUAL
, 1, clear_jobs
},
2069 { "show-environment", EQUAL
, 1, show_enviroment
},
2070 { "set-environment", MORE
, 2, set_environment
},
2071 { "unset-environment", MORE
, 2, set_environment
},
2072 { "halt", EQUAL
, 1, start_special
},
2073 { "poweroff", EQUAL
, 1, start_special
},
2074 { "reboot", EQUAL
, 1, start_special
},
2075 { "default", EQUAL
, 1, start_special
},
2076 { "rescue", EQUAL
, 1, start_special
},
2077 { "emergency", EQUAL
, 1, start_special
},
2087 left
= argc
- optind
;
2090 /* Special rule: no arguments means "list-units" */
2093 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
2094 if (streq(argv
[optind
], verbs
[i
].verb
))
2097 if (i
>= ELEMENTSOF(verbs
)) {
2098 log_error("Unknown operation %s", argv
[optind
]);
2103 switch (verbs
[i
].argc_cmp
) {
2106 if (left
!= verbs
[i
].argc
) {
2107 log_error("Invalid number of arguments.");
2114 if (left
< verbs
[i
].argc
) {
2115 log_error("Too few arguments.");
2122 if (left
> verbs
[i
].argc
) {
2123 log_error("Too many arguments.");
2130 assert_not_reached("Unknown comparison operator.");
2133 return verbs
[i
].dispatch(bus
, argv
+ optind
, left
);
2136 static int reload_with_fallback(DBusConnection
*bus
) {
2140 /* First, try systemd via D-Bus. */
2141 if ((r
= clear_jobs(bus
, NULL
, 0)) > 0)
2145 /* Nothing else worked, so let's try signals */
2146 assert(arg_action
== ACTION_RELOAD
|| arg_action
== ACTION_REEXEC
);
2148 if (kill(1, arg_action
== ACTION_RELOAD
? SIGHUP
: SIGTERM
) < 0) {
2149 log_error("kill() failed: %m");
2156 static int start_with_fallback(DBusConnection
*bus
) {
2159 warn_wall(arg_action
);
2162 /* First, try systemd via D-Bus. */
2163 if ((r
= start_unit(bus
, NULL
, 0)) > 0)
2166 /* Hmm, talking to systemd via D-Bus didn't work. Then
2167 * let's try to talk to Upstart via D-Bus. */
2168 if ((r
= talk_upstart(bus
)) > 0)
2172 /* Nothing else worked, so let's try
2174 if ((r
= talk_initctl()) != 0)
2177 log_error("Failed to talk to init daemon.");
2181 static int halt_main(DBusConnection
*bus
) {
2185 return start_with_fallback(bus
);
2188 if ((r
= utmp_put_shutdown(0)) < 0)
2189 log_warning("Failed to write utmp record: %s", strerror(-r
));
2197 /* Make sure C-A-D is handled by the kernel from this
2199 reboot(RB_ENABLE_CAD
);
2201 switch (arg_action
) {
2204 log_info("Halting");
2205 reboot(RB_HALT_SYSTEM
);
2208 case ACTION_POWEROFF
:
2209 log_info("Powering off");
2210 reboot(RB_POWER_OFF
);
2214 log_info("Rebooting");
2215 reboot(RB_AUTOBOOT
);
2219 assert_not_reached("Unknown halt action.");
2222 /* We should never reach this. */
2226 static int runlevel_main(void) {
2227 int r
, runlevel
, previous
;
2229 if ((r
= utmp_get_runlevel(&runlevel
, &previous
)) < 0) {
2235 previous
<= 0 ? 'N' : previous
,
2236 runlevel
<= 0 ? 'N' : runlevel
);
2241 int main(int argc
, char*argv
[]) {
2243 DBusConnection
*bus
= NULL
;
2246 dbus_error_init(&error
);
2248 log_parse_environment();
2250 if ((r
= parse_argv(argc
, argv
)) < 0)
2257 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
2258 * let's shortcut this */
2259 if (arg_action
== ACTION_RUNLEVEL
) {
2260 retval
= runlevel_main() < 0;
2264 /* If we are root, then let's not go via the bus */
2265 if (geteuid() == 0 && !arg_session
)
2266 bus
= dbus_connection_open("unix:abstract=/org/freedesktop/systemd1/private", &error
);
2268 bus
= dbus_bus_get(arg_session
? DBUS_BUS_SESSION
: DBUS_BUS_SYSTEM
, &error
);
2271 dbus_connection_set_exit_on_disconnect(bus
, FALSE
);
2273 switch (arg_action
) {
2275 case ACTION_SYSTEMCTL
: {
2278 log_error("Failed to get D-Bus connection: %s", error
.message
);
2282 retval
= systemctl_main(bus
, argc
, argv
) < 0;
2287 case ACTION_POWEROFF
:
2289 retval
= halt_main(bus
) < 0;
2292 case ACTION_RUNLEVEL2
:
2293 case ACTION_RUNLEVEL3
:
2294 case ACTION_RUNLEVEL4
:
2295 case ACTION_RUNLEVEL5
:
2297 case ACTION_EMERGENCY
:
2298 case ACTION_DEFAULT
:
2299 retval
= start_with_fallback(bus
) < 0;
2304 retval
= reload_with_fallback(bus
) < 0;
2307 case ACTION_INVALID
:
2308 case ACTION_RUNLEVEL
:
2310 assert_not_reached("Unknown action");
2316 dbus_connection_unref(bus
);
2318 dbus_error_free(&error
);