]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/systemctl.c
execute: optionally ignore return status of invoked commands
[thirdparty/systemd.git] / src / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33
34 #include <dbus/dbus.h>
35
36 #include "log.h"
37 #include "util.h"
38 #include "macro.h"
39 #include "set.h"
40 #include "utmp-wtmp.h"
41 #include "special.h"
42 #include "initreq.h"
43 #include "strv.h"
44 #include "dbus-common.h"
45 #include "cgroup-show.h"
46 #include "cgroup-util.h"
47 #include "list.h"
48
49 static const char *arg_type = NULL;
50 static const char *arg_property = NULL;
51 static bool arg_all = false;
52 static bool arg_fail = false;
53 static bool arg_session = false;
54 static bool arg_no_block = false;
55 static bool arg_immediate = false;
56 static bool arg_no_wtmp = false;
57 static bool arg_no_sync = false;
58 static bool arg_no_wall = false;
59 static bool arg_dry = false;
60 static bool arg_quiet = false;
61 static char **arg_wall = NULL;
62 enum action {
63 ACTION_INVALID,
64 ACTION_SYSTEMCTL,
65 ACTION_HALT,
66 ACTION_POWEROFF,
67 ACTION_REBOOT,
68 ACTION_RUNLEVEL2,
69 ACTION_RUNLEVEL3,
70 ACTION_RUNLEVEL4,
71 ACTION_RUNLEVEL5,
72 ACTION_RESCUE,
73 ACTION_EMERGENCY,
74 ACTION_DEFAULT,
75 ACTION_RELOAD,
76 ACTION_REEXEC,
77 ACTION_RUNLEVEL,
78 _ACTION_MAX
79 } arg_action = ACTION_SYSTEMCTL;
80
81 static bool private_bus = false;
82
83 static bool error_is_no_service(DBusError *error) {
84
85 assert(error);
86
87 if (!dbus_error_is_set(error))
88 return false;
89
90 if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
91 return true;
92
93 if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
94 return true;
95
96 return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
97 }
98
99 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
100
101 assert(iter);
102 assert(data);
103
104 if (dbus_message_iter_get_arg_type(iter) != type)
105 return -EIO;
106
107 dbus_message_iter_get_basic(iter, data);
108
109 if (!dbus_message_iter_next(iter) != !next)
110 return -EIO;
111
112 return 0;
113 }
114
115 static void warn_wall(enum action action) {
116 static const char *table[_ACTION_MAX] = {
117 [ACTION_HALT] = "The system is going down for system halt NOW!",
118 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
119 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
120 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
121 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
122 };
123
124 if (arg_no_wall)
125 return;
126
127 if (arg_wall) {
128 char *p;
129
130 if (!(p = strv_join(arg_wall, " "))) {
131 log_error("Failed to join strings.");
132 return;
133 }
134
135 if (*p) {
136 utmp_wall(p);
137 free(p);
138 return;
139 }
140
141 free(p);
142 }
143
144 if (!table[action])
145 return;
146
147 utmp_wall(table[action]);
148 }
149
150 static int list_units(DBusConnection *bus, char **args, unsigned n) {
151 DBusMessage *m = NULL, *reply = NULL;
152 DBusError error;
153 int r;
154 DBusMessageIter iter, sub, sub2;
155 unsigned k = 0;
156
157 dbus_error_init(&error);
158
159 assert(bus);
160
161 if (!(m = dbus_message_new_method_call(
162 "org.freedesktop.systemd1",
163 "/org/freedesktop/systemd1",
164 "org.freedesktop.systemd1.Manager",
165 "ListUnits"))) {
166 log_error("Could not allocate message.");
167 return -ENOMEM;
168 }
169
170 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
171 log_error("Failed to issue method call: %s", error.message);
172 r = -EIO;
173 goto finish;
174 }
175
176 if (!dbus_message_iter_init(reply, &iter) ||
177 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
178 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
179 log_error("Failed to parse reply.");
180 r = -EIO;
181 goto finish;
182 }
183
184 dbus_message_iter_recurse(&iter, &sub);
185
186 printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
187
188 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
189 const char *id, *description, *load_state, *active_state, *sub_state, *unit_state, *job_type, *job_path, *dot;
190 uint32_t job_id;
191
192 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
193 log_error("Failed to parse reply.");
194 r = -EIO;
195 goto finish;
196 }
197
198 dbus_message_iter_recurse(&sub, &sub2);
199
200 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
201 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
202 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
203 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
204 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
205 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_state, true) < 0 ||
206 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 ||
207 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 ||
208 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) {
209 log_error("Failed to parse reply.");
210 r = -EIO;
211 goto finish;
212 }
213
214 if ((!arg_type || ((dot = strrchr(id, '.')) &&
215 streq(dot+1, arg_type))) &&
216 (arg_all || !streq(active_state, "inactive"))) {
217
218 int a = 0, b = 0;
219
220 if (streq(active_state, "maintenance"))
221 fputs(ANSI_HIGHLIGHT_ON, stdout);
222
223 printf("%-45s %-6s %-12s %-12s%n", id, load_state, active_state, sub_state, &a);
224
225 if (job_id != 0)
226 printf(" %-15s%n", job_type, &b);
227 else
228 b = 1 + 15;
229
230 if (a + b + 2 < columns()) {
231 if (job_id == 0)
232 printf(" ");
233
234 printf(" %.*s", columns() - a - b - 2, description);
235 }
236
237 if (streq(active_state, "maintenance"))
238 fputs(ANSI_HIGHLIGHT_OFF, stdout);
239
240 fputs("\n", stdout);
241 k++;
242 }
243
244 dbus_message_iter_next(&sub);
245 }
246
247 if (arg_all)
248 printf("\n%u units listed.\n", k);
249 else
250 printf("\n%u live units listed. Pass --all to see dead units, too.\n", k);
251
252 r = 0;
253
254 finish:
255 if (m)
256 dbus_message_unref(m);
257
258 if (reply)
259 dbus_message_unref(reply);
260
261 dbus_error_free(&error);
262
263 return r;
264 }
265
266 static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
267 DBusMessage *m = NULL, *reply = NULL;
268 DBusError error;
269 int r;
270 DBusMessageIter iter, sub, sub2;
271 unsigned k = 0;
272
273 dbus_error_init(&error);
274
275 assert(bus);
276
277 if (!(m = dbus_message_new_method_call(
278 "org.freedesktop.systemd1",
279 "/org/freedesktop/systemd1",
280 "org.freedesktop.systemd1.Manager",
281 "ListJobs"))) {
282 log_error("Could not allocate message.");
283 return -ENOMEM;
284 }
285
286 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
287 log_error("Failed to issue method call: %s", error.message);
288 r = -EIO;
289 goto finish;
290 }
291
292 if (!dbus_message_iter_init(reply, &iter) ||
293 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
294 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
295 log_error("Failed to parse reply.");
296 r = -EIO;
297 goto finish;
298 }
299
300 dbus_message_iter_recurse(&iter, &sub);
301
302 printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
303
304 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
305 const char *name, *type, *state, *job_path, *unit_path;
306 uint32_t id;
307
308 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
309 log_error("Failed to parse reply.");
310 r = -EIO;
311 goto finish;
312 }
313
314 dbus_message_iter_recurse(&sub, &sub2);
315
316 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
317 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
318 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
319 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
320 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
321 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
322 log_error("Failed to parse reply.");
323 r = -EIO;
324 goto finish;
325 }
326
327 printf("%4u %-45s %-17s %-7s\n", id, name, type, state);
328 k++;
329
330 dbus_message_iter_next(&sub);
331 }
332
333 printf("\n%u jobs listed.\n", k);
334 r = 0;
335
336 finish:
337 if (m)
338 dbus_message_unref(m);
339
340 if (reply)
341 dbus_message_unref(reply);
342
343 dbus_error_free(&error);
344
345 return r;
346 }
347
348 static int load_unit(DBusConnection *bus, char **args, unsigned n) {
349 DBusMessage *m = NULL, *reply = NULL;
350 DBusError error;
351 int r;
352 unsigned i;
353
354 dbus_error_init(&error);
355
356 assert(bus);
357 assert(args);
358
359 for (i = 1; i < n; i++) {
360
361 if (!(m = dbus_message_new_method_call(
362 "org.freedesktop.systemd1",
363 "/org/freedesktop/systemd1",
364 "org.freedesktop.systemd1.Manager",
365 "LoadUnit"))) {
366 log_error("Could not allocate message.");
367 r = -ENOMEM;
368 goto finish;
369 }
370
371 if (!dbus_message_append_args(m,
372 DBUS_TYPE_STRING, &args[i],
373 DBUS_TYPE_INVALID)) {
374 log_error("Could not append arguments to message.");
375 r = -ENOMEM;
376 goto finish;
377 }
378
379 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
380 log_error("Failed to issue method call: %s", error.message);
381 r = -EIO;
382 goto finish;
383 }
384
385 dbus_message_unref(m);
386 dbus_message_unref(reply);
387
388 m = reply = NULL;
389 }
390
391 r = 0;
392
393 finish:
394 if (m)
395 dbus_message_unref(m);
396
397 if (reply)
398 dbus_message_unref(reply);
399
400 dbus_error_free(&error);
401
402 return r;
403 }
404
405 static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
406 DBusMessage *m = NULL, *reply = NULL;
407 DBusError error;
408 int r;
409 unsigned i;
410
411 dbus_error_init(&error);
412
413 assert(bus);
414 assert(args);
415
416 for (i = 1; i < n; i++) {
417 unsigned id;
418 const char *path;
419
420 if (!(m = dbus_message_new_method_call(
421 "org.freedesktop.systemd1",
422 "/org/freedesktop/systemd1",
423 "org.freedesktop.systemd1.Manager",
424 "GetJob"))) {
425 log_error("Could not allocate message.");
426 r = -ENOMEM;
427 goto finish;
428 }
429
430 if ((r = safe_atou(args[i], &id)) < 0) {
431 log_error("Failed to parse job id: %s", strerror(-r));
432 goto finish;
433 }
434
435 assert_cc(sizeof(uint32_t) == sizeof(id));
436 if (!dbus_message_append_args(m,
437 DBUS_TYPE_UINT32, &id,
438 DBUS_TYPE_INVALID)) {
439 log_error("Could not append arguments to message.");
440 r = -ENOMEM;
441 goto finish;
442 }
443
444 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
445 log_error("Failed to issue method call: %s", error.message);
446 r = -EIO;
447 goto finish;
448 }
449
450 if (!dbus_message_get_args(reply, &error,
451 DBUS_TYPE_OBJECT_PATH, &path,
452 DBUS_TYPE_INVALID)) {
453 log_error("Failed to parse reply: %s", error.message);
454 r = -EIO;
455 goto finish;
456 }
457
458 dbus_message_unref(m);
459 if (!(m = dbus_message_new_method_call(
460 "org.freedesktop.systemd1",
461 path,
462 "org.freedesktop.systemd1.Job",
463 "Cancel"))) {
464 log_error("Could not allocate message.");
465 r = -ENOMEM;
466 goto finish;
467 }
468
469 dbus_message_unref(reply);
470 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
471 log_error("Failed to issue method call: %s", error.message);
472 r = -EIO;
473 goto finish;
474 }
475
476 dbus_message_unref(m);
477 dbus_message_unref(reply);
478 m = reply = NULL;
479 }
480
481 r = 0;
482
483 finish:
484 if (m)
485 dbus_message_unref(m);
486
487 if (reply)
488 dbus_message_unref(reply);
489
490 dbus_error_free(&error);
491
492 return r;
493 }
494
495 typedef struct WaitData {
496 Set *set;
497 bool failed;
498 } WaitData;
499
500 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
501 DBusError error;
502 WaitData *d = data;
503
504 assert(connection);
505 assert(message);
506 assert(d);
507
508 dbus_error_init(&error);
509
510 log_debug("Got D-Bus request: %s.%s() on %s",
511 dbus_message_get_interface(message),
512 dbus_message_get_member(message),
513 dbus_message_get_path(message));
514
515 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
516 log_error("Warning! D-Bus connection terminated.");
517 dbus_connection_close(connection);
518
519 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
520 uint32_t id;
521 const char *path;
522 dbus_bool_t success = true;
523
524 if (!dbus_message_get_args(message, &error,
525 DBUS_TYPE_UINT32, &id,
526 DBUS_TYPE_OBJECT_PATH, &path,
527 DBUS_TYPE_BOOLEAN, &success,
528 DBUS_TYPE_INVALID))
529 log_error("Failed to parse message: %s", error.message);
530 else {
531 char *p;
532
533 if ((p = set_remove(d->set, (char*) path)))
534 free(p);
535
536 if (!success)
537 d->failed = true;
538 }
539 }
540
541 dbus_error_free(&error);
542 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
543 }
544
545 static int enable_wait_for_jobs(DBusConnection *bus) {
546 DBusError error;
547
548 assert(bus);
549
550 if (private_bus)
551 return 0;
552
553 dbus_error_init(&error);
554 dbus_bus_add_match(bus,
555 "type='signal',"
556 "sender='org.freedesktop.systemd1',"
557 "interface='org.freedesktop.systemd1.Manager',"
558 "member='JobRemoved',"
559 "path='/org/freedesktop/systemd1'",
560 &error);
561
562 if (dbus_error_is_set(&error)) {
563 log_error("Failed to add match: %s", error.message);
564 dbus_error_free(&error);
565 return -EIO;
566 }
567
568 /* This is slightly dirty, since we don't undo the match registrations. */
569 return 0;
570 }
571
572 static int wait_for_jobs(DBusConnection *bus, Set *s) {
573 int r;
574 WaitData d;
575
576 assert(bus);
577 assert(s);
578
579 zero(d);
580 d.set = s;
581 d.failed = false;
582
583 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
584 log_error("Failed to add filter.");
585 r = -ENOMEM;
586 goto finish;
587 }
588
589 while (!set_isempty(s) &&
590 dbus_connection_read_write_dispatch(bus, -1))
591 ;
592
593 if (!arg_quiet && d.failed)
594 log_error("Job failed, see logs for details.");
595
596 r = d.failed ? -EIO : 0;
597
598 finish:
599 /* This is slightly dirty, since we don't undo the filter registration. */
600
601 return r;
602 }
603
604 static int start_unit_one(
605 DBusConnection *bus,
606 const char *method,
607 const char *name,
608 const char *mode,
609 Set *s) {
610
611 DBusMessage *m = NULL, *reply = NULL;
612 DBusError error;
613 int r;
614
615 assert(bus);
616 assert(method);
617 assert(name);
618 assert(mode);
619 assert(arg_no_block || s);
620
621 dbus_error_init(&error);
622
623 if (!(m = dbus_message_new_method_call(
624 "org.freedesktop.systemd1",
625 "/org/freedesktop/systemd1",
626 "org.freedesktop.systemd1.Manager",
627 method))) {
628 log_error("Could not allocate message.");
629 r = -ENOMEM;
630 goto finish;
631 }
632
633 if (!dbus_message_append_args(m,
634 DBUS_TYPE_STRING, &name,
635 DBUS_TYPE_STRING, &mode,
636 DBUS_TYPE_INVALID)) {
637 log_error("Could not append arguments to message.");
638 r = -ENOMEM;
639 goto finish;
640 }
641
642 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
643
644 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
645 /* There's always a fallback possible for
646 * legacy actions. */
647 r = 0;
648 goto finish;
649 }
650
651 log_error("Failed to issue method call: %s", error.message);
652 r = -EIO;
653 goto finish;
654 }
655
656 if (!arg_no_block) {
657 const char *path;
658 char *p;
659
660 if (!dbus_message_get_args(reply, &error,
661 DBUS_TYPE_OBJECT_PATH, &path,
662 DBUS_TYPE_INVALID)) {
663 log_error("Failed to parse reply: %s", error.message);
664 r = -EIO;
665 goto finish;
666 }
667
668 if (!(p = strdup(path))) {
669 log_error("Failed to duplicate path.");
670 r = -ENOMEM;
671 goto finish;
672 }
673
674 if ((r = set_put(s, p)) < 0) {
675 free(p);
676 log_error("Failed to add path to set.");
677 goto finish;
678 }
679 }
680
681 r = 1;
682
683 finish:
684 if (m)
685 dbus_message_unref(m);
686
687 if (reply)
688 dbus_message_unref(reply);
689
690 dbus_error_free(&error);
691
692 return r;
693 }
694
695 static enum action verb_to_action(const char *verb) {
696 if (streq(verb, "halt"))
697 return ACTION_HALT;
698 else if (streq(verb, "poweroff"))
699 return ACTION_POWEROFF;
700 else if (streq(verb, "reboot"))
701 return ACTION_REBOOT;
702 else if (streq(verb, "rescue"))
703 return ACTION_RESCUE;
704 else if (streq(verb, "emergency"))
705 return ACTION_EMERGENCY;
706 else if (streq(verb, "default"))
707 return ACTION_DEFAULT;
708 else
709 return ACTION_INVALID;
710 }
711
712 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
713
714 static const char * const table[_ACTION_MAX] = {
715 [ACTION_HALT] = SPECIAL_HALT_TARGET,
716 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
717 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
718 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
719 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
720 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
721 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
722 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
723 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_SERVICE,
724 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
725 };
726
727 int r;
728 unsigned i;
729 const char *method, *mode, *one_name;
730 Set *s = NULL;
731
732 assert(bus);
733
734 if (arg_action == ACTION_SYSTEMCTL) {
735 method =
736 streq(args[0], "stop") ? "StopUnit" :
737 streq(args[0], "reload") ? "ReloadUnit" :
738 streq(args[0], "restart") ? "RestartUnit" :
739 "StartUnit";
740
741 mode =
742 (streq(args[0], "isolate") ||
743 streq(args[0], "rescue") ||
744 streq(args[0], "emergency")) ? "isolate" :
745 arg_fail ? "fail" :
746 "replace";
747
748 one_name = table[verb_to_action(args[0])];
749
750 } else {
751 assert(arg_action < ELEMENTSOF(table));
752 assert(table[arg_action]);
753
754 method = "StartUnit";
755
756 mode = (arg_action == ACTION_EMERGENCY ||
757 arg_action == ACTION_RESCUE) ? "isolate" : "replace";
758
759 one_name = table[arg_action];
760 }
761
762 if (!arg_no_block) {
763 if ((r = enable_wait_for_jobs(bus)) < 0) {
764 log_error("Could not watch jobs: %s", strerror(-r));
765 goto finish;
766 }
767
768 if (!(s = set_new(string_hash_func, string_compare_func))) {
769 log_error("Failed to allocate set.");
770 r = -ENOMEM;
771 goto finish;
772 }
773 }
774
775 r = 0;
776
777 if (one_name) {
778 if ((r = start_unit_one(bus, method, one_name, mode, s)) <= 0)
779 goto finish;
780 } else {
781 for (i = 1; i < n; i++)
782 if ((r = start_unit_one(bus, method, args[i], mode, s)) < 0)
783 goto finish;
784 }
785
786 if (!arg_no_block)
787 r = wait_for_jobs(bus, s);
788
789 finish:
790 if (s)
791 set_free_free(s);
792
793 return r;
794 }
795
796 static int start_special(DBusConnection *bus, char **args, unsigned n) {
797 int r;
798
799 assert(bus);
800 assert(args);
801
802 r = start_unit(bus, args, n);
803
804 if (r >= 0)
805 warn_wall(verb_to_action(args[0]));
806
807 return r;
808 }
809
810 static int check_unit(DBusConnection *bus, char **args, unsigned n) {
811 DBusMessage *m = NULL, *reply = NULL;
812 const char
813 *interface = "org.freedesktop.systemd1.Unit",
814 *property = "ActiveState";
815 int r = -EADDRNOTAVAIL;
816 DBusError error;
817 unsigned i;
818
819 assert(bus);
820 assert(args);
821
822 dbus_error_init(&error);
823
824 for (i = 1; i < n; i++) {
825 const char *path = NULL;
826 const char *state;
827 DBusMessageIter iter, sub;
828
829 if (!(m = dbus_message_new_method_call(
830 "org.freedesktop.systemd1",
831 "/org/freedesktop/systemd1",
832 "org.freedesktop.systemd1.Manager",
833 "GetUnit"))) {
834 log_error("Could not allocate message.");
835 r = -ENOMEM;
836 goto finish;
837 }
838
839 if (!dbus_message_append_args(m,
840 DBUS_TYPE_STRING, &args[i],
841 DBUS_TYPE_INVALID)) {
842 log_error("Could not append arguments to message.");
843 r = -ENOMEM;
844 goto finish;
845 }
846
847 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
848
849 /* Hmm, cannot figure out anything about this unit... */
850 if (!arg_quiet)
851 puts("unknown");
852
853 dbus_error_free(&error);
854 continue;
855 }
856
857 if (!dbus_message_get_args(reply, &error,
858 DBUS_TYPE_OBJECT_PATH, &path,
859 DBUS_TYPE_INVALID)) {
860 log_error("Failed to parse reply: %s", error.message);
861 r = -EIO;
862 goto finish;
863 }
864
865 dbus_message_unref(m);
866 if (!(m = dbus_message_new_method_call(
867 "org.freedesktop.systemd1",
868 path,
869 "org.freedesktop.DBus.Properties",
870 "Get"))) {
871 log_error("Could not allocate message.");
872 r = -ENOMEM;
873 goto finish;
874 }
875
876 if (!dbus_message_append_args(m,
877 DBUS_TYPE_STRING, &interface,
878 DBUS_TYPE_STRING, &property,
879 DBUS_TYPE_INVALID)) {
880 log_error("Could not append arguments to message.");
881 r = -ENOMEM;
882 goto finish;
883 }
884
885 dbus_message_unref(reply);
886 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
887 log_error("Failed to issue method call: %s", error.message);
888 r = -EIO;
889 goto finish;
890 }
891
892 if (!dbus_message_iter_init(reply, &iter) ||
893 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
894 log_error("Failed to parse reply.");
895 r = -EIO;
896 goto finish;
897 }
898
899 dbus_message_iter_recurse(&iter, &sub);
900
901 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
902 log_error("Failed to parse reply.");
903 r = -EIO;
904 goto finish;
905 }
906
907 dbus_message_iter_get_basic(&sub, &state);
908
909 if (!arg_quiet)
910 puts(state);
911
912 if (streq(state, "active") || startswith(state, "reloading"))
913 r = 0;
914
915 dbus_message_unref(m);
916 dbus_message_unref(reply);
917 m = reply = NULL;
918 }
919
920 finish:
921 if (m)
922 dbus_message_unref(m);
923
924 if (reply)
925 dbus_message_unref(reply);
926
927 dbus_error_free(&error);
928
929 return r;
930 }
931
932 typedef struct ExecStatusInfo {
933 char *path;
934 char **argv;
935
936 bool ignore;
937
938 usec_t start_timestamp;
939 usec_t exit_timestamp;
940 pid_t pid;
941 int code;
942 int status;
943
944 LIST_FIELDS(struct ExecStatusInfo, exec);
945 } ExecStatusInfo;
946
947 static void exec_status_info_free(ExecStatusInfo *i) {
948 assert(i);
949
950 free(i->path);
951 strv_free(i->argv);
952 free(i);
953 }
954
955 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
956 uint64_t start_timestamp, exit_timestamp;
957 DBusMessageIter sub2, sub3;
958 const char*path;
959 unsigned n;
960 uint32_t pid;
961 int32_t code, status;
962 dbus_bool_t ignore;
963
964 assert(i);
965 assert(i);
966
967 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
968 return -EIO;
969
970 dbus_message_iter_recurse(sub, &sub2);
971
972 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
973 return -EIO;
974
975 if (!(i->path = strdup(path)))
976 return -ENOMEM;
977
978 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
979 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
980 return -EIO;
981
982 n = 0;
983 dbus_message_iter_recurse(&sub2, &sub3);
984 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
985 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
986 dbus_message_iter_next(&sub3);
987 n++;
988 }
989
990
991 if (!(i->argv = new0(char*, n+1)))
992 return -ENOMEM;
993
994 n = 0;
995 dbus_message_iter_recurse(&sub2, &sub3);
996 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
997 const char *s;
998
999 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1000 dbus_message_iter_get_basic(&sub3, &s);
1001 dbus_message_iter_next(&sub3);
1002
1003 if (!(i->argv[n++] = strdup(s)))
1004 return -ENOMEM;
1005 }
1006
1007 if (!dbus_message_iter_next(&sub2) ||
1008 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1009 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1010 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1011 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1012 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1013 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1014 return -EIO;
1015
1016 i->ignore = ignore;
1017 i->start_timestamp = (usec_t) start_timestamp;
1018 i->exit_timestamp = (usec_t) exit_timestamp;
1019 i->pid = (pid_t) pid;
1020 i->code = code;
1021 i->status = status;
1022
1023 return 0;
1024 }
1025
1026 typedef struct UnitStatusInfo {
1027 const char *id;
1028 const char *load_state;
1029 const char *active_state;
1030 const char *sub_state;
1031
1032 const char *description;
1033
1034 const char *fragment_path;
1035 const char *default_control_group;
1036
1037 /* Service */
1038 pid_t main_pid;
1039 pid_t control_pid;
1040 const char *status_text;
1041 bool running;
1042
1043 usec_t start_timestamp;
1044 usec_t exit_timestamp;
1045
1046 int exit_code, exit_status;
1047
1048 /* Socket */
1049 unsigned n_accepted;
1050 unsigned n_connections;
1051 bool accept;
1052
1053 /* Device */
1054 const char *sysfs_path;
1055
1056 /* Mount, Automount */
1057 const char *where;
1058
1059 /* Swap */
1060 const char *what;
1061
1062 LIST_HEAD(ExecStatusInfo, exec);
1063 } UnitStatusInfo;
1064
1065 static void print_status_info(UnitStatusInfo *i) {
1066 ExecStatusInfo *p;
1067 int r;
1068
1069 assert(i);
1070
1071 /* This shows pretty information about a unit. See
1072 * print_property() for a low-level property printer */
1073
1074 printf("%s", strna(i->id));
1075
1076 if (i->description && !streq_ptr(i->id, i->description))
1077 printf(" - %s", i->description);
1078
1079 printf("\n");
1080
1081 if (i->fragment_path)
1082 printf("\t Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
1083 else if (streq_ptr(i->load_state, "failed"))
1084 printf("\t Loaded: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n", strna(i->load_state));
1085 else
1086 printf("\t Loaded: %s\n", strna(i->load_state));
1087
1088 if (streq_ptr(i->active_state, "maintenance")) {
1089 if (streq_ptr(i->active_state, i->sub_state))
1090 printf("\t Active: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n",
1091 strna(i->active_state));
1092 else
1093 printf("\t Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
1094 strna(i->active_state),
1095 strna(i->sub_state));
1096 } else {
1097 if (streq_ptr(i->active_state, i->sub_state))
1098 printf("\t Active: %s\n",
1099 strna(i->active_state));
1100 else
1101 printf("\t Active: %s (%s)\n",
1102 strna(i->active_state),
1103 strna(i->sub_state));
1104 }
1105
1106 if (i->sysfs_path)
1107 printf("\t Device: %s\n", i->sysfs_path);
1108 else if (i->where)
1109 printf("\t Where: %s\n", i->where);
1110 else if (i->what)
1111 printf("\t What: %s\n", i->what);
1112
1113 if (i->accept)
1114 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1115
1116 LIST_FOREACH(exec, p, i->exec) {
1117 char *t;
1118
1119 /* Only show exited processes here */
1120 if (p->code == 0)
1121 continue;
1122
1123 t = strv_join(p->argv, " ");
1124 printf("\t Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
1125 free(t);
1126
1127 if (p->code == CLD_EXITED)
1128 printf("status=%i", p->status);
1129 else
1130 printf("signal=%s", signal_to_string(p->status));
1131 printf(")\n");
1132
1133 if (i->main_pid == p->pid &&
1134 i->start_timestamp == p->start_timestamp &&
1135 i->exit_timestamp == p->start_timestamp)
1136 /* Let's not show this twice */
1137 i->main_pid = 0;
1138
1139 if (p->pid == i->control_pid)
1140 i->control_pid = 0;
1141 }
1142
1143 if (i->main_pid > 0 || i->control_pid > 0) {
1144 printf("\t");
1145
1146 if (i->main_pid > 0) {
1147 printf(" Main: %u", (unsigned) i->main_pid);
1148
1149 if (i->running) {
1150 char *t = NULL;
1151 get_process_name(i->main_pid, &t);
1152 if (t) {
1153 printf(" (%s)", t);
1154 free(t);
1155 }
1156 } else {
1157 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1158
1159 if (i->exit_code == CLD_EXITED)
1160 printf("status=%i", i->exit_status);
1161 else
1162 printf("signal=%s", signal_to_string(i->exit_status));
1163 printf(")");
1164 }
1165 }
1166
1167 if (i->main_pid > 0 && i->control_pid > 0)
1168 printf(";");
1169
1170 if (i->control_pid > 0) {
1171 char *t = NULL;
1172
1173 printf(" Control: %u", (unsigned) i->control_pid);
1174
1175 get_process_name(i->control_pid, &t);
1176 if (t) {
1177 printf(" (%s)", t);
1178 free(t);
1179 }
1180 }
1181
1182 printf("\n");
1183 }
1184
1185 if (i->status_text)
1186 printf("\t Status: \"%s\"\n", i->status_text);
1187
1188 if (i->default_control_group) {
1189 unsigned c;
1190
1191 printf("\t CGroup: %s\n", i->default_control_group);
1192
1193 if ((c = columns()) > 18)
1194 c -= 18;
1195 else
1196 c = 0;
1197
1198 if ((r = cg_init()) < 0)
1199 log_error("Failed to initialize libcg: %s", strerror(-r));
1200 else
1201 show_cgroup_recursive(i->default_control_group, "\t\t ", c);
1202 }
1203 }
1204
1205 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
1206
1207 switch (dbus_message_iter_get_arg_type(iter)) {
1208
1209 case DBUS_TYPE_STRING: {
1210 const char *s;
1211
1212 dbus_message_iter_get_basic(iter, &s);
1213
1214 if (s[0]) {
1215 if (streq(name, "Id"))
1216 i->id = s;
1217 else if (streq(name, "LoadState"))
1218 i->load_state = s;
1219 else if (streq(name, "ActiveState"))
1220 i->active_state = s;
1221 else if (streq(name, "SubState"))
1222 i->sub_state = s;
1223 else if (streq(name, "Description"))
1224 i->description = s;
1225 else if (streq(name, "FragmentPath"))
1226 i->fragment_path = s;
1227 else if (streq(name, "DefaultControlGroup"))
1228 i->default_control_group = s;
1229 else if (streq(name, "StatusText"))
1230 i->status_text = s;
1231 else if (streq(name, "SysFSPath"))
1232 i->sysfs_path = s;
1233 else if (streq(name, "Where"))
1234 i->where = s;
1235 else if (streq(name, "What"))
1236 i->what = s;
1237 }
1238
1239 break;
1240 }
1241
1242 case DBUS_TYPE_BOOLEAN: {
1243 dbus_bool_t b;
1244
1245 dbus_message_iter_get_basic(iter, &b);
1246
1247 if (streq(name, "Accept"))
1248 i->accept = b;
1249
1250 break;
1251 }
1252
1253 case DBUS_TYPE_UINT32: {
1254 uint32_t u;
1255
1256 dbus_message_iter_get_basic(iter, &u);
1257
1258 if (streq(name, "MainPID")) {
1259 if (u > 0) {
1260 i->main_pid = (pid_t) u;
1261 i->running = true;
1262 }
1263 } else if (streq(name, "ControlPID"))
1264 i->control_pid = (pid_t) u;
1265 else if (streq(name, "ExecMainPID")) {
1266 if (u > 0)
1267 i->main_pid = (pid_t) u;
1268 } else if (streq(name, "NAccepted"))
1269 i->n_accepted = u;
1270 else if (streq(name, "NConnections"))
1271 i->n_connections = u;
1272
1273 break;
1274 }
1275
1276 case DBUS_TYPE_INT32: {
1277 int32_t j;
1278
1279 dbus_message_iter_get_basic(iter, &j);
1280
1281 if (streq(name, "ExecMainCode"))
1282 i->exit_code = (int) j;
1283 else if (streq(name, "ExecMainStatus"))
1284 i->exit_status = (int) j;
1285
1286 break;
1287 }
1288
1289 case DBUS_TYPE_UINT64: {
1290 uint64_t u;
1291
1292 dbus_message_iter_get_basic(iter, &u);
1293
1294 if (streq(name, "ExecMainStartTimestamp"))
1295 i->start_timestamp = (usec_t) u;
1296 else if (streq(name, "ExecMainExitTimestamp"))
1297 i->exit_timestamp = (usec_t) u;
1298
1299 break;
1300 }
1301
1302 case DBUS_TYPE_ARRAY: {
1303
1304 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
1305 startswith(name, "Exec")) {
1306 DBusMessageIter sub;
1307
1308 dbus_message_iter_recurse(iter, &sub);
1309 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1310 ExecStatusInfo *info;
1311 int r;
1312
1313 if (!(info = new0(ExecStatusInfo, 1)))
1314 return -ENOMEM;
1315
1316 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
1317 free(info);
1318 return r;
1319 }
1320
1321 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
1322
1323 dbus_message_iter_next(&sub);
1324 }
1325 }
1326
1327 break;
1328 }
1329 }
1330
1331 return 0;
1332 }
1333
1334 static int print_property(const char *name, DBusMessageIter *iter) {
1335 assert(name);
1336 assert(iter);
1337
1338 /* This is a low-level property printer, see
1339 * print_status_info() for the nicer output */
1340
1341 if (arg_property && !streq(name, arg_property))
1342 return 0;
1343
1344 switch (dbus_message_iter_get_arg_type(iter)) {
1345
1346 case DBUS_TYPE_STRING: {
1347 const char *s;
1348 dbus_message_iter_get_basic(iter, &s);
1349
1350 if (arg_all || s[0])
1351 printf("%s=%s\n", name, s);
1352
1353 return 0;
1354 }
1355
1356 case DBUS_TYPE_BOOLEAN: {
1357 dbus_bool_t b;
1358 dbus_message_iter_get_basic(iter, &b);
1359 printf("%s=%s\n", name, yes_no(b));
1360
1361 return 0;
1362 }
1363
1364 case DBUS_TYPE_UINT64: {
1365 uint64_t u;
1366 dbus_message_iter_get_basic(iter, &u);
1367
1368 /* Yes, heuristics! But we can change this check
1369 * should it turn out to not be sufficient */
1370
1371 if (strstr(name, "Timestamp")) {
1372 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1373
1374 if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
1375 printf("%s=%s\n", name, strempty(t));
1376 } else if (strstr(name, "USec")) {
1377 char timespan[FORMAT_TIMESPAN_MAX];
1378
1379 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1380 } else
1381 printf("%s=%llu\n", name, (unsigned long long) u);
1382
1383 return 0;
1384 }
1385
1386 case DBUS_TYPE_UINT32: {
1387 uint32_t u;
1388 dbus_message_iter_get_basic(iter, &u);
1389
1390 if (strstr(name, "UMask") || strstr(name, "Mode"))
1391 printf("%s=%04o\n", name, u);
1392 else
1393 printf("%s=%u\n", name, (unsigned) u);
1394
1395 return 0;
1396 }
1397
1398 case DBUS_TYPE_INT32: {
1399 int32_t i;
1400 dbus_message_iter_get_basic(iter, &i);
1401
1402 printf("%s=%i\n", name, (int) i);
1403 return 0;
1404 }
1405
1406 case DBUS_TYPE_STRUCT: {
1407 DBusMessageIter sub;
1408 dbus_message_iter_recurse(iter, &sub);
1409
1410 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
1411 uint32_t u;
1412
1413 dbus_message_iter_get_basic(&sub, &u);
1414
1415 if (u)
1416 printf("%s=%u\n", name, (unsigned) u);
1417 else if (arg_all)
1418 printf("%s=\n", name);
1419
1420 return 0;
1421 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
1422 const char *s;
1423
1424 dbus_message_iter_get_basic(&sub, &s);
1425
1426 if (arg_all || s[0])
1427 printf("%s=%s\n", name, s);
1428
1429 return 0;
1430 }
1431
1432 break;
1433 }
1434
1435 case DBUS_TYPE_ARRAY:
1436
1437 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1438 DBusMessageIter sub;
1439 bool space = false;
1440
1441 dbus_message_iter_recurse(iter, &sub);
1442 if (arg_all ||
1443 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1444 printf("%s=", name);
1445
1446 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1447 const char *s;
1448
1449 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1450 dbus_message_iter_get_basic(&sub, &s);
1451 printf("%s%s", space ? " " : "", s);
1452
1453 space = true;
1454 dbus_message_iter_next(&sub);
1455 }
1456
1457 puts("");
1458 }
1459
1460 return 0;
1461
1462 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1463 DBusMessageIter sub;
1464
1465 dbus_message_iter_recurse(iter, &sub);
1466 if (arg_all ||
1467 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1468 printf("%s=", name);
1469
1470 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1471 uint8_t u;
1472
1473 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1474 dbus_message_iter_get_basic(&sub, &u);
1475 printf("%02x", u);
1476
1477 dbus_message_iter_next(&sub);
1478 }
1479
1480 puts("");
1481 }
1482
1483 return 0;
1484
1485 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
1486 DBusMessageIter sub, sub2;
1487
1488 dbus_message_iter_recurse(iter, &sub);
1489 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1490 const char *type, *path;
1491
1492 dbus_message_iter_recurse(&sub, &sub2);
1493
1494 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
1495 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
1496 printf("%s=%s\n", type, path);
1497
1498 dbus_message_iter_next(&sub);
1499 }
1500
1501 return 0;
1502
1503 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
1504 DBusMessageIter sub, sub2;
1505
1506 dbus_message_iter_recurse(iter, &sub);
1507 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1508 const char *base;
1509 uint64_t value, next_elapse;
1510
1511 dbus_message_iter_recurse(&sub, &sub2);
1512
1513 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
1514 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
1515 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
1516 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
1517
1518 printf("%s={ value=%s ; next_elapse=%s }\n",
1519 base,
1520 format_timespan(timespan1, sizeof(timespan1), value),
1521 format_timespan(timespan2, sizeof(timespan2), next_elapse));
1522 }
1523
1524 dbus_message_iter_next(&sub);
1525 }
1526
1527 return 0;
1528
1529 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
1530 DBusMessageIter sub;
1531
1532 dbus_message_iter_recurse(iter, &sub);
1533 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1534 ExecStatusInfo info;
1535
1536 zero(info);
1537 if (exec_status_info_deserialize(&sub, &info) >= 0) {
1538 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
1539 char *t;
1540
1541 t = strv_join(info.argv, " ");
1542
1543 printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
1544 name,
1545 strna(info.path),
1546 strna(t),
1547 yes_no(info.ignore),
1548 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
1549 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
1550 (unsigned) info. pid,
1551 sigchld_code_to_string(info.code),
1552 info.status,
1553 info.code == CLD_EXITED ? "" : "/",
1554 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1555
1556 free(t);
1557 }
1558
1559 free(info.path);
1560 strv_free(info.argv);
1561
1562 dbus_message_iter_next(&sub);
1563 }
1564
1565 return 0;
1566 }
1567
1568 break;
1569 }
1570
1571 if (arg_all)
1572 printf("%s=[unprintable]\n", name);
1573
1574 return 0;
1575 }
1576
1577 static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
1578 DBusMessage *m = NULL, *reply = NULL;
1579 const char *interface = "";
1580 int r;
1581 DBusError error;
1582 DBusMessageIter iter, sub, sub2, sub3;
1583 UnitStatusInfo info;
1584 ExecStatusInfo *p;
1585
1586 assert(bus);
1587 assert(path);
1588 assert(new_line);
1589
1590 zero(info);
1591 dbus_error_init(&error);
1592
1593 if (!(m = dbus_message_new_method_call(
1594 "org.freedesktop.systemd1",
1595 path,
1596 "org.freedesktop.DBus.Properties",
1597 "GetAll"))) {
1598 log_error("Could not allocate message.");
1599 r = -ENOMEM;
1600 goto finish;
1601 }
1602
1603 if (!dbus_message_append_args(m,
1604 DBUS_TYPE_STRING, &interface,
1605 DBUS_TYPE_INVALID)) {
1606 log_error("Could not append arguments to message.");
1607 r = -ENOMEM;
1608 goto finish;
1609 }
1610
1611 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1612 log_error("Failed to issue method call: %s", error.message);
1613 r = -EIO;
1614 goto finish;
1615 }
1616
1617 if (!dbus_message_iter_init(reply, &iter) ||
1618 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1619 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
1620 log_error("Failed to parse reply.");
1621 r = -EIO;
1622 goto finish;
1623 }
1624
1625 dbus_message_iter_recurse(&iter, &sub);
1626
1627 if (*new_line)
1628 printf("\n");
1629
1630 *new_line = true;
1631
1632 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1633 const char *name;
1634
1635 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
1636 log_error("Failed to parse reply.");
1637 r = -EIO;
1638 goto finish;
1639 }
1640
1641 dbus_message_iter_recurse(&sub, &sub2);
1642
1643 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1644 log_error("Failed to parse reply.");
1645 r = -EIO;
1646 goto finish;
1647 }
1648
1649 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
1650 log_error("Failed to parse reply.");
1651 r = -EIO;
1652 goto finish;
1653 }
1654
1655 dbus_message_iter_recurse(&sub2, &sub3);
1656
1657 if (show_properties)
1658 r = print_property(name, &sub3);
1659 else
1660 r = status_property(name, &sub3, &info);
1661
1662 if (r < 0) {
1663 log_error("Failed to parse reply.");
1664 r = -EIO;
1665 goto finish;
1666 }
1667
1668 dbus_message_iter_next(&sub);
1669 }
1670
1671 if (!show_properties)
1672 print_status_info(&info);
1673
1674 while ((p = info.exec)) {
1675 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
1676 exec_status_info_free(p);
1677 }
1678
1679 r = 0;
1680
1681 finish:
1682 if (m)
1683 dbus_message_unref(m);
1684
1685 if (reply)
1686 dbus_message_unref(reply);
1687
1688 dbus_error_free(&error);
1689
1690 return r;
1691 }
1692
1693 static int show(DBusConnection *bus, char **args, unsigned n) {
1694 DBusMessage *m = NULL, *reply = NULL;
1695 int r;
1696 DBusError error;
1697 unsigned i;
1698 bool show_properties, new_line = false;
1699
1700 assert(bus);
1701 assert(args);
1702
1703 dbus_error_init(&error);
1704
1705 show_properties = !streq(args[0], "status");
1706
1707 if (show_properties && n <= 1) {
1708 /* If not argument is specified inspect the manager
1709 * itself */
1710
1711 r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
1712 goto finish;
1713 }
1714
1715 for (i = 1; i < n; i++) {
1716 const char *path = NULL;
1717 uint32_t id;
1718
1719 if (!show_properties || safe_atou32(args[i], &id) < 0) {
1720
1721 if (!(m = dbus_message_new_method_call(
1722 "org.freedesktop.systemd1",
1723 "/org/freedesktop/systemd1",
1724 "org.freedesktop.systemd1.Manager",
1725 "LoadUnit"))) {
1726 log_error("Could not allocate message.");
1727 r = -ENOMEM;
1728 goto finish;
1729 }
1730
1731 if (!dbus_message_append_args(m,
1732 DBUS_TYPE_STRING, &args[i],
1733 DBUS_TYPE_INVALID)) {
1734 log_error("Could not append arguments to message.");
1735 r = -ENOMEM;
1736 goto finish;
1737 }
1738
1739 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1740
1741 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
1742 log_error("Failed to issue method call: %s", error.message);
1743 r = -EIO;
1744 goto finish;
1745 }
1746
1747 dbus_error_free(&error);
1748
1749 dbus_message_unref(m);
1750 if (!(m = dbus_message_new_method_call(
1751 "org.freedesktop.systemd1",
1752 "/org/freedesktop/systemd1",
1753 "org.freedesktop.systemd1.Manager",
1754 "GetUnit"))) {
1755 log_error("Could not allocate message.");
1756 r = -ENOMEM;
1757 goto finish;
1758 }
1759
1760 if (!dbus_message_append_args(m,
1761 DBUS_TYPE_STRING, &args[i],
1762 DBUS_TYPE_INVALID)) {
1763 log_error("Could not append arguments to message.");
1764 r = -ENOMEM;
1765 goto finish;
1766 }
1767
1768 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1769 log_error("Failed to issue method call: %s", error.message);
1770 r = -EIO;
1771 goto finish;
1772 }
1773 }
1774
1775 } else {
1776
1777 if (!(m = dbus_message_new_method_call(
1778 "org.freedesktop.systemd1",
1779 "/org/freedesktop/systemd1",
1780 "org.freedesktop.systemd1.Manager",
1781 "GetJob"))) {
1782 log_error("Could not allocate message.");
1783 r = -ENOMEM;
1784 goto finish;
1785 }
1786
1787 if (!dbus_message_append_args(m,
1788 DBUS_TYPE_UINT32, &id,
1789 DBUS_TYPE_INVALID)) {
1790 log_error("Could not append arguments to message.");
1791 r = -ENOMEM;
1792 goto finish;
1793 }
1794
1795 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1796 log_error("Failed to issue method call: %s", error.message);
1797 r = -EIO;
1798 goto finish;
1799 }
1800 }
1801
1802 if (!dbus_message_get_args(reply, &error,
1803 DBUS_TYPE_OBJECT_PATH, &path,
1804 DBUS_TYPE_INVALID)) {
1805 log_error("Failed to parse reply: %s", error.message);
1806 r = -EIO;
1807 goto finish;
1808 }
1809
1810 if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
1811 goto finish;
1812
1813 dbus_message_unref(m);
1814 dbus_message_unref(reply);
1815 m = reply = NULL;
1816 }
1817
1818 r = 0;
1819
1820 finish:
1821 if (m)
1822 dbus_message_unref(m);
1823
1824 if (reply)
1825 dbus_message_unref(reply);
1826
1827 dbus_error_free(&error);
1828
1829 return r;
1830 }
1831
1832 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1833 DBusError error;
1834 DBusMessage *m = NULL, *reply = NULL;
1835
1836 assert(connection);
1837 assert(message);
1838
1839 dbus_error_init(&error);
1840
1841 log_debug("Got D-Bus request: %s.%s() on %s",
1842 dbus_message_get_interface(message),
1843 dbus_message_get_member(message),
1844 dbus_message_get_path(message));
1845
1846 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1847 log_error("Warning! D-Bus connection terminated.");
1848 dbus_connection_close(connection);
1849
1850 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
1851 dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
1852 const char *id, *path;
1853
1854 if (!dbus_message_get_args(message, &error,
1855 DBUS_TYPE_STRING, &id,
1856 DBUS_TYPE_OBJECT_PATH, &path,
1857 DBUS_TYPE_INVALID))
1858 log_error("Failed to parse message: %s", error.message);
1859 else if (streq(dbus_message_get_member(message), "UnitNew"))
1860 printf("Unit %s added.\n", id);
1861 else
1862 printf("Unit %s removed.\n", id);
1863
1864 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
1865 dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1866 uint32_t id;
1867 const char *path;
1868
1869 if (!dbus_message_get_args(message, &error,
1870 DBUS_TYPE_UINT32, &id,
1871 DBUS_TYPE_OBJECT_PATH, &path,
1872 DBUS_TYPE_INVALID))
1873 log_error("Failed to parse message: %s", error.message);
1874 else if (streq(dbus_message_get_member(message), "JobNew"))
1875 printf("Job %u added.\n", id);
1876 else
1877 printf("Job %u removed.\n", id);
1878
1879
1880 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
1881 dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
1882
1883 const char *path, *interface, *property = "Id";
1884 DBusMessageIter iter, sub;
1885
1886 path = dbus_message_get_path(message);
1887 interface = dbus_message_get_interface(message);
1888
1889 if (!(m = dbus_message_new_method_call(
1890 "org.freedesktop.systemd1",
1891 path,
1892 "org.freedesktop.DBus.Properties",
1893 "Get"))) {
1894 log_error("Could not allocate message.");
1895 goto oom;
1896 }
1897
1898 if (!dbus_message_append_args(m,
1899 DBUS_TYPE_STRING, &interface,
1900 DBUS_TYPE_STRING, &property,
1901 DBUS_TYPE_INVALID)) {
1902 log_error("Could not append arguments to message.");
1903 goto finish;
1904 }
1905
1906 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
1907 log_error("Failed to issue method call: %s", error.message);
1908 goto finish;
1909 }
1910
1911 if (!dbus_message_iter_init(reply, &iter) ||
1912 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1913 log_error("Failed to parse reply.");
1914 goto finish;
1915 }
1916
1917 dbus_message_iter_recurse(&iter, &sub);
1918
1919 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
1920 const char *id;
1921
1922 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1923 log_error("Failed to parse reply.");
1924 goto finish;
1925 }
1926
1927 dbus_message_iter_get_basic(&sub, &id);
1928 printf("Unit %s changed.\n", id);
1929 } else {
1930 uint32_t id;
1931
1932 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) {
1933 log_error("Failed to parse reply.");
1934 goto finish;
1935 }
1936
1937 dbus_message_iter_get_basic(&sub, &id);
1938 printf("Job %u changed.\n", id);
1939 }
1940 }
1941
1942 finish:
1943 if (m)
1944 dbus_message_unref(m);
1945
1946 if (reply)
1947 dbus_message_unref(reply);
1948
1949 dbus_error_free(&error);
1950 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1951
1952 oom:
1953 if (m)
1954 dbus_message_unref(m);
1955
1956 if (reply)
1957 dbus_message_unref(reply);
1958
1959 dbus_error_free(&error);
1960 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1961 }
1962
1963 static int monitor(DBusConnection *bus, char **args, unsigned n) {
1964 DBusMessage *m = NULL, *reply = NULL;
1965 DBusError error;
1966 int r;
1967
1968 dbus_error_init(&error);
1969
1970 if (!private_bus) {
1971 dbus_bus_add_match(bus,
1972 "type='signal',"
1973 "sender='org.freedesktop.systemd1',"
1974 "interface='org.freedesktop.systemd1.Manager',"
1975 "path='/org/freedesktop/systemd1'",
1976 &error);
1977
1978 if (dbus_error_is_set(&error)) {
1979 log_error("Failed to add match: %s", error.message);
1980 r = -EIO;
1981 goto finish;
1982 }
1983
1984 dbus_bus_add_match(bus,
1985 "type='signal',"
1986 "sender='org.freedesktop.systemd1',"
1987 "interface='org.freedesktop.systemd1.Unit',"
1988 "member='Changed'",
1989 &error);
1990
1991 if (dbus_error_is_set(&error)) {
1992 log_error("Failed to add match: %s", error.message);
1993 r = -EIO;
1994 goto finish;
1995 }
1996
1997 dbus_bus_add_match(bus,
1998 "type='signal',"
1999 "sender='org.freedesktop.systemd1',"
2000 "interface='org.freedesktop.systemd1.Job',"
2001 "member='Changed'",
2002 &error);
2003
2004 if (dbus_error_is_set(&error)) {
2005 log_error("Failed to add match: %s", error.message);
2006 r = -EIO;
2007 goto finish;
2008 }
2009 }
2010
2011 if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
2012 log_error("Failed to add filter.");
2013 r = -ENOMEM;
2014 goto finish;
2015 }
2016
2017 if (!(m = dbus_message_new_method_call(
2018 "org.freedesktop.systemd1",
2019 "/org/freedesktop/systemd1",
2020 "org.freedesktop.systemd1.Manager",
2021 "Subscribe"))) {
2022 log_error("Could not allocate message.");
2023 r = -ENOMEM;
2024 goto finish;
2025 }
2026
2027 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2028 log_error("Failed to issue method call: %s", error.message);
2029 r = -EIO;
2030 goto finish;
2031 }
2032
2033 while (dbus_connection_read_write_dispatch(bus, -1))
2034 ;
2035
2036 r = 0;
2037
2038 finish:
2039
2040 /* This is slightly dirty, since we don't undo the filter or the matches. */
2041
2042 if (m)
2043 dbus_message_unref(m);
2044
2045 if (reply)
2046 dbus_message_unref(reply);
2047
2048 dbus_error_free(&error);
2049
2050 return r;
2051 }
2052
2053 static int dump(DBusConnection *bus, char **args, unsigned n) {
2054 DBusMessage *m = NULL, *reply = NULL;
2055 DBusError error;
2056 int r;
2057 const char *text;
2058
2059 dbus_error_init(&error);
2060
2061 if (!(m = dbus_message_new_method_call(
2062 "org.freedesktop.systemd1",
2063 "/org/freedesktop/systemd1",
2064 "org.freedesktop.systemd1.Manager",
2065 "Dump"))) {
2066 log_error("Could not allocate message.");
2067 return -ENOMEM;
2068 }
2069
2070 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2071 log_error("Failed to issue method call: %s", error.message);
2072 r = -EIO;
2073 goto finish;
2074 }
2075
2076 if (!dbus_message_get_args(reply, &error,
2077 DBUS_TYPE_STRING, &text,
2078 DBUS_TYPE_INVALID)) {
2079 log_error("Failed to parse reply: %s", error.message);
2080 r = -EIO;
2081 goto finish;
2082 }
2083
2084 fputs(text, stdout);
2085
2086 r = 0;
2087
2088 finish:
2089 if (m)
2090 dbus_message_unref(m);
2091
2092 if (reply)
2093 dbus_message_unref(reply);
2094
2095 dbus_error_free(&error);
2096
2097 return r;
2098 }
2099
2100 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
2101 DBusMessage *m = NULL, *reply = NULL;
2102 DBusError error;
2103 int r;
2104 const char *name = "", *path, *id;
2105 dbus_bool_t cleanup = FALSE;
2106 DBusMessageIter iter, sub;
2107 const char
2108 *interface = "org.freedesktop.systemd1.Unit",
2109 *property = "Id";
2110
2111 dbus_error_init(&error);
2112
2113 if (!(m = dbus_message_new_method_call(
2114 "org.freedesktop.systemd1",
2115 "/org/freedesktop/systemd1",
2116 "org.freedesktop.systemd1.Manager",
2117 "CreateSnapshot"))) {
2118 log_error("Could not allocate message.");
2119 return -ENOMEM;
2120 }
2121
2122 if (n > 1)
2123 name = args[1];
2124
2125 if (!dbus_message_append_args(m,
2126 DBUS_TYPE_STRING, &name,
2127 DBUS_TYPE_BOOLEAN, &cleanup,
2128 DBUS_TYPE_INVALID)) {
2129 log_error("Could not append arguments to message.");
2130 r = -ENOMEM;
2131 goto finish;
2132 }
2133
2134 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2135 log_error("Failed to issue method call: %s", error.message);
2136 r = -EIO;
2137 goto finish;
2138 }
2139
2140 if (!dbus_message_get_args(reply, &error,
2141 DBUS_TYPE_OBJECT_PATH, &path,
2142 DBUS_TYPE_INVALID)) {
2143 log_error("Failed to parse reply: %s", error.message);
2144 r = -EIO;
2145 goto finish;
2146 }
2147
2148 dbus_message_unref(m);
2149 if (!(m = dbus_message_new_method_call(
2150 "org.freedesktop.systemd1",
2151 path,
2152 "org.freedesktop.DBus.Properties",
2153 "Get"))) {
2154 log_error("Could not allocate message.");
2155 return -ENOMEM;
2156 }
2157
2158 if (!dbus_message_append_args(m,
2159 DBUS_TYPE_STRING, &interface,
2160 DBUS_TYPE_STRING, &property,
2161 DBUS_TYPE_INVALID)) {
2162 log_error("Could not append arguments to message.");
2163 r = -ENOMEM;
2164 goto finish;
2165 }
2166
2167 dbus_message_unref(reply);
2168 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2169 log_error("Failed to issue method call: %s", error.message);
2170 r = -EIO;
2171 goto finish;
2172 }
2173
2174 if (!dbus_message_iter_init(reply, &iter) ||
2175 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2176 log_error("Failed to parse reply.");
2177 r = -EIO;
2178 goto finish;
2179 }
2180
2181 dbus_message_iter_recurse(&iter, &sub);
2182
2183 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2184 log_error("Failed to parse reply.");
2185 r = -EIO;
2186 goto finish;
2187 }
2188
2189 dbus_message_iter_get_basic(&sub, &id);
2190
2191 if (!arg_quiet)
2192 puts(id);
2193 r = 0;
2194
2195 finish:
2196 if (m)
2197 dbus_message_unref(m);
2198
2199 if (reply)
2200 dbus_message_unref(reply);
2201
2202 dbus_error_free(&error);
2203
2204 return r;
2205 }
2206
2207 static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
2208 DBusMessage *m = NULL, *reply = NULL;
2209 int r;
2210 DBusError error;
2211 unsigned i;
2212
2213 assert(bus);
2214 assert(args);
2215
2216 dbus_error_init(&error);
2217
2218 for (i = 1; i < n; i++) {
2219 const char *path = NULL;
2220
2221 if (!(m = dbus_message_new_method_call(
2222 "org.freedesktop.systemd1",
2223 "/org/freedesktop/systemd1",
2224 "org.freedesktop.systemd1.Manager",
2225 "GetUnit"))) {
2226 log_error("Could not allocate message.");
2227 r = -ENOMEM;
2228 goto finish;
2229 }
2230
2231 if (!dbus_message_append_args(m,
2232 DBUS_TYPE_STRING, &args[i],
2233 DBUS_TYPE_INVALID)) {
2234 log_error("Could not append arguments to message.");
2235 r = -ENOMEM;
2236 goto finish;
2237 }
2238
2239 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2240 log_error("Failed to issue method call: %s", error.message);
2241 r = -EIO;
2242 goto finish;
2243 }
2244
2245 if (!dbus_message_get_args(reply, &error,
2246 DBUS_TYPE_OBJECT_PATH, &path,
2247 DBUS_TYPE_INVALID)) {
2248 log_error("Failed to parse reply: %s", error.message);
2249 r = -EIO;
2250 goto finish;
2251 }
2252
2253 dbus_message_unref(m);
2254 if (!(m = dbus_message_new_method_call(
2255 "org.freedesktop.systemd1",
2256 path,
2257 "org.freedesktop.systemd1.Snapshot",
2258 "Remove"))) {
2259 log_error("Could not allocate message.");
2260 r = -ENOMEM;
2261 goto finish;
2262 }
2263
2264 dbus_message_unref(reply);
2265 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2266 log_error("Failed to issue method call: %s", error.message);
2267 r = -EIO;
2268 goto finish;
2269 }
2270
2271 dbus_message_unref(m);
2272 dbus_message_unref(reply);
2273 m = reply = NULL;
2274 }
2275
2276 r = 0;
2277
2278 finish:
2279 if (m)
2280 dbus_message_unref(m);
2281
2282 if (reply)
2283 dbus_message_unref(reply);
2284
2285 dbus_error_free(&error);
2286
2287 return r;
2288 }
2289
2290 static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
2291 DBusMessage *m = NULL, *reply = NULL;
2292 DBusError error;
2293 int r;
2294 const char *method;
2295
2296 dbus_error_init(&error);
2297
2298 if (arg_action == ACTION_RELOAD)
2299 method = "Reload";
2300 else if (arg_action == ACTION_REEXEC)
2301 method = "Reexecute";
2302 else {
2303 assert(arg_action == ACTION_SYSTEMCTL);
2304
2305 method =
2306 streq(args[0], "clear-jobs") ? "ClearJobs" :
2307 streq(args[0], "daemon-reload") ? "Reload" :
2308 streq(args[0], "daemon-reexec") ? "Reexecute" :
2309 "Exit";
2310 }
2311
2312 if (!(m = dbus_message_new_method_call(
2313 "org.freedesktop.systemd1",
2314 "/org/freedesktop/systemd1",
2315 "org.freedesktop.systemd1.Manager",
2316 method))) {
2317 log_error("Could not allocate message.");
2318 return -ENOMEM;
2319 }
2320
2321 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2322
2323 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2324 /* There's always a fallback possible for
2325 * legacy actions. */
2326 r = 0;
2327 goto finish;
2328 }
2329
2330 log_error("Failed to issue method call: %s", error.message);
2331 r = -EIO;
2332 goto finish;
2333 }
2334
2335 r = 1;
2336
2337 finish:
2338 if (m)
2339 dbus_message_unref(m);
2340
2341 if (reply)
2342 dbus_message_unref(reply);
2343
2344 dbus_error_free(&error);
2345
2346 return r;
2347 }
2348
2349 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
2350 DBusMessage *m = NULL, *reply = NULL;
2351 DBusError error;
2352 DBusMessageIter iter, sub, sub2;
2353 int r;
2354 const char
2355 *interface = "org.freedesktop.systemd1.Manager",
2356 *property = "Environment";
2357
2358 dbus_error_init(&error);
2359
2360 if (!(m = dbus_message_new_method_call(
2361 "org.freedesktop.systemd1",
2362 "/org/freedesktop/systemd1",
2363 "org.freedesktop.DBus.Properties",
2364 "Get"))) {
2365 log_error("Could not allocate message.");
2366 return -ENOMEM;
2367 }
2368
2369 if (!dbus_message_append_args(m,
2370 DBUS_TYPE_STRING, &interface,
2371 DBUS_TYPE_STRING, &property,
2372 DBUS_TYPE_INVALID)) {
2373 log_error("Could not append arguments to message.");
2374 r = -ENOMEM;
2375 goto finish;
2376 }
2377
2378 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2379 log_error("Failed to issue method call: %s", error.message);
2380 r = -EIO;
2381 goto finish;
2382 }
2383
2384 if (!dbus_message_iter_init(reply, &iter) ||
2385 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2386 log_error("Failed to parse reply.");
2387 r = -EIO;
2388 goto finish;
2389 }
2390
2391 dbus_message_iter_recurse(&iter, &sub);
2392
2393 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
2394 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
2395 log_error("Failed to parse reply.");
2396 r = -EIO;
2397 goto finish;
2398 }
2399
2400 dbus_message_iter_recurse(&sub, &sub2);
2401
2402 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
2403 const char *text;
2404
2405 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
2406 log_error("Failed to parse reply.");
2407 r = -EIO;
2408 goto finish;
2409 }
2410
2411 dbus_message_iter_get_basic(&sub2, &text);
2412 printf("%s\n", text);
2413
2414 dbus_message_iter_next(&sub2);
2415 }
2416
2417 r = 0;
2418
2419 finish:
2420 if (m)
2421 dbus_message_unref(m);
2422
2423 if (reply)
2424 dbus_message_unref(reply);
2425
2426 dbus_error_free(&error);
2427
2428 return r;
2429 }
2430
2431 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
2432 DBusMessage *m = NULL, *reply = NULL;
2433 DBusError error;
2434 int r;
2435 const char *method;
2436 DBusMessageIter iter, sub;
2437 unsigned i;
2438
2439 dbus_error_init(&error);
2440
2441 method = streq(args[0], "set-environment")
2442 ? "SetEnvironment"
2443 : "UnsetEnvironment";
2444
2445 if (!(m = dbus_message_new_method_call(
2446 "org.freedesktop.systemd1",
2447 "/org/freedesktop/systemd1",
2448 "org.freedesktop.systemd1.Manager",
2449 method))) {
2450
2451 log_error("Could not allocate message.");
2452 return -ENOMEM;
2453 }
2454
2455 dbus_message_iter_init_append(m, &iter);
2456
2457 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
2458 log_error("Could not append arguments to message.");
2459 r = -ENOMEM;
2460 goto finish;
2461 }
2462
2463 for (i = 1; i < n; i++)
2464 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
2465 log_error("Could not append arguments to message.");
2466 r = -ENOMEM;
2467 goto finish;
2468 }
2469
2470 if (!dbus_message_iter_close_container(&iter, &sub)) {
2471 log_error("Could not append arguments to message.");
2472 r = -ENOMEM;
2473 goto finish;
2474 }
2475
2476 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2477 log_error("Failed to issue method call: %s", error.message);
2478 r = -EIO;
2479 goto finish;
2480 }
2481
2482 r = 0;
2483
2484 finish:
2485 if (m)
2486 dbus_message_unref(m);
2487
2488 if (reply)
2489 dbus_message_unref(reply);
2490
2491 dbus_error_free(&error);
2492
2493 return r;
2494 }
2495
2496 static int systemctl_help(void) {
2497
2498 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2499 "Send control commands to the systemd manager.\n\n"
2500 " -h --help Show this help\n"
2501 " -t --type=TYPE List only units of a particular type\n"
2502 " -p --property=NAME Show only properties by this name\n"
2503 " -a --all Show all units/properties, including dead/empty ones\n"
2504 " --fail When installing a new job, fail if conflicting jobs are pending\n"
2505 " --system Connect to system bus\n"
2506 " --session Connect to session bus\n"
2507 " -q --quiet Suppress output\n"
2508 " --no-block Do not wait until operation finished\n"
2509 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
2510 "Commands:\n"
2511 " list-units List units\n"
2512 " start [NAME...] Start one or more units\n"
2513 " stop [NAME...] Stop one or more units\n"
2514 " restart [NAME...] Restart one or more units\n"
2515 " reload [NAME...] Reload one or more units\n"
2516 " isolate [NAME] Start one unit and stop all others\n"
2517 " check [NAME...] Check whether any of the passed units are active\n"
2518 " status [NAME...] Show status of one or more units\n"
2519 " show [NAME...|JOB...] Show properties of one or more units/jobs/manager\n"
2520 " load [NAME...] Load one or more units\n"
2521 " list-jobs List jobs\n"
2522 " cancel [JOB...] Cancel one or more jobs\n"
2523 " clear-jobs Cancel all jobs\n"
2524 " monitor Monitor unit/job changes\n"
2525 " dump Dump server status\n"
2526 " snapshot [NAME] Create a snapshot\n"
2527 " delete [NAME...] Remove one or more snapshots\n"
2528 " daemon-reload Reload systemd manager configuration\n"
2529 " daemon-reexec Reexecute systemd manager\n"
2530 " daemon-exit Ask the systemd manager to quit\n"
2531 " show-environment Dump environment\n"
2532 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
2533 " unset-environment [NAME...] Unset one or more environment variables\n"
2534 " halt Shut down and halt the system\n"
2535 " poweroff Shut down and power-off the system\n"
2536 " reboot Shut down and reboot the system\n"
2537 " default Enter default mode\n"
2538 " rescue Enter rescue mode\n"
2539 " emergency Enter emergency mode\n",
2540 program_invocation_short_name);
2541
2542 return 0;
2543 }
2544
2545 static int halt_help(void) {
2546
2547 printf("%s [OPTIONS...]\n\n"
2548 "%s the system.\n\n"
2549 " --help Show this help\n"
2550 " --halt Halt the machine\n"
2551 " -p --poweroff Switch off the machine\n"
2552 " --reboot Reboot the machine\n"
2553 " -f --force Force immediate halt/power-off/reboot\n"
2554 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
2555 " -d --no-wtmp Don't write wtmp record\n"
2556 " -n --no-sync Don't sync before halt/power-off/reboot\n"
2557 " --no-wall Don't send wall message before halt/power-off/reboot\n",
2558 program_invocation_short_name,
2559 arg_action == ACTION_REBOOT ? "Reboot" :
2560 arg_action == ACTION_POWEROFF ? "Power off" :
2561 "Halt");
2562
2563 return 0;
2564 }
2565
2566 static int shutdown_help(void) {
2567
2568 printf("%s [OPTIONS...] [now] [WALL...]\n\n"
2569 "Shut down the system.\n\n"
2570 " --help Show this help\n"
2571 " -H --halt Halt the machine\n"
2572 " -P --poweroff Power-off the machine\n"
2573 " -r --reboot Reboot the machine\n"
2574 " -h Equivalent to --poweroff, overriden by --halt\n"
2575 " -k Don't halt/power-off/reboot, just send warnings\n"
2576 " --no-wall Don't send wall message before halt/power-off/reboot\n",
2577 program_invocation_short_name);
2578
2579 return 0;
2580 }
2581
2582 static int telinit_help(void) {
2583
2584 printf("%s [OPTIONS...] {COMMAND}\n\n"
2585 "Send control commands to the init daemon.\n\n"
2586 " --help Show this help\n"
2587 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
2588 "Commands:\n"
2589 " 0 Power-off the machine\n"
2590 " 6 Reboot the machine\n"
2591 " 2, 3, 4, 5 Start runlevelX.target unit\n"
2592 " 1, s, S Enter rescue mode\n"
2593 " q, Q Reload init daemon configuration\n"
2594 " u, U Reexecute init daemon\n",
2595 program_invocation_short_name);
2596
2597 return 0;
2598 }
2599
2600 static int runlevel_help(void) {
2601
2602 printf("%s [OPTIONS...]\n\n"
2603 "Prints the previous and current runlevel of the init system.\n\n"
2604 " --help Show this help\n",
2605 program_invocation_short_name);
2606
2607 return 0;
2608 }
2609
2610 static int systemctl_parse_argv(int argc, char *argv[]) {
2611
2612 enum {
2613 ARG_FAIL = 0x100,
2614 ARG_SESSION,
2615 ARG_SYSTEM,
2616 ARG_NO_BLOCK,
2617 ARG_NO_WALL
2618 };
2619
2620 static const struct option options[] = {
2621 { "help", no_argument, NULL, 'h' },
2622 { "type", required_argument, NULL, 't' },
2623 { "property", required_argument, NULL, 'p' },
2624 { "all", no_argument, NULL, 'a' },
2625 { "fail", no_argument, NULL, ARG_FAIL },
2626 { "session", no_argument, NULL, ARG_SESSION },
2627 { "system", no_argument, NULL, ARG_SYSTEM },
2628 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
2629 { "no-wall", no_argument, NULL, ARG_NO_WALL },
2630 { "quiet", no_argument, NULL, 'q' },
2631 { NULL, 0, NULL, 0 }
2632 };
2633
2634 int c;
2635
2636 assert(argc >= 0);
2637 assert(argv);
2638
2639 while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
2640
2641 switch (c) {
2642
2643 case 'h':
2644 systemctl_help();
2645 return 0;
2646
2647 case 't':
2648 arg_type = optarg;
2649 break;
2650
2651 case 'p':
2652 arg_property = optarg;
2653
2654 /* If the user asked for a particular
2655 * property, show it to him, even if it is
2656 * empty. */
2657 arg_all = true;
2658 break;
2659
2660 case 'a':
2661 arg_all = true;
2662 break;
2663
2664 case ARG_FAIL:
2665 arg_fail = true;
2666 break;
2667
2668 case ARG_SESSION:
2669 arg_session = true;
2670 break;
2671
2672 case ARG_SYSTEM:
2673 arg_session = false;
2674 break;
2675
2676 case ARG_NO_BLOCK:
2677 arg_no_block = true;
2678 break;
2679
2680 case ARG_NO_WALL:
2681 arg_no_wall = true;
2682 break;
2683
2684 case 'q':
2685 arg_quiet = true;
2686 break;
2687
2688 case '?':
2689 return -EINVAL;
2690
2691 default:
2692 log_error("Unknown option code %c", c);
2693 return -EINVAL;
2694 }
2695 }
2696
2697 return 1;
2698 }
2699
2700 static int halt_parse_argv(int argc, char *argv[]) {
2701
2702 enum {
2703 ARG_HELP = 0x100,
2704 ARG_HALT,
2705 ARG_REBOOT,
2706 ARG_NO_WALL
2707 };
2708
2709 static const struct option options[] = {
2710 { "help", no_argument, NULL, ARG_HELP },
2711 { "halt", no_argument, NULL, ARG_HALT },
2712 { "poweroff", no_argument, NULL, 'p' },
2713 { "reboot", no_argument, NULL, ARG_REBOOT },
2714 { "force", no_argument, NULL, 'f' },
2715 { "wtmp-only", no_argument, NULL, 'w' },
2716 { "no-wtmp", no_argument, NULL, 'd' },
2717 { "no-sync", no_argument, NULL, 'n' },
2718 { "no-wall", no_argument, NULL, ARG_NO_WALL },
2719 { NULL, 0, NULL, 0 }
2720 };
2721
2722 int c, runlevel;
2723
2724 assert(argc >= 0);
2725 assert(argv);
2726
2727 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
2728 if (runlevel == '0' || runlevel == '6')
2729 arg_immediate = true;
2730
2731 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
2732 switch (c) {
2733
2734 case ARG_HELP:
2735 halt_help();
2736 return 0;
2737
2738 case ARG_HALT:
2739 arg_action = ACTION_HALT;
2740 break;
2741
2742 case 'p':
2743 arg_action = ACTION_POWEROFF;
2744 break;
2745
2746 case ARG_REBOOT:
2747 arg_action = ACTION_REBOOT;
2748 break;
2749
2750 case 'f':
2751 arg_immediate = true;
2752 break;
2753
2754 case 'w':
2755 arg_dry = true;
2756 break;
2757
2758 case 'd':
2759 arg_no_wtmp = true;
2760 break;
2761
2762 case 'n':
2763 arg_no_sync = true;
2764 break;
2765
2766 case ARG_NO_WALL:
2767 arg_no_wall = true;
2768 break;
2769
2770 case 'i':
2771 case 'h':
2772 /* Compatibility nops */
2773 break;
2774
2775 case '?':
2776 return -EINVAL;
2777
2778 default:
2779 log_error("Unknown option code %c", c);
2780 return -EINVAL;
2781 }
2782 }
2783
2784 if (optind < argc) {
2785 log_error("Too many arguments.");
2786 return -EINVAL;
2787 }
2788
2789 return 1;
2790 }
2791
2792 static int shutdown_parse_argv(int argc, char *argv[]) {
2793
2794 enum {
2795 ARG_HELP = 0x100,
2796 ARG_NO_WALL
2797 };
2798
2799 static const struct option options[] = {
2800 { "help", no_argument, NULL, ARG_HELP },
2801 { "halt", no_argument, NULL, 'H' },
2802 { "poweroff", no_argument, NULL, 'P' },
2803 { "reboot", no_argument, NULL, 'r' },
2804 { "no-wall", no_argument, NULL, ARG_NO_WALL },
2805 { NULL, 0, NULL, 0 }
2806 };
2807
2808 int c;
2809
2810 assert(argc >= 0);
2811 assert(argv);
2812
2813 while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
2814 switch (c) {
2815
2816 case ARG_HELP:
2817 shutdown_help();
2818 return 0;
2819
2820 case 'H':
2821 arg_action = ACTION_HALT;
2822 break;
2823
2824 case 'P':
2825 arg_action = ACTION_POWEROFF;
2826 break;
2827
2828 case 'r':
2829 arg_action = ACTION_REBOOT;
2830 break;
2831
2832 case 'h':
2833 if (arg_action != ACTION_HALT)
2834 arg_action = ACTION_POWEROFF;
2835 break;
2836
2837 case 'k':
2838 arg_dry = true;
2839 break;
2840
2841 case ARG_NO_WALL:
2842 arg_no_wall = true;
2843 break;
2844
2845 case 't':
2846 case 'a':
2847 /* Compatibility nops */
2848 break;
2849
2850 case '?':
2851 return -EINVAL;
2852
2853 default:
2854 log_error("Unknown option code %c", c);
2855 return -EINVAL;
2856 }
2857 }
2858
2859 if (argc > optind && !streq(argv[optind], "now"))
2860 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
2861
2862 /* We ignore the time argument */
2863 if (argc > optind + 1)
2864 arg_wall = argv + optind + 1;
2865
2866 optind = argc;
2867
2868 return 1;
2869 }
2870
2871 static int telinit_parse_argv(int argc, char *argv[]) {
2872
2873 enum {
2874 ARG_HELP = 0x100,
2875 ARG_NO_WALL
2876 };
2877
2878 static const struct option options[] = {
2879 { "help", no_argument, NULL, ARG_HELP },
2880 { "no-wall", no_argument, NULL, ARG_NO_WALL },
2881 { NULL, 0, NULL, 0 }
2882 };
2883
2884 static const struct {
2885 char from;
2886 enum action to;
2887 } table[] = {
2888 { '0', ACTION_POWEROFF },
2889 { '6', ACTION_REBOOT },
2890 { '1', ACTION_RESCUE },
2891 { '2', ACTION_RUNLEVEL2 },
2892 { '3', ACTION_RUNLEVEL3 },
2893 { '4', ACTION_RUNLEVEL4 },
2894 { '5', ACTION_RUNLEVEL5 },
2895 { 's', ACTION_RESCUE },
2896 { 'S', ACTION_RESCUE },
2897 { 'q', ACTION_RELOAD },
2898 { 'Q', ACTION_RELOAD },
2899 { 'u', ACTION_REEXEC },
2900 { 'U', ACTION_REEXEC }
2901 };
2902
2903 unsigned i;
2904 int c;
2905
2906 assert(argc >= 0);
2907 assert(argv);
2908
2909 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
2910 switch (c) {
2911
2912 case ARG_HELP:
2913 telinit_help();
2914 return 0;
2915
2916 case ARG_NO_WALL:
2917 arg_no_wall = true;
2918 break;
2919
2920 case '?':
2921 return -EINVAL;
2922
2923 default:
2924 log_error("Unknown option code %c", c);
2925 return -EINVAL;
2926 }
2927 }
2928
2929 if (optind >= argc) {
2930 telinit_help();
2931 return -EINVAL;
2932 }
2933
2934 if (optind + 1 < argc) {
2935 log_error("Too many arguments.");
2936 return -EINVAL;
2937 }
2938
2939 if (strlen(argv[optind]) != 1) {
2940 log_error("Expected single character argument.");
2941 return -EINVAL;
2942 }
2943
2944 for (i = 0; i < ELEMENTSOF(table); i++)
2945 if (table[i].from == argv[optind][0])
2946 break;
2947
2948 if (i >= ELEMENTSOF(table)) {
2949 log_error("Unknown command %s.", argv[optind]);
2950 return -EINVAL;
2951 }
2952
2953 arg_action = table[i].to;
2954
2955 optind ++;
2956
2957 return 1;
2958 }
2959
2960 static int runlevel_parse_argv(int argc, char *argv[]) {
2961
2962 enum {
2963 ARG_HELP = 0x100,
2964 };
2965
2966 static const struct option options[] = {
2967 { "help", no_argument, NULL, ARG_HELP },
2968 { NULL, 0, NULL, 0 }
2969 };
2970
2971 int c;
2972
2973 assert(argc >= 0);
2974 assert(argv);
2975
2976 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
2977 switch (c) {
2978
2979 case ARG_HELP:
2980 runlevel_help();
2981 return 0;
2982
2983 case '?':
2984 return -EINVAL;
2985
2986 default:
2987 log_error("Unknown option code %c", c);
2988 return -EINVAL;
2989 }
2990 }
2991
2992 if (optind < argc) {
2993 log_error("Too many arguments.");
2994 return -EINVAL;
2995 }
2996
2997 return 1;
2998 }
2999
3000 static int parse_argv(int argc, char *argv[]) {
3001 assert(argc >= 0);
3002 assert(argv);
3003
3004 if (program_invocation_short_name) {
3005
3006 if (strstr(program_invocation_short_name, "halt")) {
3007 arg_action = ACTION_HALT;
3008 return halt_parse_argv(argc, argv);
3009 } else if (strstr(program_invocation_short_name, "poweroff")) {
3010 arg_action = ACTION_POWEROFF;
3011 return halt_parse_argv(argc, argv);
3012 } else if (strstr(program_invocation_short_name, "reboot")) {
3013 arg_action = ACTION_REBOOT;
3014 return halt_parse_argv(argc, argv);
3015 } else if (strstr(program_invocation_short_name, "shutdown")) {
3016 arg_action = ACTION_POWEROFF;
3017 return shutdown_parse_argv(argc, argv);
3018 } else if (strstr(program_invocation_short_name, "init")) {
3019 arg_action = ACTION_INVALID;
3020 return telinit_parse_argv(argc, argv);
3021 } else if (strstr(program_invocation_short_name, "runlevel")) {
3022 arg_action = ACTION_RUNLEVEL;
3023 return runlevel_parse_argv(argc, argv);
3024 }
3025 }
3026
3027 arg_action = ACTION_SYSTEMCTL;
3028 return systemctl_parse_argv(argc, argv);
3029 }
3030
3031 static int action_to_runlevel(void) {
3032
3033 static const char table[_ACTION_MAX] = {
3034 [ACTION_HALT] = '0',
3035 [ACTION_POWEROFF] = '0',
3036 [ACTION_REBOOT] = '6',
3037 [ACTION_RUNLEVEL2] = '2',
3038 [ACTION_RUNLEVEL3] = '3',
3039 [ACTION_RUNLEVEL4] = '4',
3040 [ACTION_RUNLEVEL5] = '5',
3041 [ACTION_RESCUE] = '1'
3042 };
3043
3044 assert(arg_action < _ACTION_MAX);
3045
3046 return table[arg_action];
3047 }
3048
3049 static int talk_upstart(void) {
3050 DBusMessage *m = NULL, *reply = NULL;
3051 DBusError error;
3052 int previous, rl, r;
3053 char
3054 env1_buf[] = "RUNLEVEL=X",
3055 env2_buf[] = "PREVLEVEL=X";
3056 char *env1 = env1_buf, *env2 = env2_buf;
3057 const char *emit = "runlevel";
3058 dbus_bool_t b_false = FALSE;
3059 DBusMessageIter iter, sub;
3060 DBusConnection *bus;
3061
3062 dbus_error_init(&error);
3063
3064 if (!(rl = action_to_runlevel()))
3065 return 0;
3066
3067 if (utmp_get_runlevel(&previous, NULL) < 0)
3068 previous = 'N';
3069
3070 if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
3071 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
3072 r = 0;
3073 goto finish;
3074 }
3075
3076 log_error("Failed to connect to Upstart bus: %s", error.message);
3077 r = -EIO;
3078 goto finish;
3079 }
3080
3081 if ((r = bus_check_peercred(bus)) < 0) {
3082 log_error("Failed to verify owner of bus.");
3083 goto finish;
3084 }
3085
3086 if (!(m = dbus_message_new_method_call(
3087 "com.ubuntu.Upstart",
3088 "/com/ubuntu/Upstart",
3089 "com.ubuntu.Upstart0_6",
3090 "EmitEvent"))) {
3091
3092 log_error("Could not allocate message.");
3093 r = -ENOMEM;
3094 goto finish;
3095 }
3096
3097 dbus_message_iter_init_append(m, &iter);
3098
3099 env1_buf[sizeof(env1_buf)-2] = rl;
3100 env2_buf[sizeof(env2_buf)-2] = previous;
3101
3102 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
3103 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
3104 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
3105 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
3106 !dbus_message_iter_close_container(&iter, &sub) ||
3107 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
3108 log_error("Could not append arguments to message.");
3109 r = -ENOMEM;
3110 goto finish;
3111 }
3112
3113 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3114
3115 if (error_is_no_service(&error)) {
3116 r = 0;
3117 goto finish;
3118 }
3119
3120 log_error("Failed to issue method call: %s", error.message);
3121 r = -EIO;
3122 goto finish;
3123 }
3124
3125 r = 1;
3126
3127 finish:
3128 if (m)
3129 dbus_message_unref(m);
3130
3131 if (reply)
3132 dbus_message_unref(reply);
3133
3134 if (bus) {
3135 dbus_connection_close(bus);
3136 dbus_connection_unref(bus);
3137 }
3138
3139 dbus_error_free(&error);
3140
3141 return r;
3142 }
3143
3144 static int talk_initctl(void) {
3145 struct init_request request;
3146 int r, fd;
3147 char rl;
3148
3149 if (!(rl = action_to_runlevel()))
3150 return 0;
3151
3152 zero(request);
3153 request.magic = INIT_MAGIC;
3154 request.sleeptime = 0;
3155 request.cmd = INIT_CMD_RUNLVL;
3156 request.runlevel = rl;
3157
3158 if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
3159
3160 if (errno == ENOENT)
3161 return 0;
3162
3163 log_error("Failed to open "INIT_FIFO": %m");
3164 return -errno;
3165 }
3166
3167 errno = 0;
3168 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
3169 close_nointr_nofail(fd);
3170
3171 if (r < 0) {
3172 log_error("Failed to write to "INIT_FIFO": %m");
3173 return errno ? -errno : -EIO;
3174 }
3175
3176 return 1;
3177 }
3178
3179 static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
3180
3181 static const struct {
3182 const char* verb;
3183 const enum {
3184 MORE,
3185 LESS,
3186 EQUAL
3187 } argc_cmp;
3188 const int argc;
3189 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
3190 } verbs[] = {
3191 { "list-units", LESS, 1, list_units },
3192 { "list-jobs", EQUAL, 1, list_jobs },
3193 { "clear-jobs", EQUAL, 1, clear_jobs },
3194 { "load", MORE, 2, load_unit },
3195 { "cancel", MORE, 2, cancel_job },
3196 { "start", MORE, 2, start_unit },
3197 { "stop", MORE, 2, start_unit },
3198 { "reload", MORE, 2, start_unit },
3199 { "restart", MORE, 2, start_unit },
3200 { "isolate", EQUAL, 2, start_unit },
3201 { "check", MORE, 2, check_unit },
3202 { "show", MORE, 1, show },
3203 { "status", MORE, 2, show },
3204 { "monitor", EQUAL, 1, monitor },
3205 { "dump", EQUAL, 1, dump },
3206 { "snapshot", LESS, 2, snapshot },
3207 { "delete", MORE, 2, delete_snapshot },
3208 { "daemon-reload", EQUAL, 1, clear_jobs },
3209 { "daemon-reexec", EQUAL, 1, clear_jobs },
3210 { "daemon-exit", EQUAL, 1, clear_jobs },
3211 { "show-environment", EQUAL, 1, show_enviroment },
3212 { "set-environment", MORE, 2, set_environment },
3213 { "unset-environment", MORE, 2, set_environment },
3214 { "halt", EQUAL, 1, start_special },
3215 { "poweroff", EQUAL, 1, start_special },
3216 { "reboot", EQUAL, 1, start_special },
3217 { "default", EQUAL, 1, start_special },
3218 { "rescue", EQUAL, 1, start_special },
3219 { "emergency", EQUAL, 1, start_special }
3220 };
3221
3222 int left;
3223 unsigned i;
3224
3225 assert(bus);
3226 assert(argc >= 0);
3227 assert(argv);
3228
3229 left = argc - optind;
3230
3231 if (left <= 0)
3232 /* Special rule: no arguments means "list-units" */
3233 i = 0;
3234 else {
3235 if (streq(argv[optind], "help")) {
3236 systemctl_help();
3237 return 0;
3238 }
3239
3240 for (i = 0; i < ELEMENTSOF(verbs); i++)
3241 if (streq(argv[optind], verbs[i].verb))
3242 break;
3243
3244 if (i >= ELEMENTSOF(verbs)) {
3245 log_error("Unknown operation %s", argv[optind]);
3246 return -EINVAL;
3247 }
3248 }
3249
3250 switch (verbs[i].argc_cmp) {
3251
3252 case EQUAL:
3253 if (left != verbs[i].argc) {
3254 log_error("Invalid number of arguments.");
3255 return -EINVAL;
3256 }
3257
3258 break;
3259
3260 case MORE:
3261 if (left < verbs[i].argc) {
3262 log_error("Too few arguments.");
3263 return -EINVAL;
3264 }
3265
3266 break;
3267
3268 case LESS:
3269 if (left > verbs[i].argc) {
3270 log_error("Too many arguments.");
3271 return -EINVAL;
3272 }
3273
3274 break;
3275
3276 default:
3277 assert_not_reached("Unknown comparison operator.");
3278 }
3279
3280 return verbs[i].dispatch(bus, argv + optind, left);
3281 }
3282
3283 static int reload_with_fallback(DBusConnection *bus) {
3284 int r;
3285
3286 if (bus) {
3287 /* First, try systemd via D-Bus. */
3288 if ((r = clear_jobs(bus, NULL, 0)) > 0)
3289 return 0;
3290 }
3291
3292 /* Nothing else worked, so let's try signals */
3293 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
3294
3295 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
3296 log_error("kill() failed: %m");
3297 return -errno;
3298 }
3299
3300 return 0;
3301 }
3302
3303 static int start_with_fallback(DBusConnection *bus) {
3304 int r;
3305
3306
3307 if (bus) {
3308 /* First, try systemd via D-Bus. */
3309 if ((r = start_unit(bus, NULL, 0)) > 0)
3310 goto done;
3311
3312 /* Hmm, talking to systemd via D-Bus didn't work. Then
3313 * let's try to talk to Upstart via D-Bus. */
3314 if ((r = talk_upstart()) > 0)
3315 goto done;
3316 }
3317
3318 /* Nothing else worked, so let's try
3319 * /dev/initctl */
3320 if ((r = talk_initctl()) != 0)
3321 goto done;
3322
3323 log_error("Failed to talk to init daemon.");
3324 return -EIO;
3325
3326 done:
3327 warn_wall(arg_action);
3328 return 0;
3329 }
3330
3331 static int halt_main(DBusConnection *bus) {
3332 int r;
3333
3334 if (geteuid() != 0) {
3335 log_error("Must to be root.");
3336 return -EPERM;
3337 }
3338
3339 if (!arg_dry && !arg_immediate)
3340 return start_with_fallback(bus);
3341
3342 if (!arg_no_wtmp)
3343 if ((r = utmp_put_shutdown(0)) < 0)
3344 log_warning("Failed to write utmp record: %s", strerror(-r));
3345
3346 if (!arg_no_sync)
3347 sync();
3348
3349 if (arg_dry)
3350 return 0;
3351
3352 /* Make sure C-A-D is handled by the kernel from this
3353 * point on... */
3354 reboot(RB_ENABLE_CAD);
3355
3356 switch (arg_action) {
3357
3358 case ACTION_HALT:
3359 log_info("Halting");
3360 reboot(RB_HALT_SYSTEM);
3361 break;
3362
3363 case ACTION_POWEROFF:
3364 log_info("Powering off");
3365 reboot(RB_POWER_OFF);
3366 break;
3367
3368 case ACTION_REBOOT:
3369 log_info("Rebooting");
3370 reboot(RB_AUTOBOOT);
3371 break;
3372
3373 default:
3374 assert_not_reached("Unknown halt action.");
3375 }
3376
3377 /* We should never reach this. */
3378 return -ENOSYS;
3379 }
3380
3381 static int runlevel_main(void) {
3382 int r, runlevel, previous;
3383
3384 if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
3385 printf("unknown");
3386 return r;
3387 }
3388
3389 printf("%c %c\n",
3390 previous <= 0 ? 'N' : previous,
3391 runlevel <= 0 ? 'N' : runlevel);
3392
3393 return 0;
3394 }
3395
3396 int main(int argc, char*argv[]) {
3397 int r, retval = 1;
3398 DBusConnection *bus = NULL;
3399 DBusError error;
3400
3401 dbus_error_init(&error);
3402
3403 log_parse_environment();
3404
3405 if ((r = parse_argv(argc, argv)) < 0)
3406 goto finish;
3407 else if (r == 0) {
3408 retval = 0;
3409 goto finish;
3410 }
3411
3412 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
3413 * let's shortcut this */
3414 if (arg_action == ACTION_RUNLEVEL) {
3415 retval = runlevel_main() < 0;
3416 goto finish;
3417 }
3418
3419 bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
3420
3421 switch (arg_action) {
3422
3423 case ACTION_SYSTEMCTL: {
3424
3425 if (!bus) {
3426 log_error("Failed to get D-Bus connection: %s", error.message);
3427 goto finish;
3428 }
3429
3430 retval = systemctl_main(bus, argc, argv) < 0;
3431 break;
3432 }
3433
3434 case ACTION_HALT:
3435 case ACTION_POWEROFF:
3436 case ACTION_REBOOT:
3437 retval = halt_main(bus) < 0;
3438 break;
3439
3440 case ACTION_RUNLEVEL2:
3441 case ACTION_RUNLEVEL3:
3442 case ACTION_RUNLEVEL4:
3443 case ACTION_RUNLEVEL5:
3444 case ACTION_RESCUE:
3445 case ACTION_EMERGENCY:
3446 case ACTION_DEFAULT:
3447 retval = start_with_fallback(bus) < 0;
3448 break;
3449
3450 case ACTION_RELOAD:
3451 case ACTION_REEXEC:
3452 retval = reload_with_fallback(bus) < 0;
3453 break;
3454
3455 case ACTION_INVALID:
3456 case ACTION_RUNLEVEL:
3457 default:
3458 assert_not_reached("Unknown action");
3459 }
3460
3461 finish:
3462
3463 if (bus) {
3464 dbus_connection_close(bus);
3465 dbus_connection_unref(bus);
3466 }
3467
3468 dbus_error_free(&error);
3469
3470 dbus_shutdown();
3471
3472 return retval;
3473 }