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