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