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/>.
27 #include <sys/ioctl.h>
31 #include <dbus/dbus.h>
38 static const char *arg_type = NULL;
39 static bool arg_all = false;
40 static bool arg_replace = false;
41 static bool arg_session = false;
42 static bool arg_block = false;
44 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
46 if (dbus_message_iter_get_arg_type(iter) != type)
49 dbus_message_iter_get_basic(iter, data);
51 if (!dbus_message_iter_next(iter) != !next)
57 static int columns(void) {
58 static int parsed_columns = 0;
61 if (parsed_columns > 0)
62 return parsed_columns;
64 if ((e = getenv("COLUMNS")))
65 parsed_columns = atoi(e);
67 if (parsed_columns <= 0) {
71 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
72 parsed_columns = ws.ws_col;
75 if (parsed_columns <= 0)
78 return parsed_columns;
81 static int list_units(DBusConnection *bus, char **args, unsigned n) {
82 DBusMessage *m = NULL, *reply = NULL;
85 DBusMessageIter iter, sub, sub2;
88 dbus_error_init(&error);
90 if (!(m = dbus_message_new_method_call(
91 "org.freedesktop.systemd1",
92 "/org/freedesktop/systemd1",
93 "org.freedesktop.systemd1.Manager",
95 log_error("Could not allocate message.");
99 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
100 log_error("Failed to issue method call: %s", error.message);
105 if (!dbus_message_iter_init(reply, &iter) ||
106 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
107 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
108 log_error("Failed to parse reply.");
113 dbus_message_iter_recurse(&iter, &sub);
115 printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
117 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
118 const char *id, *description, *load_state, *active_state, *sub_state, *unit_state, *job_type, *job_path, *dot;
121 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
122 log_error("Failed to parse reply.");
127 dbus_message_iter_recurse(&sub, &sub2);
129 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
130 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
131 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
132 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
133 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
134 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_state, true) < 0 ||
135 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 ||
136 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 ||
137 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) {
138 log_error("Failed to parse reply.");
143 if ((!arg_type || ((dot = strrchr(id, '.')) &&
144 streq(dot+1, arg_type))) &&
145 (arg_all || !streq(active_state, "inactive"))) {
149 printf("%-45s %-6s %-12s %-12s%n", id, load_state, active_state, sub_state, &a);
152 printf(" %-15s%n", job_type, &b);
156 if (a + b + 2 < columns()) {
160 printf("%.*s", columns() - a - b - 2, description);
167 dbus_message_iter_next(&sub);
171 printf("\n%u units listed.\n", k);
173 printf("\n%u live units listed. Pass --all to see dead units, too.\n", k);
179 dbus_message_unref(m);
182 dbus_message_unref(reply);
184 dbus_error_free(&error);
189 static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
190 DBusMessage *m = NULL, *reply = NULL;
193 DBusMessageIter iter, sub, sub2;
196 dbus_error_init(&error);
198 if (!(m = dbus_message_new_method_call(
199 "org.freedesktop.systemd1",
200 "/org/freedesktop/systemd1",
201 "org.freedesktop.systemd1.Manager",
203 log_error("Could not allocate message.");
207 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
208 log_error("Failed to issue method call: %s", error.message);
213 if (!dbus_message_iter_init(reply, &iter) ||
214 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
215 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
216 log_error("Failed to parse reply.");
221 dbus_message_iter_recurse(&iter, &sub);
223 printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
225 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
226 const char *name, *type, *state, *job_path, *unit_path;
229 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
230 log_error("Failed to parse reply.");
235 dbus_message_iter_recurse(&sub, &sub2);
237 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
238 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
239 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
240 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
241 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
242 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
243 log_error("Failed to parse reply.");
248 printf("%4u %-45s %-17s %-7s\n", id, name, type, state);
251 dbus_message_iter_next(&sub);
254 printf("\n%u jobs listed.\n", k);
259 dbus_message_unref(m);
262 dbus_message_unref(reply);
264 dbus_error_free(&error);
269 static int load_unit(DBusConnection *bus, char **args, unsigned n) {
270 DBusMessage *m = NULL, *reply = NULL;
275 dbus_error_init(&error);
277 for (i = 1; i < n; i++) {
279 if (!(m = dbus_message_new_method_call(
280 "org.freedesktop.systemd1",
281 "/org/freedesktop/systemd1",
282 "org.freedesktop.systemd1.Manager",
284 log_error("Could not allocate message.");
289 if (!dbus_message_append_args(m,
290 DBUS_TYPE_STRING, &args[i],
291 DBUS_TYPE_INVALID)) {
292 log_error("Could not append arguments to message.");
297 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
298 log_error("Failed to issue method call: %s", error.message);
303 dbus_message_unref(m);
304 dbus_message_unref(reply);
313 dbus_message_unref(m);
316 dbus_message_unref(reply);
318 dbus_error_free(&error);
323 static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
324 DBusMessage *m = NULL, *reply = NULL;
329 dbus_error_init(&error);
331 for (i = 1; i < n; i++) {
335 if (!(m = dbus_message_new_method_call(
336 "org.freedesktop.systemd1",
337 "/org/freedesktop/systemd1",
338 "org.freedesktop.systemd1.Manager",
340 log_error("Could not allocate message.");
345 if ((r = safe_atou(args[i], &id)) < 0) {
346 log_error("Failed to parse job id: %s", strerror(-r));
350 assert_cc(sizeof(uint32_t) == sizeof(id));
351 if (!dbus_message_append_args(m,
352 DBUS_TYPE_UINT32, &id,
353 DBUS_TYPE_INVALID)) {
354 log_error("Could not append arguments to message.");
359 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
360 log_error("Failed to issue method call: %s", error.message);
365 if (!dbus_message_get_args(reply, &error,
366 DBUS_TYPE_OBJECT_PATH, &path,
367 DBUS_TYPE_INVALID)) {
368 log_error("Failed to parse reply: %s", error.message);
373 dbus_message_unref(m);
374 if (!(m = dbus_message_new_method_call(
375 "org.freedesktop.systemd1",
377 "org.freedesktop.systemd1.Job",
379 log_error("Could not allocate message.");
384 dbus_message_unref(reply);
385 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
386 log_error("Failed to issue method call: %s", error.message);
391 dbus_message_unref(m);
392 dbus_message_unref(reply);
400 dbus_message_unref(m);
403 dbus_message_unref(reply);
405 dbus_error_free(&error);
410 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
418 dbus_error_init(&error);
420 /* log_debug("Got D-Bus request: %s.%s() on %s", */
421 /* dbus_message_get_interface(message), */
422 /* dbus_message_get_member(message), */
423 /* dbus_message_get_path(message)); */
425 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
426 log_error("Warning! D-Bus connection terminated.");
427 dbus_connection_close(connection);
429 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
433 if (!dbus_message_get_args(message, &error,
434 DBUS_TYPE_UINT32, &id,
435 DBUS_TYPE_OBJECT_PATH, &path,
437 log_error("Failed to parse message: %s", error.message);
441 if ((p = set_remove(s, (char*) path)))
446 dbus_error_free(&error);
447 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
450 static int enable_wait_for_jobs(DBusConnection *bus) {
452 DBusMessage *m = NULL, *reply = NULL;
457 dbus_error_init(&error);
459 dbus_bus_add_match(bus,
461 "sender='org.freedesktop.systemd1',"
462 "interface='org.freedesktop.systemd1.Manager',"
463 "member='JobRemoved',"
464 "path='/org/freedesktop/systemd1'",
467 if (dbus_error_is_set(&error)) {
468 log_error("Failed to add match: %s", error.message);
473 if (!(m = dbus_message_new_method_call(
474 "org.freedesktop.systemd1",
475 "/org/freedesktop/systemd1",
476 "org.freedesktop.systemd1.Manager",
478 log_error("Could not allocate message.");
483 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
484 log_error("Failed to issue method call: %s", error.message);
492 /* This is slightly dirty, since we don't undo the match registrations. */
495 dbus_message_unref(m);
498 dbus_message_unref(reply);
500 dbus_error_free(&error);
505 static int wait_for_jobs(DBusConnection *bus, Set *s) {
511 if (!dbus_connection_add_filter(bus, wait_filter, s, NULL)) {
512 log_error("Failed to add filter.");
517 while (!set_isempty(s) &&
518 dbus_connection_read_write_dispatch(bus, -1))
524 /* This is slightly dirty, since we don't undo the filter registration. */
529 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
530 DBusMessage *m = NULL, *reply = NULL;
534 const char *method, *mode;
538 dbus_error_init(&error);
541 streq(args[0], "start") ? "StartUnit" :
542 streq(args[0], "stop") ? "StopUnit" :
543 streq(args[0], "reload") ? "ReloadUnit" :
546 mode = arg_replace ? "replace" : "fail";
549 if ((r = enable_wait_for_jobs(bus)) < 0) {
550 log_error("Could not watch jobs: %s", strerror(-r));
555 for (i = 1; i < n; i++) {
557 if (!(m = dbus_message_new_method_call(
558 "org.freedesktop.systemd1",
559 "/org/freedesktop/systemd1",
560 "org.freedesktop.systemd1.Manager",
562 log_error("Could not allocate message.");
567 if (!dbus_message_append_args(m,
568 DBUS_TYPE_STRING, &args[i],
569 DBUS_TYPE_STRING, &mode,
570 DBUS_TYPE_INVALID)) {
571 log_error("Could not append arguments to message.");
576 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
577 log_error("Failed to issue method call: %s", error.message);
585 if (!dbus_message_get_args(reply, &error,
586 DBUS_TYPE_OBJECT_PATH, &path,
587 DBUS_TYPE_INVALID)) {
588 log_error("Failed to parse reply: %s", error.message);
594 if (!(s = set_new(string_hash_func, string_compare_func))) {
595 log_error("Failed to allocate set.");
600 if (!(p = strdup(path))) {
601 log_error("Failed to duplicate path.");
606 if ((r = set_put(s, p)) < 0) {
607 log_error("Failed to add path to set.");
613 dbus_message_unref(m);
614 dbus_message_unref(reply);
620 r = wait_for_jobs(bus, s);
631 dbus_message_unref(m);
634 dbus_message_unref(reply);
636 dbus_error_free(&error);
641 static int isolate_unit(DBusConnection *bus, char **args, unsigned n) {
642 DBusMessage *m = NULL, *reply = NULL;
645 const char *mode = "isolate";
649 dbus_error_init(&error);
652 if ((r = enable_wait_for_jobs(bus)) < 0) {
653 log_error("Could not watch jobs: %s", strerror(-r));
658 if (!(m = dbus_message_new_method_call(
659 "org.freedesktop.systemd1",
660 "/org/freedesktop/systemd1",
661 "org.freedesktop.systemd1.Manager",
663 log_error("Could not allocate message.");
668 if (!dbus_message_append_args(m,
669 DBUS_TYPE_STRING, &args[1],
670 DBUS_TYPE_STRING, &mode,
671 DBUS_TYPE_INVALID)) {
672 log_error("Could not append arguments to message.");
677 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
678 log_error("Failed to issue method call: %s", error.message);
686 if (!dbus_message_get_args(reply, &error,
687 DBUS_TYPE_OBJECT_PATH, &path,
688 DBUS_TYPE_INVALID)) {
689 log_error("Failed to parse reply: %s", error.message);
694 if (!(s = set_new(string_hash_func, string_compare_func))) {
695 log_error("Failed to allocate set.");
700 if (!(p = strdup(path))) {
701 log_error("Failed to duplicate path.");
706 if ((r = set_put(s, p)) < 0) {
707 log_error("Failed to add path to set.");
712 r = wait_for_jobs(bus, s);
724 dbus_message_unref(m);
727 dbus_message_unref(reply);
729 dbus_error_free(&error);
734 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
736 DBusMessage *m = NULL, *reply = NULL;
741 dbus_error_init(&error);
743 /* log_debug("Got D-Bus request: %s.%s() on %s", */
744 /* dbus_message_get_interface(message), */
745 /* dbus_message_get_member(message), */
746 /* dbus_message_get_path(message)); */
748 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
749 log_error("Warning! D-Bus connection terminated.");
750 dbus_connection_close(connection);
752 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
753 dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
754 const char *id, *path;
756 if (!dbus_message_get_args(message, &error,
757 DBUS_TYPE_STRING, &id,
758 DBUS_TYPE_OBJECT_PATH, &path,
760 log_error("Failed to parse message: %s", error.message);
761 else if (streq(dbus_message_get_member(message), "UnitNew"))
762 printf("Unit %s added.\n", id);
764 printf("Unit %s removed.\n", id);
766 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
767 dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
771 if (!dbus_message_get_args(message, &error,
772 DBUS_TYPE_UINT32, &id,
773 DBUS_TYPE_OBJECT_PATH, &path,
775 log_error("Failed to parse message: %s", error.message);
776 else if (streq(dbus_message_get_member(message), "JobNew"))
777 printf("Job %u added.\n", id);
779 printf("Job %u removed.\n", id);
782 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
783 dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
785 const char *path, *interface, *property = "Id";
786 DBusMessageIter iter, sub;
788 path = dbus_message_get_path(message);
789 interface = dbus_message_get_interface(message);
791 if (!(m = dbus_message_new_method_call(
792 "org.freedesktop.systemd1",
794 "org.freedesktop.DBus.Properties",
796 log_error("Could not allocate message.");
800 if (!dbus_message_append_args(m,
801 DBUS_TYPE_STRING, &interface,
802 DBUS_TYPE_STRING, &property,
803 DBUS_TYPE_INVALID)) {
804 log_error("Could not append arguments to message.");
808 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
809 log_error("Failed to issue method call: %s", error.message);
813 if (!dbus_message_iter_init(reply, &iter) ||
814 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
815 log_error("Failed to parse reply.");
819 dbus_message_iter_recurse(&iter, &sub);
821 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
824 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
825 log_error("Failed to parse reply.");
829 dbus_message_iter_get_basic(&sub, &id);
830 printf("Unit %s changed.\n", id);
834 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) {
835 log_error("Failed to parse reply.");
839 dbus_message_iter_get_basic(&sub, &id);
840 printf("Job %u changed.\n", id);
846 dbus_message_unref(m);
849 dbus_message_unref(reply);
851 dbus_error_free(&error);
852 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
856 dbus_message_unref(m);
859 dbus_message_unref(reply);
861 dbus_error_free(&error);
862 return DBUS_HANDLER_RESULT_NEED_MEMORY;
865 static int monitor(DBusConnection *bus, char **args, unsigned n) {
866 DBusMessage *m = NULL, *reply = NULL;
870 dbus_error_init(&error);
872 dbus_bus_add_match(bus,
874 "sender='org.freedesktop.systemd1',"
875 "interface='org.freedesktop.systemd1.Manager',"
876 "path='/org/freedesktop/systemd1'",
879 if (dbus_error_is_set(&error)) {
880 log_error("Failed to add match: %s", error.message);
885 dbus_bus_add_match(bus,
887 "sender='org.freedesktop.systemd1',"
888 "interface='org.freedesktop.systemd1.Unit',"
892 if (dbus_error_is_set(&error)) {
893 log_error("Failed to add match: %s", error.message);
898 dbus_bus_add_match(bus,
900 "sender='org.freedesktop.systemd1',"
901 "interface='org.freedesktop.systemd1.Job',"
905 if (dbus_error_is_set(&error)) {
906 log_error("Failed to add match: %s", error.message);
911 if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
912 log_error("Failed to add filter.");
917 if (!(m = dbus_message_new_method_call(
918 "org.freedesktop.systemd1",
919 "/org/freedesktop/systemd1",
920 "org.freedesktop.systemd1.Manager",
922 log_error("Could not allocate message.");
927 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
928 log_error("Failed to issue method call: %s", error.message);
933 while (dbus_connection_read_write_dispatch(bus, -1))
940 /* This is slightly dirty, since we don't undo the filter or the matches. */
943 dbus_message_unref(m);
946 dbus_message_unref(reply);
948 dbus_error_free(&error);
953 static int dump(DBusConnection *bus, char **args, unsigned n) {
954 DBusMessage *m = NULL, *reply = NULL;
959 dbus_error_init(&error);
961 if (!(m = dbus_message_new_method_call(
962 "org.freedesktop.systemd1",
963 "/org/freedesktop/systemd1",
964 "org.freedesktop.systemd1.Manager",
966 log_error("Could not allocate message.");
970 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
971 log_error("Failed to issue method call: %s", error.message);
976 if (!dbus_message_get_args(reply, &error,
977 DBUS_TYPE_STRING, &text,
978 DBUS_TYPE_INVALID)) {
979 log_error("Failed to parse reply: %s", error.message);
990 dbus_message_unref(m);
993 dbus_message_unref(reply);
995 dbus_error_free(&error);
1000 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
1001 DBusMessage *m = NULL, *reply = NULL;
1004 const char *name = "", *path, *id;
1005 dbus_bool_t cleanup = FALSE;
1006 DBusMessageIter iter, sub;
1008 *interface = "org.freedesktop.systemd1.Unit",
1011 dbus_error_init(&error);
1013 if (!(m = dbus_message_new_method_call(
1014 "org.freedesktop.systemd1",
1015 "/org/freedesktop/systemd1",
1016 "org.freedesktop.systemd1.Manager",
1017 "CreateSnapshot"))) {
1018 log_error("Could not allocate message.");
1025 if (!dbus_message_append_args(m,
1026 DBUS_TYPE_STRING, &name,
1027 DBUS_TYPE_BOOLEAN, &cleanup,
1028 DBUS_TYPE_INVALID)) {
1029 log_error("Could not append arguments to message.");
1034 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1035 log_error("Failed to issue method call: %s", error.message);
1040 if (!dbus_message_get_args(reply, &error,
1041 DBUS_TYPE_OBJECT_PATH, &path,
1042 DBUS_TYPE_INVALID)) {
1043 log_error("Failed to parse reply: %s", error.message);
1048 dbus_message_unref(m);
1049 if (!(m = dbus_message_new_method_call(
1050 "org.freedesktop.systemd1",
1052 "org.freedesktop.DBus.Properties",
1054 log_error("Could not allocate message.");
1058 if (!dbus_message_append_args(m,
1059 DBUS_TYPE_STRING, &interface,
1060 DBUS_TYPE_STRING, &property,
1061 DBUS_TYPE_INVALID)) {
1062 log_error("Could not append arguments to message.");
1067 dbus_message_unref(reply);
1068 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1069 log_error("Failed to issue method call: %s", error.message);
1074 if (!dbus_message_iter_init(reply, &iter) ||
1075 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1076 log_error("Failed to parse reply.");
1081 dbus_message_iter_recurse(&iter, &sub);
1083 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1084 log_error("Failed to parse reply.");
1089 dbus_message_iter_get_basic(&sub, &id);
1095 dbus_message_unref(m);
1098 dbus_message_unref(reply);
1100 dbus_error_free(&error);
1105 static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
1106 DBusMessage *m = NULL, *reply = NULL;
1111 dbus_error_init(&error);
1114 streq(args[0], "clear-jobs") ? "ClearJobs" :
1115 streq(args[0], "daemon-reload") ? "Reload" :
1116 streq(args[0], "daemon-reexec") ? "Reexecute" :
1119 if (!(m = dbus_message_new_method_call(
1120 "org.freedesktop.systemd1",
1121 "/org/freedesktop/systemd1",
1122 "org.freedesktop.systemd1.Manager",
1124 log_error("Could not allocate message.");
1128 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1129 log_error("Failed to issue method call: %s", error.message);
1138 dbus_message_unref(m);
1141 dbus_message_unref(reply);
1143 dbus_error_free(&error);
1148 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
1149 DBusMessage *m = NULL, *reply = NULL;
1151 DBusMessageIter iter, sub, sub2;
1154 *interface = "org.freedesktop.systemd1.Manager",
1155 *property = "Environment";
1157 dbus_error_init(&error);
1159 if (!(m = dbus_message_new_method_call(
1160 "org.freedesktop.systemd1",
1161 "/org/freedesktop/systemd1",
1162 "org.freedesktop.DBus.Properties",
1164 log_error("Could not allocate message.");
1168 if (!dbus_message_append_args(m,
1169 DBUS_TYPE_STRING, &interface,
1170 DBUS_TYPE_STRING, &property,
1171 DBUS_TYPE_INVALID)) {
1172 log_error("Could not append arguments to message.");
1177 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1178 log_error("Failed to issue method call: %s", error.message);
1183 if (!dbus_message_iter_init(reply, &iter) ||
1184 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1185 log_error("Failed to parse reply.");
1190 dbus_message_iter_recurse(&iter, &sub);
1192 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
1193 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
1194 log_error("Failed to parse reply.");
1199 dbus_message_iter_recurse(&sub, &sub2);
1201 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
1204 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
1205 log_error("Failed to parse reply.");
1210 dbus_message_iter_get_basic(&sub2, &text);
1211 printf("%s\n", text);
1213 dbus_message_iter_next(&sub2);
1220 dbus_message_unref(m);
1223 dbus_message_unref(reply);
1225 dbus_error_free(&error);
1230 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
1231 DBusMessage *m = NULL, *reply = NULL;
1235 DBusMessageIter iter, sub;
1238 dbus_error_init(&error);
1240 method = streq(args[0], "set-environment")
1242 : "UnsetEnvironment";
1244 if (!(m = dbus_message_new_method_call(
1245 "org.freedesktop.systemd1",
1246 "/org/freedesktop/systemd1",
1247 "org.freedesktop.systemd1.Manager",
1250 log_error("Could not allocate message.");
1254 dbus_message_iter_init_append(m, &iter);
1256 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
1257 log_error("Could not append arguments to message.");
1262 for (i = 1; i < n; i++)
1263 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
1264 log_error("Could not append arguments to message.");
1269 if (!dbus_message_iter_close_container(&iter, &sub)) {
1270 log_error("Could not append arguments to message.");
1275 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1276 log_error("Failed to issue method call: %s", error.message);
1285 dbus_message_unref(m);
1288 dbus_message_unref(reply);
1290 dbus_error_free(&error);
1295 static int help(void) {
1297 printf("%s [options]\n\n"
1298 " -h --help Show this help\n"
1299 " -t --type=TYPE List only units of a particular type\n"
1300 " -a --all Show all units, including dead ones\n"
1301 " --replace When installing a new job, replace existing conflicting ones\n"
1302 " --system Connect to system bus\n"
1303 " --session Connect to session bus\n"
1304 " --block Wait until operation finished\n\n"
1306 " list-units List units\n"
1307 " list-jobs List jobs\n"
1308 " clear-jobs Cancel all jobs\n"
1309 " load [NAME...] Load one or more units\n"
1310 " cancel [JOB...] Cancel one or more jobs\n"
1311 " start [NAME...] Start one or more units\n"
1312 " stop [NAME...] Stop one or more units\n"
1313 " restart [NAME...] Restart one or more units\n"
1314 " reload [NAME...] Reload one or more units\n"
1315 " isolate [NAME] Start one unit and stop all others\n"
1316 " monitor Monitor unit/job changes\n"
1317 " dump Dump server status\n"
1318 " snapshot [NAME] Create a snapshot\n"
1319 " daemon-reload Reload daemon configuration\n"
1320 " daemon-reexecute Reexecute daemon\n"
1321 " daemon-exit Ask the daemon to quit\n"
1322 " show-environment Dump environment\n"
1323 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
1324 " unset-environment [NAME...] Unset one or more environment variables\n",
1330 static int parse_argv(int argc, char *argv[]) {
1333 ARG_REPLACE = 0x100,
1339 static const struct option options[] = {
1340 { "help", no_argument, NULL, 'h' },
1341 { "type", required_argument, NULL, 't' },
1342 { "all", no_argument, NULL, 'a' },
1343 { "replace", no_argument, NULL, ARG_REPLACE },
1344 { "session", no_argument, NULL, ARG_SESSION },
1345 { "system", no_argument, NULL, ARG_SYSTEM },
1346 { "block", no_argument, NULL, ARG_BLOCK },
1347 { NULL, 0, NULL, 0 }
1355 while ((c = getopt_long(argc, argv, "hta", options, NULL)) >= 0) {
1380 arg_session = false;
1391 log_error("Unknown option code %c", c);
1399 int main(int argc, char*argv[]) {
1401 static const struct {
1409 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
1411 { "list-units", LESS, 1, list_units },
1412 { "list-jobs", EQUAL, 1, list_jobs },
1413 { "clear-jobs", EQUAL, 1, clear_jobs },
1414 { "load", MORE, 2, load_unit },
1415 { "cancel", MORE, 2, cancel_job },
1416 { "start", MORE, 2, start_unit },
1417 { "stop", MORE, 2, start_unit },
1418 { "reload", MORE, 2, start_unit },
1419 { "restart", MORE, 2, start_unit },
1420 { "isolate", EQUAL, 2, isolate_unit },
1421 { "monitor", EQUAL, 1, monitor },
1422 { "dump", EQUAL, 1, dump },
1423 { "snapshot", LESS, 2, snapshot },
1424 { "daemon-reload", EQUAL, 1, clear_jobs },
1425 { "daemon-reexec", EQUAL, 1, clear_jobs },
1426 { "daemon-exit", EQUAL, 1, clear_jobs },
1427 { "show-environment", EQUAL, 1, show_enviroment },
1428 { "set-environment", MORE, 2, set_environment },
1429 { "unset-environment", MORE, 2, set_environment },
1432 int r, retval = 1, left;
1434 DBusConnection *bus = NULL;
1437 dbus_error_init(&error);
1439 log_set_target(LOG_TARGET_CONSOLE);
1440 log_parse_environment();
1442 if ((r = parse_argv(argc, argv)) < 0)
1449 left = argc - optind;
1452 /* Special rule: no arguments means "list-units" */
1455 for (i = 0; i < ELEMENTSOF(verbs); i++)
1456 if (streq(argv[optind], verbs[i].verb))
1459 if (i >= ELEMENTSOF(verbs)) {
1460 log_error("Unknown operation %s", argv[optind]);
1465 switch (verbs[i].argc_cmp) {
1468 if (left != verbs[i].argc) {
1469 log_error("Invalid number of arguments.");
1476 if (left < verbs[i].argc) {
1477 log_error("Too few arguments.");
1484 if (left > verbs[i].argc) {
1485 log_error("Too many arguments.");
1492 assert_not_reached("Unknown comparison operator.");
1495 if (!(bus = dbus_bus_get(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) {
1496 log_error("Failed to get D-Bus connection: %s", error.message);
1500 dbus_connection_set_exit_on_disconnect(bus, FALSE);
1502 retval = verbs[i].dispatch(bus, argv + optind, left) < 0;
1507 dbus_connection_unref(bus);