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>
32 #include <dbus/dbus.h>
38 #include "utmp-wtmp.h"
40 static const char *arg_type = NULL;
41 static bool arg_all = false;
42 static bool arg_replace = false;
43 static bool arg_session = false;
44 static bool arg_block = false;
45 static bool arg_immediate = false;
46 static bool arg_no_wtmp = false;
47 static bool arg_no_sync = false;
48 static bool arg_dry = false;
49 static char **arg_wall = NULL;
65 } arg_action = ACTION_SYSTEMCTL;
67 static bool error_is_no_service(DBusError *error) {
69 if (!dbus_error_is_set(error))
72 if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
75 if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
78 return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
81 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
83 if (dbus_message_iter_get_arg_type(iter) != type)
86 dbus_message_iter_get_basic(iter, data);
88 if (!dbus_message_iter_next(iter) != !next)
94 static int columns(void) {
95 static int parsed_columns = 0;
98 if (parsed_columns > 0)
99 return parsed_columns;
101 if ((e = getenv("COLUMNS")))
102 parsed_columns = atoi(e);
104 if (parsed_columns <= 0) {
108 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
109 parsed_columns = ws.ws_col;
112 if (parsed_columns <= 0)
115 return parsed_columns;
119 static void warn_wall(void) {
120 static const char *table[_ACTION_MAX] = {
121 [ACTION_HALT] = "The system is going down for system halt NOW!",
122 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
123 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
124 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!"
127 if (!table[arg_action])
130 utmp_wall(table[arg_action]);
133 static int list_units(DBusConnection *bus, char **args, unsigned n) {
134 DBusMessage *m = NULL, *reply = NULL;
137 DBusMessageIter iter, sub, sub2;
140 dbus_error_init(&error);
142 if (!(m = dbus_message_new_method_call(
143 "org.freedesktop.systemd1",
144 "/org/freedesktop/systemd1",
145 "org.freedesktop.systemd1.Manager",
147 log_error("Could not allocate message.");
151 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
152 log_error("Failed to issue method call: %s", error.message);
157 if (!dbus_message_iter_init(reply, &iter) ||
158 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
159 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
160 log_error("Failed to parse reply.");
165 dbus_message_iter_recurse(&iter, &sub);
167 printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
169 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
170 const char *id, *description, *load_state, *active_state, *sub_state, *unit_state, *job_type, *job_path, *dot;
173 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
174 log_error("Failed to parse reply.");
179 dbus_message_iter_recurse(&sub, &sub2);
181 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
182 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
183 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
184 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
185 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
186 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_state, true) < 0 ||
187 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 ||
188 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 ||
189 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) {
190 log_error("Failed to parse reply.");
195 if ((!arg_type || ((dot = strrchr(id, '.')) &&
196 streq(dot+1, arg_type))) &&
197 (arg_all || !streq(active_state, "inactive"))) {
201 printf("%-45s %-6s %-12s %-12s%n", id, load_state, active_state, sub_state, &a);
204 printf(" %-15s%n", job_type, &b);
208 if (a + b + 2 < columns()) {
212 printf("%.*s", columns() - a - b - 2, description);
219 dbus_message_iter_next(&sub);
223 printf("\n%u units listed.\n", k);
225 printf("\n%u live units listed. Pass --all to see dead units, too.\n", k);
231 dbus_message_unref(m);
234 dbus_message_unref(reply);
236 dbus_error_free(&error);
241 static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
242 DBusMessage *m = NULL, *reply = NULL;
245 DBusMessageIter iter, sub, sub2;
248 dbus_error_init(&error);
250 if (!(m = dbus_message_new_method_call(
251 "org.freedesktop.systemd1",
252 "/org/freedesktop/systemd1",
253 "org.freedesktop.systemd1.Manager",
255 log_error("Could not allocate message.");
259 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
260 log_error("Failed to issue method call: %s", error.message);
265 if (!dbus_message_iter_init(reply, &iter) ||
266 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
267 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
268 log_error("Failed to parse reply.");
273 dbus_message_iter_recurse(&iter, &sub);
275 printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
277 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
278 const char *name, *type, *state, *job_path, *unit_path;
281 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
282 log_error("Failed to parse reply.");
287 dbus_message_iter_recurse(&sub, &sub2);
289 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
290 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
291 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
292 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
293 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
294 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
295 log_error("Failed to parse reply.");
300 printf("%4u %-45s %-17s %-7s\n", id, name, type, state);
303 dbus_message_iter_next(&sub);
306 printf("\n%u jobs listed.\n", k);
311 dbus_message_unref(m);
314 dbus_message_unref(reply);
316 dbus_error_free(&error);
321 static int load_unit(DBusConnection *bus, char **args, unsigned n) {
322 DBusMessage *m = NULL, *reply = NULL;
327 dbus_error_init(&error);
329 for (i = 1; i < n; i++) {
331 if (!(m = dbus_message_new_method_call(
332 "org.freedesktop.systemd1",
333 "/org/freedesktop/systemd1",
334 "org.freedesktop.systemd1.Manager",
336 log_error("Could not allocate message.");
341 if (!dbus_message_append_args(m,
342 DBUS_TYPE_STRING, &args[i],
343 DBUS_TYPE_INVALID)) {
344 log_error("Could not append arguments to message.");
349 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
350 log_error("Failed to issue method call: %s", error.message);
355 dbus_message_unref(m);
356 dbus_message_unref(reply);
365 dbus_message_unref(m);
368 dbus_message_unref(reply);
370 dbus_error_free(&error);
375 static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
376 DBusMessage *m = NULL, *reply = NULL;
381 dbus_error_init(&error);
383 for (i = 1; i < n; i++) {
387 if (!(m = dbus_message_new_method_call(
388 "org.freedesktop.systemd1",
389 "/org/freedesktop/systemd1",
390 "org.freedesktop.systemd1.Manager",
392 log_error("Could not allocate message.");
397 if ((r = safe_atou(args[i], &id)) < 0) {
398 log_error("Failed to parse job id: %s", strerror(-r));
402 assert_cc(sizeof(uint32_t) == sizeof(id));
403 if (!dbus_message_append_args(m,
404 DBUS_TYPE_UINT32, &id,
405 DBUS_TYPE_INVALID)) {
406 log_error("Could not append arguments to message.");
411 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
412 log_error("Failed to issue method call: %s", error.message);
417 if (!dbus_message_get_args(reply, &error,
418 DBUS_TYPE_OBJECT_PATH, &path,
419 DBUS_TYPE_INVALID)) {
420 log_error("Failed to parse reply: %s", error.message);
425 dbus_message_unref(m);
426 if (!(m = dbus_message_new_method_call(
427 "org.freedesktop.systemd1",
429 "org.freedesktop.systemd1.Job",
431 log_error("Could not allocate message.");
436 dbus_message_unref(reply);
437 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
438 log_error("Failed to issue method call: %s", error.message);
443 dbus_message_unref(m);
444 dbus_message_unref(reply);
452 dbus_message_unref(m);
455 dbus_message_unref(reply);
457 dbus_error_free(&error);
462 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
470 dbus_error_init(&error);
472 /* log_debug("Got D-Bus request: %s.%s() on %s", */
473 /* dbus_message_get_interface(message), */
474 /* dbus_message_get_member(message), */
475 /* dbus_message_get_path(message)); */
477 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
478 log_error("Warning! D-Bus connection terminated.");
479 dbus_connection_close(connection);
481 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
485 if (!dbus_message_get_args(message, &error,
486 DBUS_TYPE_UINT32, &id,
487 DBUS_TYPE_OBJECT_PATH, &path,
489 log_error("Failed to parse message: %s", error.message);
493 if ((p = set_remove(s, (char*) path)))
498 dbus_error_free(&error);
499 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
502 static int enable_wait_for_jobs(DBusConnection *bus) {
504 DBusMessage *m = NULL, *reply = NULL;
509 dbus_error_init(&error);
511 dbus_bus_add_match(bus,
513 "sender='org.freedesktop.systemd1',"
514 "interface='org.freedesktop.systemd1.Manager',"
515 "member='JobRemoved',"
516 "path='/org/freedesktop/systemd1'",
519 if (dbus_error_is_set(&error)) {
520 log_error("Failed to add match: %s", error.message);
525 if (!(m = dbus_message_new_method_call(
526 "org.freedesktop.systemd1",
527 "/org/freedesktop/systemd1",
528 "org.freedesktop.systemd1.Manager",
530 log_error("Could not allocate message.");
535 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
536 log_error("Failed to issue method call: %s", error.message);
544 /* This is slightly dirty, since we don't undo the match registrations. */
547 dbus_message_unref(m);
550 dbus_message_unref(reply);
552 dbus_error_free(&error);
557 static int wait_for_jobs(DBusConnection *bus, Set *s) {
563 if (!dbus_connection_add_filter(bus, wait_filter, s, NULL)) {
564 log_error("Failed to add filter.");
569 while (!set_isempty(s) &&
570 dbus_connection_read_write_dispatch(bus, -1))
576 /* This is slightly dirty, since we don't undo the filter registration. */
581 static int start_unit_one(
588 DBusMessage *m = NULL, *reply = NULL;
596 assert(!arg_block || s);
598 dbus_error_init(&error);
600 if (!(m = dbus_message_new_method_call(
601 "org.freedesktop.systemd1",
602 "/org/freedesktop/systemd1",
603 "org.freedesktop.systemd1.Manager",
605 log_error("Could not allocate message.");
610 if (!dbus_message_append_args(m,
611 DBUS_TYPE_STRING, &name,
612 DBUS_TYPE_STRING, &mode,
613 DBUS_TYPE_INVALID)) {
614 log_error("Could not append arguments to message.");
619 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
621 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
622 /* There's always a fallback possible for
628 log_error("Failed to issue method call: %s", error.message);
637 if (!dbus_message_get_args(reply, &error,
638 DBUS_TYPE_OBJECT_PATH, &path,
639 DBUS_TYPE_INVALID)) {
640 log_error("Failed to parse reply: %s", error.message);
645 if (!(p = strdup(path))) {
646 log_error("Failed to duplicate path.");
651 if ((r = set_put(s, p)) < 0) {
653 log_error("Failed to add path to set.");
662 dbus_message_unref(m);
665 dbus_message_unref(reply);
667 dbus_error_free(&error);
672 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
674 static const char * const table[_ACTION_MAX] = {
675 [ACTION_HALT] = "halt.target",
676 [ACTION_POWEROFF] = "poweroff.target",
677 [ACTION_REBOOT] = "reboot.target",
678 [ACTION_RUNLEVEL2] = "runlevel2.target",
679 [ACTION_RUNLEVEL3] = "runlevel3.target",
680 [ACTION_RUNLEVEL4] = "runlevel4.target",
681 [ACTION_RUNLEVEL5] = "runlevel5.target",
682 [ACTION_RESCUE] = "rescue.target"
687 const char *method, *mode;
690 if (arg_action == ACTION_SYSTEMCTL) {
692 streq(args[0], "start") ? "StartUnit" :
693 streq(args[0], "stop") ? "StopUnit" :
694 streq(args[0], "reload") ? "ReloadUnit" :
695 streq(args[0], "restart") ? "RestartUnit" :
696 /* isolate */ "StartUnit";
699 streq(args[0], "isolate") ? "isolate" :
700 arg_replace ? "replace" :
704 if ((r = enable_wait_for_jobs(bus)) < 0) {
705 log_error("Could not watch jobs: %s", strerror(-r));
709 if (!(s = set_new(string_hash_func, string_compare_func))) {
710 log_error("Failed to allocate set.");
716 assert(arg_action < ELEMENTSOF(table));
717 assert(table[arg_action]);
719 method = "StartUnit";
720 mode = arg_action == ACTION_RESCUE ? "isolate" : "replace";
725 if (arg_action == ACTION_SYSTEMCTL) {
726 for (i = 1; i < n; i++)
727 if ((r = start_unit_one(bus, method, args[i], mode, s)) < 0)
731 r = wait_for_jobs(bus, s);
734 if ((r = start_unit_one(bus, method, table[arg_action], mode, s)) <= 0)
745 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
747 DBusMessage *m = NULL, *reply = NULL;
752 dbus_error_init(&error);
754 /* log_debug("Got D-Bus request: %s.%s() on %s", */
755 /* dbus_message_get_interface(message), */
756 /* dbus_message_get_member(message), */
757 /* dbus_message_get_path(message)); */
759 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
760 log_error("Warning! D-Bus connection terminated.");
761 dbus_connection_close(connection);
763 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
764 dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
765 const char *id, *path;
767 if (!dbus_message_get_args(message, &error,
768 DBUS_TYPE_STRING, &id,
769 DBUS_TYPE_OBJECT_PATH, &path,
771 log_error("Failed to parse message: %s", error.message);
772 else if (streq(dbus_message_get_member(message), "UnitNew"))
773 printf("Unit %s added.\n", id);
775 printf("Unit %s removed.\n", id);
777 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
778 dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
782 if (!dbus_message_get_args(message, &error,
783 DBUS_TYPE_UINT32, &id,
784 DBUS_TYPE_OBJECT_PATH, &path,
786 log_error("Failed to parse message: %s", error.message);
787 else if (streq(dbus_message_get_member(message), "JobNew"))
788 printf("Job %u added.\n", id);
790 printf("Job %u removed.\n", id);
793 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
794 dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
796 const char *path, *interface, *property = "Id";
797 DBusMessageIter iter, sub;
799 path = dbus_message_get_path(message);
800 interface = dbus_message_get_interface(message);
802 if (!(m = dbus_message_new_method_call(
803 "org.freedesktop.systemd1",
805 "org.freedesktop.DBus.Properties",
807 log_error("Could not allocate message.");
811 if (!dbus_message_append_args(m,
812 DBUS_TYPE_STRING, &interface,
813 DBUS_TYPE_STRING, &property,
814 DBUS_TYPE_INVALID)) {
815 log_error("Could not append arguments to message.");
819 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
820 log_error("Failed to issue method call: %s", error.message);
824 if (!dbus_message_iter_init(reply, &iter) ||
825 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
826 log_error("Failed to parse reply.");
830 dbus_message_iter_recurse(&iter, &sub);
832 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
835 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
836 log_error("Failed to parse reply.");
840 dbus_message_iter_get_basic(&sub, &id);
841 printf("Unit %s changed.\n", id);
845 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) {
846 log_error("Failed to parse reply.");
850 dbus_message_iter_get_basic(&sub, &id);
851 printf("Job %u changed.\n", id);
857 dbus_message_unref(m);
860 dbus_message_unref(reply);
862 dbus_error_free(&error);
863 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
867 dbus_message_unref(m);
870 dbus_message_unref(reply);
872 dbus_error_free(&error);
873 return DBUS_HANDLER_RESULT_NEED_MEMORY;
876 static int monitor(DBusConnection *bus, char **args, unsigned n) {
877 DBusMessage *m = NULL, *reply = NULL;
881 dbus_error_init(&error);
883 dbus_bus_add_match(bus,
885 "sender='org.freedesktop.systemd1',"
886 "interface='org.freedesktop.systemd1.Manager',"
887 "path='/org/freedesktop/systemd1'",
890 if (dbus_error_is_set(&error)) {
891 log_error("Failed to add match: %s", error.message);
896 dbus_bus_add_match(bus,
898 "sender='org.freedesktop.systemd1',"
899 "interface='org.freedesktop.systemd1.Unit',"
903 if (dbus_error_is_set(&error)) {
904 log_error("Failed to add match: %s", error.message);
909 dbus_bus_add_match(bus,
911 "sender='org.freedesktop.systemd1',"
912 "interface='org.freedesktop.systemd1.Job',"
916 if (dbus_error_is_set(&error)) {
917 log_error("Failed to add match: %s", error.message);
922 if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
923 log_error("Failed to add filter.");
928 if (!(m = dbus_message_new_method_call(
929 "org.freedesktop.systemd1",
930 "/org/freedesktop/systemd1",
931 "org.freedesktop.systemd1.Manager",
933 log_error("Could not allocate message.");
938 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
939 log_error("Failed to issue method call: %s", error.message);
944 while (dbus_connection_read_write_dispatch(bus, -1))
951 /* This is slightly dirty, since we don't undo the filter or the matches. */
954 dbus_message_unref(m);
957 dbus_message_unref(reply);
959 dbus_error_free(&error);
964 static int dump(DBusConnection *bus, char **args, unsigned n) {
965 DBusMessage *m = NULL, *reply = NULL;
970 dbus_error_init(&error);
972 if (!(m = dbus_message_new_method_call(
973 "org.freedesktop.systemd1",
974 "/org/freedesktop/systemd1",
975 "org.freedesktop.systemd1.Manager",
977 log_error("Could not allocate message.");
981 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
982 log_error("Failed to issue method call: %s", error.message);
987 if (!dbus_message_get_args(reply, &error,
988 DBUS_TYPE_STRING, &text,
989 DBUS_TYPE_INVALID)) {
990 log_error("Failed to parse reply: %s", error.message);
1001 dbus_message_unref(m);
1004 dbus_message_unref(reply);
1006 dbus_error_free(&error);
1011 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
1012 DBusMessage *m = NULL, *reply = NULL;
1015 const char *name = "", *path, *id;
1016 dbus_bool_t cleanup = FALSE;
1017 DBusMessageIter iter, sub;
1019 *interface = "org.freedesktop.systemd1.Unit",
1022 dbus_error_init(&error);
1024 if (!(m = dbus_message_new_method_call(
1025 "org.freedesktop.systemd1",
1026 "/org/freedesktop/systemd1",
1027 "org.freedesktop.systemd1.Manager",
1028 "CreateSnapshot"))) {
1029 log_error("Could not allocate message.");
1036 if (!dbus_message_append_args(m,
1037 DBUS_TYPE_STRING, &name,
1038 DBUS_TYPE_BOOLEAN, &cleanup,
1039 DBUS_TYPE_INVALID)) {
1040 log_error("Could not append arguments to message.");
1045 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1046 log_error("Failed to issue method call: %s", error.message);
1051 if (!dbus_message_get_args(reply, &error,
1052 DBUS_TYPE_OBJECT_PATH, &path,
1053 DBUS_TYPE_INVALID)) {
1054 log_error("Failed to parse reply: %s", error.message);
1059 dbus_message_unref(m);
1060 if (!(m = dbus_message_new_method_call(
1061 "org.freedesktop.systemd1",
1063 "org.freedesktop.DBus.Properties",
1065 log_error("Could not allocate message.");
1069 if (!dbus_message_append_args(m,
1070 DBUS_TYPE_STRING, &interface,
1071 DBUS_TYPE_STRING, &property,
1072 DBUS_TYPE_INVALID)) {
1073 log_error("Could not append arguments to message.");
1078 dbus_message_unref(reply);
1079 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1080 log_error("Failed to issue method call: %s", error.message);
1085 if (!dbus_message_iter_init(reply, &iter) ||
1086 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1087 log_error("Failed to parse reply.");
1092 dbus_message_iter_recurse(&iter, &sub);
1094 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1095 log_error("Failed to parse reply.");
1100 dbus_message_iter_get_basic(&sub, &id);
1106 dbus_message_unref(m);
1109 dbus_message_unref(reply);
1111 dbus_error_free(&error);
1116 static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
1117 DBusMessage *m = NULL, *reply = NULL;
1122 dbus_error_init(&error);
1124 if (arg_action == ACTION_RELOAD)
1126 else if (arg_action == ACTION_REEXEC)
1127 method = "Reexecute";
1129 assert(arg_action == ACTION_SYSTEMCTL);
1132 streq(args[0], "clear-jobs") ? "ClearJobs" :
1133 streq(args[0], "daemon-reload") ? "Reload" :
1134 streq(args[0], "daemon-reexec") ? "Reexecute" :
1138 if (!(m = dbus_message_new_method_call(
1139 "org.freedesktop.systemd1",
1140 "/org/freedesktop/systemd1",
1141 "org.freedesktop.systemd1.Manager",
1143 log_error("Could not allocate message.");
1147 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1149 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
1150 /* There's always a fallback possible for
1151 * legacy actions. */
1156 log_error("Failed to issue method call: %s", error.message);
1165 dbus_message_unref(m);
1168 dbus_message_unref(reply);
1170 dbus_error_free(&error);
1175 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
1176 DBusMessage *m = NULL, *reply = NULL;
1178 DBusMessageIter iter, sub, sub2;
1181 *interface = "org.freedesktop.systemd1.Manager",
1182 *property = "Environment";
1184 dbus_error_init(&error);
1186 if (!(m = dbus_message_new_method_call(
1187 "org.freedesktop.systemd1",
1188 "/org/freedesktop/systemd1",
1189 "org.freedesktop.DBus.Properties",
1191 log_error("Could not allocate message.");
1195 if (!dbus_message_append_args(m,
1196 DBUS_TYPE_STRING, &interface,
1197 DBUS_TYPE_STRING, &property,
1198 DBUS_TYPE_INVALID)) {
1199 log_error("Could not append arguments to message.");
1204 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1205 log_error("Failed to issue method call: %s", error.message);
1210 if (!dbus_message_iter_init(reply, &iter) ||
1211 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1212 log_error("Failed to parse reply.");
1217 dbus_message_iter_recurse(&iter, &sub);
1219 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
1220 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
1221 log_error("Failed to parse reply.");
1226 dbus_message_iter_recurse(&sub, &sub2);
1228 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
1231 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
1232 log_error("Failed to parse reply.");
1237 dbus_message_iter_get_basic(&sub2, &text);
1238 printf("%s\n", text);
1240 dbus_message_iter_next(&sub2);
1247 dbus_message_unref(m);
1250 dbus_message_unref(reply);
1252 dbus_error_free(&error);
1257 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
1258 DBusMessage *m = NULL, *reply = NULL;
1262 DBusMessageIter iter, sub;
1265 dbus_error_init(&error);
1267 method = streq(args[0], "set-environment")
1269 : "UnsetEnvironment";
1271 if (!(m = dbus_message_new_method_call(
1272 "org.freedesktop.systemd1",
1273 "/org/freedesktop/systemd1",
1274 "org.freedesktop.systemd1.Manager",
1277 log_error("Could not allocate message.");
1281 dbus_message_iter_init_append(m, &iter);
1283 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
1284 log_error("Could not append arguments to message.");
1289 for (i = 1; i < n; i++)
1290 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
1291 log_error("Could not append arguments to message.");
1296 if (!dbus_message_iter_close_container(&iter, &sub)) {
1297 log_error("Could not append arguments to message.");
1302 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1303 log_error("Failed to issue method call: %s", error.message);
1312 dbus_message_unref(m);
1315 dbus_message_unref(reply);
1317 dbus_error_free(&error);
1322 static int systemctl_help(void) {
1324 printf("%s [options]\n\n"
1325 "Send control commands to the init system.\n\n"
1326 " -h --help Show this help\n"
1327 " -t --type=TYPE List only units of a particular type\n"
1328 " -a --all Show all units, including dead ones\n"
1329 " --replace When installing a new job, replace existing conflicting ones\n"
1330 " --system Connect to system bus\n"
1331 " --session Connect to session bus\n"
1332 " --block Wait until operation finished\n\n"
1334 " list-units List units\n"
1335 " list-jobs List jobs\n"
1336 " clear-jobs Cancel all jobs\n"
1337 " load [NAME...] Load one or more units\n"
1338 " cancel [JOB...] Cancel one or more jobs\n"
1339 " start [NAME...] Start one or more units\n"
1340 " stop [NAME...] Stop one or more units\n"
1341 " restart [NAME...] Restart one or more units\n"
1342 " reload [NAME...] Reload one or more units\n"
1343 " isolate [NAME] Start one unit and stop all others\n"
1344 " monitor Monitor unit/job changes\n"
1345 " dump Dump server status\n"
1346 " snapshot [NAME] Create a snapshot\n"
1347 " daemon-reload Reload daemon configuration\n"
1348 " daemon-reexecute Reexecute daemon\n"
1349 " daemon-exit Ask the daemon to quit\n"
1350 " show-environment Dump environment\n"
1351 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
1352 " unset-environment [NAME...] Unset one or more environment variables\n",
1353 program_invocation_short_name);
1358 static int halt_help(void) {
1360 printf("%s [options]\n\n"
1361 "%s the system.\n\n"
1362 " --help Show this help\n"
1363 " --halt Halt the machine\n"
1364 " -p --poweroff Switch off the machine\n"
1365 " --reboot Reboot the machine\n"
1366 " -f --force Force immediate reboot/halt/power-off\n"
1367 " -w --wtmp-only Don't reboot/halt/power-off, just write wtmp record\n"
1368 " -d --no-wtmp Don't write wtmp record\n"
1369 " -n --no-sync Don't sync before reboot/halt/power-off\n",
1370 program_invocation_short_name,
1371 arg_action == ACTION_REBOOT ? "Reboot" :
1372 arg_action == ACTION_POWEROFF ? "Power off" :
1378 static int shutdown_help(void) {
1380 printf("%s [options] [TIME] [WALL...]\n\n"
1381 "Shut down the system.\n\n"
1382 " --help Show this help\n"
1383 " -H --halt Halt the machine\n"
1384 " -P --poweroff Power-off the machine\n"
1385 " -r --reboot Reboot the machine\n"
1386 " -h Equivalent to --poweroff, overriden by --halt\n"
1387 " -k Don't reboot/halt/power-off, just send warnings\n",
1388 program_invocation_short_name);
1393 static int telinit_help(void) {
1395 printf("%s [options]\n\n"
1396 "Send control commands to the init system.\n\n"
1397 " --help Show this help\n\n"
1399 " 0 Power-off the machine\n"
1400 " 6 Reboot the machine\n"
1401 " 1, 2, 3, 4, 5 Start runlevelX.target unit\n"
1402 " s, S Start the rescue.target unit\n"
1403 " q, Q Ask systemd to reload its configuration\n"
1404 " u, U Ask systemd to reexecute itself\n",
1405 program_invocation_short_name);
1410 static int runlevel_help(void) {
1412 printf("%s [options]\n\n"
1413 "Prints the previous and current runlevel of the init system.\n\n"
1414 " --help Show this help\n",
1415 program_invocation_short_name);
1420 static int systemctl_parse_argv(int argc, char *argv[]) {
1423 ARG_REPLACE = 0x100,
1429 static const struct option options[] = {
1430 { "help", no_argument, NULL, 'h' },
1431 { "type", required_argument, NULL, 't' },
1432 { "all", no_argument, NULL, 'a' },
1433 { "replace", no_argument, NULL, ARG_REPLACE },
1434 { "session", no_argument, NULL, ARG_SESSION },
1435 { "system", no_argument, NULL, ARG_SYSTEM },
1436 { "block", no_argument, NULL, ARG_BLOCK },
1437 { NULL, 0, NULL, 0 }
1445 while ((c = getopt_long(argc, argv, "hta", options, NULL)) >= 0) {
1470 arg_session = false;
1481 log_error("Unknown option code %c", c);
1489 static int halt_parse_argv(int argc, char *argv[]) {
1497 static const struct option options[] = {
1498 { "help", no_argument, NULL, ARG_HELP },
1499 { "halt", no_argument, NULL, ARG_HALT },
1500 { "poweroff", no_argument, NULL, 'p' },
1501 { "reboot", no_argument, NULL, ARG_REBOOT },
1502 { "force", no_argument, NULL, 'f' },
1503 { "wtmp-only", no_argument, NULL, 'w' },
1504 { "no-wtmp", no_argument, NULL, 'd' },
1505 { "no-sync", no_argument, NULL, 'n' },
1506 { NULL, 0, NULL, 0 }
1514 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
1515 if (runlevel == '0' || runlevel == '6')
1516 arg_immediate = true;
1518 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
1526 arg_action = ACTION_HALT;
1530 arg_action = ACTION_POWEROFF;
1534 arg_action = ACTION_REBOOT;
1538 arg_immediate = true;
1555 /* Compatibility nops */
1562 log_error("Unknown option code %c", c);
1567 if (optind < argc) {
1568 log_error("Too many arguments.");
1575 static int shutdown_parse_argv(int argc, char *argv[]) {
1581 static const struct option options[] = {
1582 { "help", no_argument, NULL, ARG_HELP },
1583 { "halt", no_argument, NULL, 'H' },
1584 { "poweroff", no_argument, NULL, 'P' },
1585 { "reboot", no_argument, NULL, 'r' },
1586 { NULL, 0, NULL, 0 }
1594 while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
1602 arg_action = ACTION_HALT;
1606 arg_action = ACTION_POWEROFF;
1610 arg_action = ACTION_REBOOT;
1614 if (arg_action != ACTION_HALT)
1615 arg_action = ACTION_POWEROFF;
1624 /* Compatibility nops */
1631 log_error("Unknown option code %c", c);
1636 /* We ignore the time argument */
1637 if (argc > optind + 1)
1638 arg_wall = argv + optind + 1;
1646 static int telinit_parse_argv(int argc, char *argv[]) {
1652 static const struct option options[] = {
1653 { "help", no_argument, NULL, ARG_HELP },
1654 { NULL, 0, NULL, 0 }
1657 static const struct {
1661 { '0', ACTION_POWEROFF },
1662 { '6', ACTION_REBOOT },
1663 { '1', ACTION_RESCUE },
1664 { '2', ACTION_RUNLEVEL2 },
1665 { '3', ACTION_RUNLEVEL3 },
1666 { '4', ACTION_RUNLEVEL4 },
1667 { '5', ACTION_RUNLEVEL5 },
1668 { 's', ACTION_RESCUE },
1669 { 'S', ACTION_RESCUE },
1670 { 'q', ACTION_RELOAD },
1671 { 'Q', ACTION_RELOAD },
1672 { 'u', ACTION_REEXEC },
1673 { 'U', ACTION_REEXEC }
1682 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
1693 log_error("Unknown option code %c", c);
1698 if (optind >= argc) {
1699 log_error("Argument missing.");
1703 if (optind + 1 < argc) {
1704 log_error("Too many arguments.");
1708 if (strlen(argv[optind]) != 1) {
1709 log_error("Expected single character argument.");
1713 for (i = 0; i < ELEMENTSOF(table); i++)
1714 if (table[i].from == argv[optind][0])
1717 if (i >= ELEMENTSOF(table)) {
1718 log_error("Unknown command %s.", argv[optind]);
1722 arg_action = table[i].to;
1729 static int runlevel_parse_argv(int argc, char *argv[]) {
1735 static const struct option options[] = {
1736 { "help", no_argument, NULL, ARG_HELP },
1737 { NULL, 0, NULL, 0 }
1745 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
1756 log_error("Unknown option code %c", c);
1761 if (optind < argc) {
1762 log_error("Too many arguments.");
1769 static int parse_argv(int argc, char *argv[]) {
1773 if (program_invocation_short_name) {
1775 if (strstr(program_invocation_short_name, "halt")) {
1776 arg_action = ACTION_HALT;
1777 return halt_parse_argv(argc, argv);
1778 } else if (strstr(program_invocation_short_name, "poweroff")) {
1779 arg_action = ACTION_POWEROFF;
1780 return halt_parse_argv(argc, argv);
1781 } else if (strstr(program_invocation_short_name, "reboot")) {
1782 arg_action = ACTION_REBOOT;
1783 return halt_parse_argv(argc, argv);
1784 } else if (strstr(program_invocation_short_name, "shutdown")) {
1785 arg_action = ACTION_POWEROFF;
1786 return shutdown_parse_argv(argc, argv);
1787 } else if (strstr(program_invocation_short_name, "init")) {
1788 arg_action = ACTION_INVALID;
1789 return telinit_parse_argv(argc, argv);
1790 } else if (strstr(program_invocation_short_name, "runlevel")) {
1791 arg_action = ACTION_RUNLEVEL;
1792 return runlevel_parse_argv(argc, argv);
1796 arg_action = ACTION_SYSTEMCTL;
1797 return systemctl_parse_argv(argc, argv);
1800 static int talk_upstart(DBusConnection *bus) {
1801 log_error("Talking upstart");
1805 static int talk_initctl(void) {
1806 log_error("Talking initctl");
1810 static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
1812 static const struct {
1820 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
1822 { "list-units", LESS, 1, list_units },
1823 { "list-jobs", EQUAL, 1, list_jobs },
1824 { "clear-jobs", EQUAL, 1, clear_jobs },
1825 { "load", MORE, 2, load_unit },
1826 { "cancel", MORE, 2, cancel_job },
1827 { "start", MORE, 2, start_unit },
1828 { "stop", MORE, 2, start_unit },
1829 { "reload", MORE, 2, start_unit },
1830 { "restart", MORE, 2, start_unit },
1831 { "isolate", EQUAL, 2, start_unit },
1832 { "monitor", EQUAL, 1, monitor },
1833 { "dump", EQUAL, 1, dump },
1834 { "snapshot", LESS, 2, snapshot },
1835 { "daemon-reload", EQUAL, 1, clear_jobs },
1836 { "daemon-reexec", EQUAL, 1, clear_jobs },
1837 { "daemon-exit", EQUAL, 1, clear_jobs },
1838 { "show-environment", EQUAL, 1, show_enviroment },
1839 { "set-environment", MORE, 2, set_environment },
1840 { "unset-environment", MORE, 2, set_environment },
1850 left = argc - optind;
1853 /* Special rule: no arguments means "list-units" */
1856 for (i = 0; i < ELEMENTSOF(verbs); i++)
1857 if (streq(argv[optind], verbs[i].verb))
1860 if (i >= ELEMENTSOF(verbs)) {
1861 log_error("Unknown operation %s", argv[optind]);
1866 switch (verbs[i].argc_cmp) {
1869 if (left != verbs[i].argc) {
1870 log_error("Invalid number of arguments.");
1877 if (left < verbs[i].argc) {
1878 log_error("Too few arguments.");
1885 if (left > verbs[i].argc) {
1886 log_error("Too many arguments.");
1893 assert_not_reached("Unknown comparison operator.");
1896 return verbs[i].dispatch(bus, argv + optind, left);
1899 static int reload_with_fallback(DBusConnection *bus) {
1903 /* First, try systemd via D-Bus. */
1904 if ((r = clear_jobs(bus, NULL, 0)) > 0)
1908 /* Nothing else worked, so let's try signals */
1909 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
1911 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
1912 log_error("kill() failed: %m");
1919 static int start_with_fallback(DBusConnection *bus) {
1925 /* First, try systemd via D-Bus. */
1926 if ((r = start_unit(bus, NULL, 0)) > 0)
1929 /* Hmm, talking to systemd via D-Bus didn't work. Then
1930 * let's try to talk to Upstart via D-Bus. */
1931 if ((r = talk_upstart(bus)) > 0)
1935 /* Nothing else worked, so let's try
1937 return talk_initctl();
1940 static int halt_main(DBusConnection *bus) {
1944 return start_with_fallback(bus);
1949 if ((r = utmp_put_shutdown(0)) < 0)
1950 log_warning("Failed to write utmp record: %s", strerror(-r));
1958 /* Make sure C-A-D is handled by the kernel from this
1960 reboot(RB_ENABLE_CAD);
1962 switch (arg_action) {
1965 log_info("Halting");
1966 reboot(RB_HALT_SYSTEM);
1969 case ACTION_POWEROFF:
1970 log_info("Powering off");
1971 reboot(RB_POWER_OFF);
1975 log_info("Rebooting");
1976 reboot(RB_AUTOBOOT);
1980 assert_not_reached("Unknown halt action.");
1983 /* We should never reach this. */
1987 static int runlevel_main(void) {
1988 int r, runlevel, previous;
1990 if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
1996 previous <= 0 ? 'N' : previous,
1997 runlevel <= 0 ? 'N' : runlevel);
2002 int main(int argc, char*argv[]) {
2004 DBusConnection *bus = NULL;
2007 dbus_error_init(&error);
2009 log_parse_environment();
2011 if ((r = parse_argv(argc, argv)) < 0)
2018 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
2019 * let's shortcut this */
2020 if (arg_action == ACTION_RUNLEVEL) {
2021 retval = runlevel_main() < 0;
2025 if ((bus = dbus_bus_get(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error)))
2026 dbus_connection_set_exit_on_disconnect(bus, FALSE);
2028 switch (arg_action) {
2030 case ACTION_SYSTEMCTL: {
2033 log_error("Failed to get D-Bus connection: %s", error.message);
2037 retval = systemctl_main(bus, argc, argv) < 0;
2042 case ACTION_POWEROFF:
2044 retval = halt_main(bus) < 0;
2047 case ACTION_RUNLEVEL2:
2048 case ACTION_RUNLEVEL3:
2049 case ACTION_RUNLEVEL4:
2050 case ACTION_RUNLEVEL5:
2052 retval = start_with_fallback(bus) < 0;
2057 retval = reload_with_fallback(bus) < 0;
2061 assert_not_reached("Unknown action");
2067 dbus_connection_unref(bus);
2069 dbus_error_free(&error);