chiark / gitweb /
man: document that first param to ExecStart= cannot be variable substitution
[elogind.git] / src / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34
35 #include <dbus/dbus.h>
36
37 #include "log.h"
38 #include "util.h"
39 #include "macro.h"
40 #include "set.h"
41 #include "utmp-wtmp.h"
42 #include "special.h"
43 #include "initreq.h"
44 #include "strv.h"
45 #include "dbus-common.h"
46 #include "cgroup-show.h"
47 #include "cgroup-util.h"
48 #include "list.h"
49 #include "path-lookup.h"
50 #include "conf-parser.h"
51 #include "sd-daemon.h"
52 #include "shutdownd.h"
53 #include "exit-status.h"
54 #include "bus-errors.h"
55 #include "build.h"
56
57 static const char *arg_type = NULL;
58 static char **arg_property = NULL;
59 static bool arg_all = false;
60 static bool arg_fail = false;
61 static bool arg_session = false;
62 static bool arg_global = false;
63 static bool arg_immediate = false;
64 static bool arg_no_block = false;
65 static bool arg_no_wtmp = false;
66 static bool arg_no_sync = false;
67 static bool arg_no_wall = false;
68 static bool arg_no_reload = false;
69 static bool arg_dry = false;
70 static bool arg_quiet = false;
71 static bool arg_full = false;
72 static bool arg_force = false;
73 static bool arg_defaults = false;
74 static char **arg_wall = NULL;
75 static usec_t arg_when = 0;
76 static enum action {
77         ACTION_INVALID,
78         ACTION_SYSTEMCTL,
79         ACTION_HALT,
80         ACTION_POWEROFF,
81         ACTION_REBOOT,
82         ACTION_RUNLEVEL2,
83         ACTION_RUNLEVEL3,
84         ACTION_RUNLEVEL4,
85         ACTION_RUNLEVEL5,
86         ACTION_RESCUE,
87         ACTION_EMERGENCY,
88         ACTION_DEFAULT,
89         ACTION_RELOAD,
90         ACTION_REEXEC,
91         ACTION_RUNLEVEL,
92         ACTION_CANCEL_SHUTDOWN,
93         _ACTION_MAX
94 } arg_action = ACTION_SYSTEMCTL;
95 static enum dot {
96         DOT_ALL,
97         DOT_ORDER,
98         DOT_REQUIRE
99 } arg_dot = DOT_ALL;
100
101 static bool private_bus = false;
102
103 static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
104
105 static bool on_tty(void) {
106         static int t = -1;
107
108         if (_unlikely_(t < 0))
109                 t = isatty(STDOUT_FILENO) > 0;
110
111         return t;
112 }
113
114 static const char *ansi_highlight(bool b) {
115
116         if (!on_tty())
117                 return "";
118
119         return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
120 }
121
122 static const char *ansi_highlight_green(bool b) {
123
124         if (!on_tty())
125                 return "";
126
127         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
128 }
129
130 static bool error_is_no_service(const DBusError *error) {
131         assert(error);
132
133         if (!dbus_error_is_set(error))
134                 return false;
135
136         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
137                 return true;
138
139         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
140                 return true;
141
142         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
143 }
144
145 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
146         assert(error);
147
148         if (!dbus_error_is_set(error))
149                 return r;
150
151         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
152             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
153             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
154             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
155                 return EXIT_NOPERMISSION;
156
157         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
158                 return EXIT_NOTINSTALLED;
159
160         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
161             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
162                 return EXIT_NOTIMPLEMENTED;
163
164         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
165                 return EXIT_NOTCONFIGURED;
166
167         if (r != 0)
168                 return r;
169
170         return EXIT_FAILURE;
171 }
172
173 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
174
175         assert(iter);
176         assert(data);
177
178         if (dbus_message_iter_get_arg_type(iter) != type)
179                 return -EIO;
180
181         dbus_message_iter_get_basic(iter, data);
182
183         if (!dbus_message_iter_next(iter) != !next)
184                 return -EIO;
185
186         return 0;
187 }
188
189 static void warn_wall(enum action action) {
190         static const char *table[_ACTION_MAX] = {
191                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
192                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
193                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
194                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
195                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
196         };
197
198         if (arg_no_wall)
199                 return;
200
201         if (arg_wall) {
202                 char *p;
203
204                 if (!(p = strv_join(arg_wall, " "))) {
205                         log_error("Failed to join strings.");
206                         return;
207                 }
208
209                 if (*p) {
210                         utmp_wall(p);
211                         free(p);
212                         return;
213                 }
214
215                 free(p);
216         }
217
218         if (!table[action])
219                 return;
220
221         utmp_wall(table[action]);
222 }
223
224 struct unit_info {
225         const char *id;
226         const char *description;
227         const char *load_state;
228         const char *active_state;
229         const char *sub_state;
230         const char *following;
231         const char *unit_path;
232         uint32_t job_id;
233         const char *job_type;
234         const char *job_path;
235 };
236
237 static int compare_unit_info(const void *a, const void *b) {
238         const char *d1, *d2;
239         const struct unit_info *u = a, *v = b;
240
241         d1 = strrchr(u->id, '.');
242         d2 = strrchr(v->id, '.');
243
244         if (d1 && d2) {
245                 int r;
246
247                 if ((r = strcasecmp(d1, d2)) != 0)
248                         return r;
249         }
250
251         return strcasecmp(u->id, v->id);
252 }
253
254 static bool output_show_job(const struct unit_info *u) {
255         const char *dot;
256         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
257                               streq(dot+1, arg_type))) &&
258                 (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
259 }
260
261 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
262         unsigned active_len, sub_len, job_len;
263
264         active_len = strlen("ACTIVE");
265         sub_len = strlen("SUB");
266         job_len = strlen("JOB");
267         for (const struct unit_info *u = unit_infos; u < unit_infos + c; u++) {
268                 if (output_show_job(u)) {
269                         active_len = MAX(active_len, strlen(u->active_state));
270                         sub_len = MAX(sub_len, strlen(u->sub_state));
271                         if (u->job_id != 0)
272                                 job_len = MAX(job_len, strlen(u->job_type));
273                 }
274         }
275
276         if (on_tty()) {
277                 printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
278                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
279                 if (columns() >= 80+12 || arg_full)
280                         printf(" %s\n", "DESCRIPTION");
281                 else
282                         printf("\n");
283         }
284
285         for (const struct unit_info *u = unit_infos; u < unit_infos + c; u++) {
286                 if (output_show_job(u)) {
287                         char *e;
288                         int a = 0, b = 0;
289                         const char *on_loaded, *off_loaded;
290                         const char *on_active, *off_active;
291
292                         if (!streq(u->load_state, "loaded")) {
293                                 on_loaded = ansi_highlight(true);
294                                 off_loaded = ansi_highlight(false);
295                         } else
296                                 on_loaded = off_loaded = "";
297
298                         if (streq(u->active_state, "failed")) {
299                                 on_active = ansi_highlight(true);
300                                 off_active = ansi_highlight(false);
301                         } else
302                                 on_active = off_active = "";
303
304                         e = arg_full ? NULL : ellipsize(u->id, 25, 33);
305
306                         printf("%-25s %s%-6s%s %s%-*s %-*s%s%n",
307                                e ? e : u->id,
308                                on_loaded, u->load_state, off_loaded,
309                                on_active, active_len, u->active_state,
310                                           sub_len, u->sub_state, off_active,
311                                &a);
312
313                         free(e);
314
315                         a -= strlen(on_loaded) + strlen(off_loaded);
316                         a -= strlen(on_active) + strlen(off_active);
317
318                         if (u->job_id != 0)
319                                 printf(" %-*s", job_len, u->job_type);
320                         else
321                                 b = 1 + job_len;
322
323                         if (a + b + 1 < columns()) {
324                                 if (u->job_id == 0)
325                                         printf(" %-*s", job_len, "");
326
327                                 if (arg_full)
328                                         printf(" %s", u->description);
329                                 else
330                                         printf(" %.*s", columns() - a - b - 1, u->description);
331                         }
332
333                         fputs("\n", stdout);
334                 }
335         }
336
337         if (!on_tty()) {
338                 printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
339                        "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
340                        "SUB    = The low-level unit activation state, values depend on unit type.\n"
341                        "JOB    = Pending job for the unit.\n");
342
343                 if (arg_all)
344                         printf("\n%u units listed.\n", c);
345                 else
346                         printf("\n%u units listed. Pass --all to see inactive units, too.\n", c);
347         }
348 }
349
350 static int list_units(DBusConnection *bus, char **args, unsigned n) {
351         DBusMessage *m = NULL, *reply = NULL;
352         DBusError error;
353         int r;
354         DBusMessageIter iter, sub, sub2;
355         unsigned c = 0, n_units = 0;
356         struct unit_info *unit_infos = NULL;
357
358         dbus_error_init(&error);
359
360         assert(bus);
361
362         if (!(m = dbus_message_new_method_call(
363                               "org.freedesktop.systemd1",
364                               "/org/freedesktop/systemd1",
365                               "org.freedesktop.systemd1.Manager",
366                               "ListUnits"))) {
367                 log_error("Could not allocate message.");
368                 return -ENOMEM;
369         }
370
371         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
372                 log_error("Failed to issue method call: %s", bus_error_message(&error));
373                 r = -EIO;
374                 goto finish;
375         }
376
377         if (!dbus_message_iter_init(reply, &iter) ||
378             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
379             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
380                 log_error("Failed to parse reply.");
381                 r = -EIO;
382                 goto finish;
383         }
384
385         dbus_message_iter_recurse(&iter, &sub);
386
387         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
388                 struct unit_info *u;
389
390                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
391                         log_error("Failed to parse reply.");
392                         r = -EIO;
393                         goto finish;
394                 }
395
396                 if (c >= n_units) {
397                         struct unit_info *w;
398
399                         n_units = MAX(2*c, 16);
400                         w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
401
402                         if (!w) {
403                                 log_error("Failed to allocate unit array.");
404                                 r = -ENOMEM;
405                                 goto finish;
406                         }
407
408                         unit_infos = w;
409                 }
410
411                 u = unit_infos+c;
412
413                 dbus_message_iter_recurse(&sub, &sub2);
414
415                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
416                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
417                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
418                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
419                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
420                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
421                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
422                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
423                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
424                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
425                         log_error("Failed to parse reply.");
426                         r = -EIO;
427                         goto finish;
428                 }
429
430                 dbus_message_iter_next(&sub);
431                 c++;
432         }
433
434         qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
435         output_units_list(unit_infos, c);
436
437         r = 0;
438
439 finish:
440         if (m)
441                 dbus_message_unref(m);
442
443         if (reply)
444                 dbus_message_unref(reply);
445
446         free(unit_infos);
447
448         dbus_error_free(&error);
449
450         return r;
451 }
452
453 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
454         static const char * const colors[] = {
455                 "Requires",              "[color=\"black\"]",
456                 "RequiresOverridable",   "[color=\"black\"]",
457                 "Requisite",             "[color=\"darkblue\"]",
458                 "RequisiteOverridable",  "[color=\"darkblue\"]",
459                 "Wants",                 "[color=\"darkgrey\"]",
460                 "Conflicts",             "[color=\"red\"]",
461                 "ConflictedBy",          "[color=\"red\"]",
462                 "After",                 "[color=\"green\"]"
463         };
464
465         const char *c = NULL;
466         unsigned i;
467
468         assert(name);
469         assert(prop);
470         assert(iter);
471
472         for (i = 0; i < ELEMENTSOF(colors); i += 2)
473                 if (streq(colors[i], prop)) {
474                         c = colors[i+1];
475                         break;
476                 }
477
478         if (!c)
479                 return 0;
480
481         if (arg_dot != DOT_ALL)
482                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
483                         return 0;
484
485         switch (dbus_message_iter_get_arg_type(iter)) {
486
487         case DBUS_TYPE_ARRAY:
488
489                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
490                         DBusMessageIter sub;
491
492                         dbus_message_iter_recurse(iter, &sub);
493
494                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
495                                 const char *s;
496
497                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
498                                 dbus_message_iter_get_basic(&sub, &s);
499                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
500
501                                 dbus_message_iter_next(&sub);
502                         }
503
504                         return 0;
505                 }
506         }
507
508         return 0;
509 }
510
511 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
512         DBusMessage *m = NULL, *reply = NULL;
513         const char *interface = "org.freedesktop.systemd1.Unit";
514         int r;
515         DBusError error;
516         DBusMessageIter iter, sub, sub2, sub3;
517
518         assert(bus);
519         assert(path);
520
521         dbus_error_init(&error);
522
523         if (!(m = dbus_message_new_method_call(
524                               "org.freedesktop.systemd1",
525                               path,
526                               "org.freedesktop.DBus.Properties",
527                               "GetAll"))) {
528                 log_error("Could not allocate message.");
529                 r = -ENOMEM;
530                 goto finish;
531         }
532
533         if (!dbus_message_append_args(m,
534                                       DBUS_TYPE_STRING, &interface,
535                                       DBUS_TYPE_INVALID)) {
536                 log_error("Could not append arguments to message.");
537                 r = -ENOMEM;
538                 goto finish;
539         }
540
541         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
542                 log_error("Failed to issue method call: %s", bus_error_message(&error));
543                 r = -EIO;
544                 goto finish;
545         }
546
547         if (!dbus_message_iter_init(reply, &iter) ||
548             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
549             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
550                 log_error("Failed to parse reply.");
551                 r = -EIO;
552                 goto finish;
553         }
554
555         dbus_message_iter_recurse(&iter, &sub);
556
557         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
558                 const char *prop;
559
560                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
561                         log_error("Failed to parse reply.");
562                         r = -EIO;
563                         goto finish;
564                 }
565
566                 dbus_message_iter_recurse(&sub, &sub2);
567
568                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
569                         log_error("Failed to parse reply.");
570                         r = -EIO;
571                         goto finish;
572                 }
573
574                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
575                         log_error("Failed to parse reply.");
576                         r = -EIO;
577                         goto finish;
578                 }
579
580                 dbus_message_iter_recurse(&sub2, &sub3);
581
582                 if (dot_one_property(name, prop, &sub3)) {
583                         log_error("Failed to parse reply.");
584                         r = -EIO;
585                         goto finish;
586                 }
587
588                 dbus_message_iter_next(&sub);
589         }
590
591         r = 0;
592
593 finish:
594         if (m)
595                 dbus_message_unref(m);
596
597         if (reply)
598                 dbus_message_unref(reply);
599
600         dbus_error_free(&error);
601
602         return r;
603 }
604
605 static int dot(DBusConnection *bus, char **args, unsigned n) {
606         DBusMessage *m = NULL, *reply = NULL;
607         DBusError error;
608         int r;
609         DBusMessageIter iter, sub, sub2;
610
611         dbus_error_init(&error);
612
613         assert(bus);
614
615         if (!(m = dbus_message_new_method_call(
616                               "org.freedesktop.systemd1",
617                               "/org/freedesktop/systemd1",
618                               "org.freedesktop.systemd1.Manager",
619                               "ListUnits"))) {
620                 log_error("Could not allocate message.");
621                 return -ENOMEM;
622         }
623
624         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
625                 log_error("Failed to issue method call: %s", bus_error_message(&error));
626                 r = -EIO;
627                 goto finish;
628         }
629
630         if (!dbus_message_iter_init(reply, &iter) ||
631             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
632             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
633                 log_error("Failed to parse reply.");
634                 r = -EIO;
635                 goto finish;
636         }
637
638         printf("digraph systemd {\n");
639
640         dbus_message_iter_recurse(&iter, &sub);
641         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
642                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
643
644                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
645                         log_error("Failed to parse reply.");
646                         r = -EIO;
647                         goto finish;
648                 }
649
650                 dbus_message_iter_recurse(&sub, &sub2);
651
652                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
653                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
654                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
655                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
656                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
657                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
658                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
659                         log_error("Failed to parse reply.");
660                         r = -EIO;
661                         goto finish;
662                 }
663
664                 if ((r = dot_one(bus, id, unit_path)) < 0)
665                         goto finish;
666
667                 /* printf("\t\"%s\";\n", id); */
668                 dbus_message_iter_next(&sub);
669         }
670
671         printf("}\n");
672
673         log_info("   Color legend: black     = Requires\n"
674                  "                 dark blue = Requisite\n"
675                  "                 dark grey = Wants\n"
676                  "                 red       = Conflicts\n"
677                  "                 green     = After\n");
678
679         if (isatty(fileno(stdout)))
680                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
681                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
682
683         r = 0;
684
685 finish:
686         if (m)
687                 dbus_message_unref(m);
688
689         if (reply)
690                 dbus_message_unref(reply);
691
692         dbus_error_free(&error);
693
694         return r;
695 }
696
697 static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
698         DBusMessage *m = NULL, *reply = NULL;
699         DBusError error;
700         int r;
701         DBusMessageIter iter, sub, sub2;
702         unsigned k = 0;
703
704         dbus_error_init(&error);
705
706         assert(bus);
707
708         if (!(m = dbus_message_new_method_call(
709                               "org.freedesktop.systemd1",
710                               "/org/freedesktop/systemd1",
711                               "org.freedesktop.systemd1.Manager",
712                               "ListJobs"))) {
713                 log_error("Could not allocate message.");
714                 return -ENOMEM;
715         }
716
717         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
718                 log_error("Failed to issue method call: %s", bus_error_message(&error));
719                 r = -EIO;
720                 goto finish;
721         }
722
723         if (!dbus_message_iter_init(reply, &iter) ||
724             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
725             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
726                 log_error("Failed to parse reply.");
727                 r = -EIO;
728                 goto finish;
729         }
730
731         dbus_message_iter_recurse(&iter, &sub);
732
733         if (isatty(STDOUT_FILENO))
734                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
735
736         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
737                 const char *name, *type, *state, *job_path, *unit_path;
738                 uint32_t id;
739                 char *e;
740
741                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
742                         log_error("Failed to parse reply.");
743                         r = -EIO;
744                         goto finish;
745                 }
746
747                 dbus_message_iter_recurse(&sub, &sub2);
748
749                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
750                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
751                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
752                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
753                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
754                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
755                         log_error("Failed to parse reply.");
756                         r = -EIO;
757                         goto finish;
758                 }
759
760                 e = arg_full ? NULL : ellipsize(name, 25, 33);
761                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
762                 free(e);
763
764                 k++;
765
766                 dbus_message_iter_next(&sub);
767         }
768
769         if (isatty(STDOUT_FILENO))
770                 printf("\n%u jobs listed.\n", k);
771
772         r = 0;
773
774 finish:
775         if (m)
776                 dbus_message_unref(m);
777
778         if (reply)
779                 dbus_message_unref(reply);
780
781         dbus_error_free(&error);
782
783         return r;
784 }
785
786 static int load_unit(DBusConnection *bus, char **args, unsigned n) {
787         DBusMessage *m = NULL, *reply = NULL;
788         DBusError error;
789         int r;
790         unsigned i;
791
792         dbus_error_init(&error);
793
794         assert(bus);
795         assert(args);
796
797         for (i = 1; i < n; i++) {
798
799                 if (!(m = dbus_message_new_method_call(
800                                       "org.freedesktop.systemd1",
801                                       "/org/freedesktop/systemd1",
802                                       "org.freedesktop.systemd1.Manager",
803                                       "LoadUnit"))) {
804                         log_error("Could not allocate message.");
805                         r = -ENOMEM;
806                         goto finish;
807                 }
808
809                 if (!dbus_message_append_args(m,
810                                               DBUS_TYPE_STRING, &args[i],
811                                               DBUS_TYPE_INVALID)) {
812                         log_error("Could not append arguments to message.");
813                         r = -ENOMEM;
814                         goto finish;
815                 }
816
817                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
818                         log_error("Failed to issue method call: %s", bus_error_message(&error));
819                         r = -EIO;
820                         goto finish;
821                 }
822
823                 dbus_message_unref(m);
824                 dbus_message_unref(reply);
825
826                 m = reply = NULL;
827         }
828
829         r = 0;
830
831 finish:
832         if (m)
833                 dbus_message_unref(m);
834
835         if (reply)
836                 dbus_message_unref(reply);
837
838         dbus_error_free(&error);
839
840         return r;
841 }
842
843 static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
844         DBusMessage *m = NULL, *reply = NULL;
845         DBusError error;
846         int r;
847         unsigned i;
848
849         dbus_error_init(&error);
850
851         assert(bus);
852         assert(args);
853
854         if (n <= 1)
855                 return daemon_reload(bus, args, n);
856
857         for (i = 1; i < n; i++) {
858                 unsigned id;
859                 const char *path;
860
861                 if (!(m = dbus_message_new_method_call(
862                                       "org.freedesktop.systemd1",
863                                       "/org/freedesktop/systemd1",
864                                       "org.freedesktop.systemd1.Manager",
865                                       "GetJob"))) {
866                         log_error("Could not allocate message.");
867                         r = -ENOMEM;
868                         goto finish;
869                 }
870
871                 if ((r = safe_atou(args[i], &id)) < 0) {
872                         log_error("Failed to parse job id: %s", strerror(-r));
873                         goto finish;
874                 }
875
876                 assert_cc(sizeof(uint32_t) == sizeof(id));
877                 if (!dbus_message_append_args(m,
878                                               DBUS_TYPE_UINT32, &id,
879                                               DBUS_TYPE_INVALID)) {
880                         log_error("Could not append arguments to message.");
881                         r = -ENOMEM;
882                         goto finish;
883                 }
884
885                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
886                         log_error("Failed to issue method call: %s", bus_error_message(&error));
887                         r = -EIO;
888                         goto finish;
889                 }
890
891                 if (!dbus_message_get_args(reply, &error,
892                                            DBUS_TYPE_OBJECT_PATH, &path,
893                                            DBUS_TYPE_INVALID)) {
894                         log_error("Failed to parse reply: %s", bus_error_message(&error));
895                         r = -EIO;
896                         goto finish;
897                 }
898
899                 dbus_message_unref(m);
900                 if (!(m = dbus_message_new_method_call(
901                                       "org.freedesktop.systemd1",
902                                       path,
903                                       "org.freedesktop.systemd1.Job",
904                                       "Cancel"))) {
905                         log_error("Could not allocate message.");
906                         r = -ENOMEM;
907                         goto finish;
908                 }
909
910                 dbus_message_unref(reply);
911                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
912                         log_error("Failed to issue method call: %s", bus_error_message(&error));
913                         r = -EIO;
914                         goto finish;
915                 }
916
917                 dbus_message_unref(m);
918                 dbus_message_unref(reply);
919                 m = reply = NULL;
920         }
921
922         r = 0;
923
924 finish:
925         if (m)
926                 dbus_message_unref(m);
927
928         if (reply)
929                 dbus_message_unref(reply);
930
931         dbus_error_free(&error);
932
933         return r;
934 }
935
936 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
937         DBusMessage *m = NULL, *reply = NULL;
938         dbus_bool_t b = FALSE;
939         DBusMessageIter iter, sub;
940         const char
941                 *interface = "org.freedesktop.systemd1.Unit",
942                 *property = "NeedDaemonReload",
943                 *path;
944
945         /* We ignore all errors here, since this is used to show a warning only */
946
947         if (!(m = dbus_message_new_method_call(
948                               "org.freedesktop.systemd1",
949                               "/org/freedesktop/systemd1",
950                               "org.freedesktop.systemd1.Manager",
951                               "GetUnit")))
952                 goto finish;
953
954         if (!dbus_message_append_args(m,
955                                       DBUS_TYPE_STRING, &unit,
956                                       DBUS_TYPE_INVALID))
957                 goto finish;
958
959         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
960                 goto finish;
961
962         if (!dbus_message_get_args(reply, NULL,
963                                    DBUS_TYPE_OBJECT_PATH, &path,
964                                    DBUS_TYPE_INVALID))
965                 goto finish;
966
967         dbus_message_unref(m);
968         if (!(m = dbus_message_new_method_call(
969                               "org.freedesktop.systemd1",
970                               path,
971                               "org.freedesktop.DBus.Properties",
972                               "Get")))
973                 goto finish;
974
975         if (!dbus_message_append_args(m,
976                                       DBUS_TYPE_STRING, &interface,
977                                       DBUS_TYPE_STRING, &property,
978                                       DBUS_TYPE_INVALID)) {
979                 goto finish;
980         }
981
982         dbus_message_unref(reply);
983         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
984                 goto finish;
985
986         if (!dbus_message_iter_init(reply, &iter) ||
987             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
988                 goto finish;
989
990         dbus_message_iter_recurse(&iter, &sub);
991
992         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
993                 goto finish;
994
995         dbus_message_iter_get_basic(&sub, &b);
996
997 finish:
998         if (m)
999                 dbus_message_unref(m);
1000
1001         if (reply)
1002                 dbus_message_unref(reply);
1003
1004         return b;
1005 }
1006
1007 typedef struct WaitData {
1008         Set *set;
1009         bool failed;
1010 } WaitData;
1011
1012 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1013         DBusError error;
1014         WaitData *d = data;
1015
1016         assert(connection);
1017         assert(message);
1018         assert(d);
1019
1020         dbus_error_init(&error);
1021
1022         log_debug("Got D-Bus request: %s.%s() on %s",
1023                   dbus_message_get_interface(message),
1024                   dbus_message_get_member(message),
1025                   dbus_message_get_path(message));
1026
1027         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1028                 log_error("Warning! D-Bus connection terminated.");
1029                 dbus_connection_close(connection);
1030
1031         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1032                 uint32_t id;
1033                 const char *path;
1034                 dbus_bool_t success = true;
1035
1036                 if (!dbus_message_get_args(message, &error,
1037                                            DBUS_TYPE_UINT32, &id,
1038                                            DBUS_TYPE_OBJECT_PATH, &path,
1039                                            DBUS_TYPE_BOOLEAN, &success,
1040                                            DBUS_TYPE_INVALID))
1041                         log_error("Failed to parse message: %s", bus_error_message(&error));
1042                 else {
1043                         char *p;
1044
1045                         if ((p = set_remove(d->set, (char*) path)))
1046                                 free(p);
1047
1048                         if (!success)
1049                                 d->failed = true;
1050                 }
1051         }
1052
1053         dbus_error_free(&error);
1054         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1055 }
1056
1057 static int enable_wait_for_jobs(DBusConnection *bus) {
1058         DBusError error;
1059
1060         assert(bus);
1061
1062         if (private_bus)
1063                 return 0;
1064
1065         dbus_error_init(&error);
1066         dbus_bus_add_match(bus,
1067                            "type='signal',"
1068                            "sender='org.freedesktop.systemd1',"
1069                            "interface='org.freedesktop.systemd1.Manager',"
1070                            "member='JobRemoved',"
1071                            "path='/org/freedesktop/systemd1'",
1072                            &error);
1073
1074         if (dbus_error_is_set(&error)) {
1075                 log_error("Failed to add match: %s", bus_error_message(&error));
1076                 dbus_error_free(&error);
1077                 return -EIO;
1078         }
1079
1080         /* This is slightly dirty, since we don't undo the match registrations. */
1081         return 0;
1082 }
1083
1084 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1085         int r;
1086         WaitData d;
1087
1088         assert(bus);
1089         assert(s);
1090
1091         zero(d);
1092         d.set = s;
1093         d.failed = false;
1094
1095         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1096                 log_error("Failed to add filter.");
1097                 r = -ENOMEM;
1098                 goto finish;
1099         }
1100
1101         while (!set_isempty(s) &&
1102                dbus_connection_read_write_dispatch(bus, -1))
1103                 ;
1104
1105         if (!arg_quiet && d.failed)
1106                 log_error("Job failed, see system logs for details.");
1107
1108         r = d.failed ? -EIO : 0;
1109
1110 finish:
1111         /* This is slightly dirty, since we don't undo the filter registration. */
1112
1113         return r;
1114 }
1115
1116 static int start_unit_one(
1117                 DBusConnection *bus,
1118                 const char *method,
1119                 const char *name,
1120                 const char *mode,
1121                 DBusError *error,
1122                 Set *s) {
1123
1124         DBusMessage *m = NULL, *reply = NULL;
1125         const char *path;
1126         int r;
1127
1128         assert(bus);
1129         assert(method);
1130         assert(name);
1131         assert(mode);
1132         assert(error);
1133         assert(arg_no_block || s);
1134
1135         if (!(m = dbus_message_new_method_call(
1136                               "org.freedesktop.systemd1",
1137                               "/org/freedesktop/systemd1",
1138                               "org.freedesktop.systemd1.Manager",
1139                               method))) {
1140                 log_error("Could not allocate message.");
1141                 r = -ENOMEM;
1142                 goto finish;
1143         }
1144
1145         if (!dbus_message_append_args(m,
1146                                       DBUS_TYPE_STRING, &name,
1147                                       DBUS_TYPE_STRING, &mode,
1148                                       DBUS_TYPE_INVALID)) {
1149                 log_error("Could not append arguments to message.");
1150                 r = -ENOMEM;
1151                 goto finish;
1152         }
1153
1154         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1155
1156                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1157                         /* There's always a fallback possible for
1158                          * legacy actions. */
1159                         r = -EADDRNOTAVAIL;
1160                         goto finish;
1161                 }
1162
1163                 log_error("Failed to issue method call: %s", bus_error_message(error));
1164                 r = -EIO;
1165                 goto finish;
1166         }
1167
1168         if (!dbus_message_get_args(reply, error,
1169                                    DBUS_TYPE_OBJECT_PATH, &path,
1170                                    DBUS_TYPE_INVALID)) {
1171                 log_error("Failed to parse reply: %s", bus_error_message(error));
1172                 r = -EIO;
1173                 goto finish;
1174         }
1175
1176         if (need_daemon_reload(bus, name))
1177                 log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1178                             arg_session ? "--session" : "--system");
1179
1180         if (!arg_no_block) {
1181                 char *p;
1182
1183                 if (!(p = strdup(path))) {
1184                         log_error("Failed to duplicate path.");
1185                         r = -ENOMEM;
1186                         goto finish;
1187                 }
1188
1189                 if ((r = set_put(s, p)) < 0) {
1190                         free(p);
1191                         log_error("Failed to add path to set.");
1192                         goto finish;
1193                 }
1194         }
1195
1196         r = 0;
1197
1198 finish:
1199         if (m)
1200                 dbus_message_unref(m);
1201
1202         if (reply)
1203                 dbus_message_unref(reply);
1204
1205         return r;
1206 }
1207
1208 static enum action verb_to_action(const char *verb) {
1209         if (streq(verb, "halt"))
1210                 return ACTION_HALT;
1211         else if (streq(verb, "poweroff"))
1212                 return ACTION_POWEROFF;
1213         else if (streq(verb, "reboot"))
1214                 return ACTION_REBOOT;
1215         else if (streq(verb, "rescue"))
1216                 return ACTION_RESCUE;
1217         else if (streq(verb, "emergency"))
1218                 return ACTION_EMERGENCY;
1219         else if (streq(verb, "default"))
1220                 return ACTION_DEFAULT;
1221         else
1222                 return ACTION_INVALID;
1223 }
1224
1225 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
1226
1227         static const char * const table[_ACTION_MAX] = {
1228                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1229                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1230                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1231                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1232                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1233                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1234                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1235                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1236                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1237                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
1238         };
1239
1240         int r, ret = 0;
1241         unsigned i;
1242         const char *method, *mode, *one_name;
1243         Set *s = NULL;
1244         DBusError error;
1245
1246         dbus_error_init(&error);
1247
1248         assert(bus);
1249
1250         if (arg_action == ACTION_SYSTEMCTL) {
1251                 method =
1252                         streq(args[0], "stop")                  ? "StopUnit" :
1253                         streq(args[0], "reload")                ? "ReloadUnit" :
1254                         streq(args[0], "restart")               ? "RestartUnit" :
1255                         streq(args[0], "try-restart")           ? "TryRestartUnit" :
1256                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1257                         streq(args[0], "reload-or-try-restart") ||
1258                         streq(args[0], "force-reload")          ||
1259                         streq(args[0], "condrestart")           ? "ReloadOrTryRestartUnit" :
1260                                                                   "StartUnit";
1261
1262                 mode =
1263                         (streq(args[0], "isolate") ||
1264                          streq(args[0], "rescue")  ||
1265                          streq(args[0], "emergency")) ? "isolate" :
1266                                              arg_fail ? "fail" :
1267                                                         "replace";
1268
1269                 one_name = table[verb_to_action(args[0])];
1270
1271         } else {
1272                 assert(arg_action < ELEMENTSOF(table));
1273                 assert(table[arg_action]);
1274
1275                 method = "StartUnit";
1276
1277                 mode = (arg_action == ACTION_EMERGENCY ||
1278                         arg_action == ACTION_RESCUE ||
1279                         arg_action == ACTION_RUNLEVEL2 ||
1280                         arg_action == ACTION_RUNLEVEL3 ||
1281                         arg_action == ACTION_RUNLEVEL4 ||
1282                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1283
1284                 one_name = table[arg_action];
1285         }
1286
1287         if (!arg_no_block) {
1288                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1289                         log_error("Could not watch jobs: %s", strerror(-ret));
1290                         goto finish;
1291                 }
1292
1293                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1294                         log_error("Failed to allocate set.");
1295                         ret = -ENOMEM;
1296                         goto finish;
1297                 }
1298         }
1299
1300         if (one_name) {
1301                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1302                         goto finish;
1303         } else {
1304                 for (i = 1; i < n; i++)
1305                         if ((r = start_unit_one(bus, method, args[i], mode, &error, s)) != 0) {
1306                                 ret = translate_bus_error_to_exit_status(r, &error);
1307                                 dbus_error_free(&error);
1308                         }
1309         }
1310
1311         if (!arg_no_block)
1312                 if ((r = wait_for_jobs(bus, s)) < 0) {
1313                         ret = r;
1314                         goto finish;
1315                 }
1316
1317 finish:
1318         if (s)
1319                 set_free_free(s);
1320
1321         dbus_error_free(&error);
1322
1323         return ret;
1324 }
1325
1326 static int start_special(DBusConnection *bus, char **args, unsigned n) {
1327         int r;
1328
1329         assert(bus);
1330         assert(args);
1331
1332         r = start_unit(bus, args, n);
1333
1334         if (r >= 0)
1335                 warn_wall(verb_to_action(args[0]));
1336
1337         return r;
1338 }
1339
1340 static int check_unit(DBusConnection *bus, char **args, unsigned n) {
1341         DBusMessage *m = NULL, *reply = NULL;
1342         const char
1343                 *interface = "org.freedesktop.systemd1.Unit",
1344                 *property = "ActiveState";
1345         int r = 3; /* According to LSB: "program is not running" */
1346         DBusError error;
1347         unsigned i;
1348
1349         assert(bus);
1350         assert(args);
1351
1352         dbus_error_init(&error);
1353
1354         for (i = 1; i < n; i++) {
1355                 const char *path = NULL;
1356                 const char *state;
1357                 DBusMessageIter iter, sub;
1358
1359                 if (!(m = dbus_message_new_method_call(
1360                                       "org.freedesktop.systemd1",
1361                                       "/org/freedesktop/systemd1",
1362                                       "org.freedesktop.systemd1.Manager",
1363                                       "GetUnit"))) {
1364                         log_error("Could not allocate message.");
1365                         r = -ENOMEM;
1366                         goto finish;
1367                 }
1368
1369                 if (!dbus_message_append_args(m,
1370                                               DBUS_TYPE_STRING, &args[i],
1371                                               DBUS_TYPE_INVALID)) {
1372                         log_error("Could not append arguments to message.");
1373                         r = -ENOMEM;
1374                         goto finish;
1375                 }
1376
1377                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1378
1379                         /* Hmm, cannot figure out anything about this unit... */
1380                         if (!arg_quiet)
1381                                 puts("unknown");
1382
1383                         dbus_error_free(&error);
1384                         continue;
1385                 }
1386
1387                 if (!dbus_message_get_args(reply, &error,
1388                                            DBUS_TYPE_OBJECT_PATH, &path,
1389                                            DBUS_TYPE_INVALID)) {
1390                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1391                         r = -EIO;
1392                         goto finish;
1393                 }
1394
1395                 dbus_message_unref(m);
1396                 if (!(m = dbus_message_new_method_call(
1397                                       "org.freedesktop.systemd1",
1398                                       path,
1399                                       "org.freedesktop.DBus.Properties",
1400                                       "Get"))) {
1401                         log_error("Could not allocate message.");
1402                         r = -ENOMEM;
1403                         goto finish;
1404                 }
1405
1406                 if (!dbus_message_append_args(m,
1407                                               DBUS_TYPE_STRING, &interface,
1408                                               DBUS_TYPE_STRING, &property,
1409                                               DBUS_TYPE_INVALID)) {
1410                         log_error("Could not append arguments to message.");
1411                         r = -ENOMEM;
1412                         goto finish;
1413                 }
1414
1415                 dbus_message_unref(reply);
1416                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1417                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1418                         r = -EIO;
1419                         goto finish;
1420                 }
1421
1422                 if (!dbus_message_iter_init(reply, &iter) ||
1423                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1424                         log_error("Failed to parse reply.");
1425                         r = -EIO;
1426                         goto finish;
1427                 }
1428
1429                 dbus_message_iter_recurse(&iter, &sub);
1430
1431                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1432                         log_error("Failed to parse reply.");
1433                         r = -EIO;
1434                         goto finish;
1435                 }
1436
1437                 dbus_message_iter_get_basic(&sub, &state);
1438
1439                 if (!arg_quiet)
1440                         puts(state);
1441
1442                 if (streq(state, "active") || streq(state, "reloading"))
1443                         r = 0;
1444
1445                 dbus_message_unref(m);
1446                 dbus_message_unref(reply);
1447                 m = reply = NULL;
1448         }
1449
1450 finish:
1451         if (m)
1452                 dbus_message_unref(m);
1453
1454         if (reply)
1455                 dbus_message_unref(reply);
1456
1457         dbus_error_free(&error);
1458
1459         return r;
1460 }
1461
1462 typedef struct ExecStatusInfo {
1463         char *path;
1464         char **argv;
1465
1466         bool ignore;
1467
1468         usec_t start_timestamp;
1469         usec_t exit_timestamp;
1470         pid_t pid;
1471         int code;
1472         int status;
1473
1474         LIST_FIELDS(struct ExecStatusInfo, exec);
1475 } ExecStatusInfo;
1476
1477 static void exec_status_info_free(ExecStatusInfo *i) {
1478         assert(i);
1479
1480         free(i->path);
1481         strv_free(i->argv);
1482         free(i);
1483 }
1484
1485 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1486         uint64_t start_timestamp, exit_timestamp;
1487         DBusMessageIter sub2, sub3;
1488         const char*path;
1489         unsigned n;
1490         uint32_t pid;
1491         int32_t code, status;
1492         dbus_bool_t ignore;
1493
1494         assert(i);
1495         assert(i);
1496
1497         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1498                 return -EIO;
1499
1500         dbus_message_iter_recurse(sub, &sub2);
1501
1502         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1503                 return -EIO;
1504
1505         if (!(i->path = strdup(path)))
1506                 return -ENOMEM;
1507
1508         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1509             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1510                 return -EIO;
1511
1512         n = 0;
1513         dbus_message_iter_recurse(&sub2, &sub3);
1514         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1515                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1516                 dbus_message_iter_next(&sub3);
1517                 n++;
1518         }
1519
1520
1521         if (!(i->argv = new0(char*, n+1)))
1522                 return -ENOMEM;
1523
1524         n = 0;
1525         dbus_message_iter_recurse(&sub2, &sub3);
1526         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1527                 const char *s;
1528
1529                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1530                 dbus_message_iter_get_basic(&sub3, &s);
1531                 dbus_message_iter_next(&sub3);
1532
1533                 if (!(i->argv[n++] = strdup(s)))
1534                         return -ENOMEM;
1535         }
1536
1537         if (!dbus_message_iter_next(&sub2) ||
1538             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1539             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1540             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1541             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1542             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1543             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1544                 return -EIO;
1545
1546         i->ignore = ignore;
1547         i->start_timestamp = (usec_t) start_timestamp;
1548         i->exit_timestamp = (usec_t) exit_timestamp;
1549         i->pid = (pid_t) pid;
1550         i->code = code;
1551         i->status = status;
1552
1553         return 0;
1554 }
1555
1556 typedef struct UnitStatusInfo {
1557         const char *id;
1558         const char *load_state;
1559         const char *active_state;
1560         const char *sub_state;
1561
1562         const char *description;
1563
1564         const char *path;
1565         const char *default_control_group;
1566
1567         usec_t inactive_exit_timestamp;
1568         usec_t active_enter_timestamp;
1569         usec_t active_exit_timestamp;
1570         usec_t inactive_enter_timestamp;
1571
1572         bool need_daemon_reload;
1573
1574         /* Service */
1575         pid_t main_pid;
1576         pid_t control_pid;
1577         const char *status_text;
1578         bool running:1;
1579         bool is_sysv:1;
1580
1581         usec_t start_timestamp;
1582         usec_t exit_timestamp;
1583
1584         int exit_code, exit_status;
1585
1586         /* Socket */
1587         unsigned n_accepted;
1588         unsigned n_connections;
1589         bool accept;
1590
1591         /* Device */
1592         const char *sysfs_path;
1593
1594         /* Mount, Automount */
1595         const char *where;
1596
1597         /* Swap */
1598         const char *what;
1599
1600         LIST_HEAD(ExecStatusInfo, exec);
1601 } UnitStatusInfo;
1602
1603 static void print_status_info(UnitStatusInfo *i) {
1604         ExecStatusInfo *p;
1605         const char *on, *off, *ss;
1606         usec_t timestamp;
1607         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
1608         char since2[FORMAT_TIMESTAMP_MAX], *s2;
1609
1610         assert(i);
1611
1612         /* This shows pretty information about a unit. See
1613          * print_property() for a low-level property printer */
1614
1615         printf("%s", strna(i->id));
1616
1617         if (i->description && !streq_ptr(i->id, i->description))
1618                 printf(" - %s", i->description);
1619
1620         printf("\n");
1621
1622         if (streq_ptr(i->load_state, "failed")) {
1623                 on = ansi_highlight(true);
1624                 off = ansi_highlight(false);
1625         } else
1626                 on = off = "";
1627
1628         if (i->path)
1629                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
1630         else
1631                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
1632
1633         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
1634
1635         if (streq_ptr(i->active_state, "failed")) {
1636                 on = ansi_highlight(true);
1637                 off = ansi_highlight(false);
1638         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
1639                 on = ansi_highlight_green(true);
1640                 off = ansi_highlight_green(false);
1641         } else
1642                 on = off = "";
1643
1644         if (ss)
1645                 printf("\t  Active: %s%s (%s)%s",
1646                        on,
1647                        strna(i->active_state),
1648                        ss,
1649                        off);
1650         else
1651                 printf("\t  Active: %s%s%s",
1652                        on,
1653                        strna(i->active_state),
1654                        off);
1655
1656         timestamp = (streq_ptr(i->active_state, "active")      ||
1657                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
1658                     (streq_ptr(i->active_state, "inactive")    ||
1659                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
1660                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
1661                                                                   i->active_exit_timestamp;
1662
1663         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
1664         s2 = format_timestamp(since2, sizeof(since2), timestamp);
1665
1666         if (s1)
1667                 printf(" since [%s; %s]\n", s2, s1);
1668         else if (s2)
1669                 printf(" since [%s]\n", s2);
1670         else
1671                 printf("\n");
1672
1673         if (i->sysfs_path)
1674                 printf("\t  Device: %s\n", i->sysfs_path);
1675         else if (i->where)
1676                 printf("\t   Where: %s\n", i->where);
1677         else if (i->what)
1678                 printf("\t    What: %s\n", i->what);
1679
1680         if (i->accept)
1681                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1682
1683         LIST_FOREACH(exec, p, i->exec) {
1684                 char *t;
1685
1686                 /* Only show exited processes here */
1687                 if (p->code == 0)
1688                         continue;
1689
1690                 t = strv_join(p->argv, " ");
1691                 printf("\t Process: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
1692                 free(t);
1693
1694                 if (p->code == CLD_EXITED) {
1695                         const char *c;
1696
1697                         printf("status=%i", p->status);
1698
1699                         if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
1700                                 printf("/%s", c);
1701
1702                 } else
1703                         printf("signal=%s", signal_to_string(p->status));
1704                 printf(")\n");
1705
1706                 if (i->main_pid == p->pid &&
1707                     i->start_timestamp == p->start_timestamp &&
1708                     i->exit_timestamp == p->start_timestamp)
1709                         /* Let's not show this twice */
1710                         i->main_pid = 0;
1711
1712                 if (p->pid == i->control_pid)
1713                         i->control_pid = 0;
1714         }
1715
1716         if (i->main_pid > 0 || i->control_pid > 0) {
1717                 printf("\t");
1718
1719                 if (i->main_pid > 0) {
1720                         printf("Main PID: %u", (unsigned) i->main_pid);
1721
1722                         if (i->running) {
1723                                 char *t = NULL;
1724                                 get_process_name(i->main_pid, &t);
1725                                 if (t) {
1726                                         printf(" (%s)", t);
1727                                         free(t);
1728                                 }
1729                         } else if (i->exit_code > 0) {
1730                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1731
1732                                 if (i->exit_code == CLD_EXITED) {
1733                                         const char *c;
1734
1735                                         printf("status=%i", i->exit_status);
1736
1737                                         if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
1738                                                 printf("/%s", c);
1739
1740                                 } else
1741                                         printf("signal=%s", signal_to_string(i->exit_status));
1742                                 printf(")");
1743                         }
1744                 }
1745
1746                 if (i->main_pid > 0 && i->control_pid > 0)
1747                         printf(";");
1748
1749                 if (i->control_pid > 0) {
1750                         char *t = NULL;
1751
1752                         printf(" Control: %u", (unsigned) i->control_pid);
1753
1754                         get_process_name(i->control_pid, &t);
1755                         if (t) {
1756                                 printf(" (%s)", t);
1757                                 free(t);
1758                         }
1759                 }
1760
1761                 printf("\n");
1762         }
1763
1764         if (i->status_text)
1765                 printf("\t  Status: \"%s\"\n", i->status_text);
1766
1767         if (i->default_control_group) {
1768                 unsigned c;
1769
1770                 printf("\t  CGroup: %s\n", i->default_control_group);
1771
1772                 if ((c = columns()) > 18)
1773                         c -= 18;
1774                 else
1775                         c = 0;
1776
1777                 show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
1778         }
1779
1780         if (i->need_daemon_reload)
1781                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
1782                        ansi_highlight(true),
1783                        ansi_highlight(false),
1784                        arg_session ? "--session" : "--system");
1785 }
1786
1787 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
1788
1789         switch (dbus_message_iter_get_arg_type(iter)) {
1790
1791         case DBUS_TYPE_STRING: {
1792                 const char *s;
1793
1794                 dbus_message_iter_get_basic(iter, &s);
1795
1796                 if (s[0]) {
1797                         if (streq(name, "Id"))
1798                                 i->id = s;
1799                         else if (streq(name, "LoadState"))
1800                                 i->load_state = s;
1801                         else if (streq(name, "ActiveState"))
1802                                 i->active_state = s;
1803                         else if (streq(name, "SubState"))
1804                                 i->sub_state = s;
1805                         else if (streq(name, "Description"))
1806                                 i->description = s;
1807                         else if (streq(name, "FragmentPath"))
1808                                 i->path = s;
1809                         else if (streq(name, "SysVPath")) {
1810                                 i->is_sysv = true;
1811                                 i->path = s;
1812                         } else if (streq(name, "DefaultControlGroup"))
1813                                 i->default_control_group = s;
1814                         else if (streq(name, "StatusText"))
1815                                 i->status_text = s;
1816                         else if (streq(name, "SysFSPath"))
1817                                 i->sysfs_path = s;
1818                         else if (streq(name, "Where"))
1819                                 i->where = s;
1820                         else if (streq(name, "What"))
1821                                 i->what = s;
1822                 }
1823
1824                 break;
1825         }
1826
1827         case DBUS_TYPE_BOOLEAN: {
1828                 dbus_bool_t b;
1829
1830                 dbus_message_iter_get_basic(iter, &b);
1831
1832                 if (streq(name, "Accept"))
1833                         i->accept = b;
1834                 else if (streq(name, "NeedDaemonReload"))
1835                         i->need_daemon_reload = b;
1836
1837                 break;
1838         }
1839
1840         case DBUS_TYPE_UINT32: {
1841                 uint32_t u;
1842
1843                 dbus_message_iter_get_basic(iter, &u);
1844
1845                 if (streq(name, "MainPID")) {
1846                         if (u > 0) {
1847                                 i->main_pid = (pid_t) u;
1848                                 i->running = true;
1849                         }
1850                 } else if (streq(name, "ControlPID"))
1851                         i->control_pid = (pid_t) u;
1852                 else if (streq(name, "ExecMainPID")) {
1853                         if (u > 0)
1854                                 i->main_pid = (pid_t) u;
1855                 } else if (streq(name, "NAccepted"))
1856                         i->n_accepted = u;
1857                 else if (streq(name, "NConnections"))
1858                         i->n_connections = u;
1859
1860                 break;
1861         }
1862
1863         case DBUS_TYPE_INT32: {
1864                 int32_t j;
1865
1866                 dbus_message_iter_get_basic(iter, &j);
1867
1868                 if (streq(name, "ExecMainCode"))
1869                         i->exit_code = (int) j;
1870                 else if (streq(name, "ExecMainStatus"))
1871                         i->exit_status = (int) j;
1872
1873                 break;
1874         }
1875
1876         case DBUS_TYPE_UINT64: {
1877                 uint64_t u;
1878
1879                 dbus_message_iter_get_basic(iter, &u);
1880
1881                 if (streq(name, "ExecMainStartTimestamp"))
1882                         i->start_timestamp = (usec_t) u;
1883                 else if (streq(name, "ExecMainExitTimestamp"))
1884                         i->exit_timestamp = (usec_t) u;
1885                 else if (streq(name, "ActiveEnterTimestamp"))
1886                         i->active_enter_timestamp = (usec_t) u;
1887                 else if (streq(name, "InactiveEnterTimestamp"))
1888                         i->inactive_enter_timestamp = (usec_t) u;
1889                 else if (streq(name, "InactiveExitTimestamp"))
1890                         i->inactive_exit_timestamp = (usec_t) u;
1891                 else if (streq(name, "ActiveExitTimestamp"))
1892                         i->active_exit_timestamp = (usec_t) u;
1893
1894                 break;
1895         }
1896
1897         case DBUS_TYPE_ARRAY: {
1898
1899                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
1900                     startswith(name, "Exec")) {
1901                         DBusMessageIter sub;
1902
1903                         dbus_message_iter_recurse(iter, &sub);
1904                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1905                                 ExecStatusInfo *info;
1906                                 int r;
1907
1908                                 if (!(info = new0(ExecStatusInfo, 1)))
1909                                         return -ENOMEM;
1910
1911                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
1912                                         free(info);
1913                                         return r;
1914                                 }
1915
1916                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
1917
1918                                 dbus_message_iter_next(&sub);
1919                         }
1920                 }
1921
1922                 break;
1923         }
1924         }
1925
1926         return 0;
1927 }
1928
1929 static int print_property(const char *name, DBusMessageIter *iter) {
1930         assert(name);
1931         assert(iter);
1932
1933         /* This is a low-level property printer, see
1934          * print_status_info() for the nicer output */
1935
1936         if (arg_property && !strv_find(arg_property, name))
1937                 return 0;
1938
1939         switch (dbus_message_iter_get_arg_type(iter)) {
1940
1941         case DBUS_TYPE_STRING: {
1942                 const char *s;
1943                 dbus_message_iter_get_basic(iter, &s);
1944
1945                 if (arg_all || s[0])
1946                         printf("%s=%s\n", name, s);
1947
1948                 return 0;
1949         }
1950
1951         case DBUS_TYPE_BOOLEAN: {
1952                 dbus_bool_t b;
1953                 dbus_message_iter_get_basic(iter, &b);
1954                 printf("%s=%s\n", name, yes_no(b));
1955
1956                 return 0;
1957         }
1958
1959         case DBUS_TYPE_UINT64: {
1960                 uint64_t u;
1961                 dbus_message_iter_get_basic(iter, &u);
1962
1963                 /* Yes, heuristics! But we can change this check
1964                  * should it turn out to not be sufficient */
1965
1966                 if (strstr(name, "Timestamp")) {
1967                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1968
1969                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
1970                                 printf("%s=%s\n", name, strempty(t));
1971                 } else if (strstr(name, "USec")) {
1972                         char timespan[FORMAT_TIMESPAN_MAX];
1973
1974                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1975                 } else
1976                         printf("%s=%llu\n", name, (unsigned long long) u);
1977
1978                 return 0;
1979         }
1980
1981         case DBUS_TYPE_UINT32: {
1982                 uint32_t u;
1983                 dbus_message_iter_get_basic(iter, &u);
1984
1985                 if (strstr(name, "UMask") || strstr(name, "Mode"))
1986                         printf("%s=%04o\n", name, u);
1987                 else
1988                         printf("%s=%u\n", name, (unsigned) u);
1989
1990                 return 0;
1991         }
1992
1993         case DBUS_TYPE_INT32: {
1994                 int32_t i;
1995                 dbus_message_iter_get_basic(iter, &i);
1996
1997                 printf("%s=%i\n", name, (int) i);
1998                 return 0;
1999         }
2000
2001         case DBUS_TYPE_STRUCT: {
2002                 DBusMessageIter sub;
2003                 dbus_message_iter_recurse(iter, &sub);
2004
2005                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2006                         uint32_t u;
2007
2008                         dbus_message_iter_get_basic(&sub, &u);
2009
2010                         if (u)
2011                                 printf("%s=%u\n", name, (unsigned) u);
2012                         else if (arg_all)
2013                                 printf("%s=\n", name);
2014
2015                         return 0;
2016                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2017                         const char *s;
2018
2019                         dbus_message_iter_get_basic(&sub, &s);
2020
2021                         if (arg_all || s[0])
2022                                 printf("%s=%s\n", name, s);
2023
2024                         return 0;
2025                 }
2026
2027                 break;
2028         }
2029
2030         case DBUS_TYPE_ARRAY:
2031
2032                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
2033                         DBusMessageIter sub;
2034                         bool space = false;
2035
2036                         dbus_message_iter_recurse(iter, &sub);
2037                         if (arg_all ||
2038                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2039                                 printf("%s=", name);
2040
2041                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2042                                         const char *s;
2043
2044                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
2045                                         dbus_message_iter_get_basic(&sub, &s);
2046                                         printf("%s%s", space ? " " : "", s);
2047
2048                                         space = true;
2049                                         dbus_message_iter_next(&sub);
2050                                 }
2051
2052                                 puts("");
2053                         }
2054
2055                         return 0;
2056
2057                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
2058                         DBusMessageIter sub;
2059
2060                         dbus_message_iter_recurse(iter, &sub);
2061                         if (arg_all ||
2062                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2063                                 printf("%s=", name);
2064
2065                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2066                                         uint8_t u;
2067
2068                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
2069                                         dbus_message_iter_get_basic(&sub, &u);
2070                                         printf("%02x", u);
2071
2072                                         dbus_message_iter_next(&sub);
2073                                 }
2074
2075                                 puts("");
2076                         }
2077
2078                         return 0;
2079
2080                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2081                         DBusMessageIter sub, sub2;
2082
2083                         dbus_message_iter_recurse(iter, &sub);
2084                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2085                                 const char *type, *path;
2086
2087                                 dbus_message_iter_recurse(&sub, &sub2);
2088
2089                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2090                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2091                                         printf("%s=%s\n", type, path);
2092
2093                                 dbus_message_iter_next(&sub);
2094                         }
2095
2096                         return 0;
2097
2098                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2099                         DBusMessageIter sub, sub2;
2100
2101                         dbus_message_iter_recurse(iter, &sub);
2102                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2103                                 const char *base;
2104                                 uint64_t value, next_elapse;
2105
2106                                 dbus_message_iter_recurse(&sub, &sub2);
2107
2108                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2109                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2110                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2111                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2112
2113                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2114                                                base,
2115                                                format_timespan(timespan1, sizeof(timespan1), value),
2116                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2117                                 }
2118
2119                                 dbus_message_iter_next(&sub);
2120                         }
2121
2122                         return 0;
2123
2124                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2125                         DBusMessageIter sub;
2126
2127                         dbus_message_iter_recurse(iter, &sub);
2128                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2129                                 ExecStatusInfo info;
2130
2131                                 zero(info);
2132                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2133                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2134                                         char *t;
2135
2136                                         t = strv_join(info.argv, " ");
2137
2138                                         printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2139                                                name,
2140                                                strna(info.path),
2141                                                strna(t),
2142                                                yes_no(info.ignore),
2143                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2144                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2145                                                (unsigned) info. pid,
2146                                                sigchld_code_to_string(info.code),
2147                                                info.status,
2148                                                info.code == CLD_EXITED ? "" : "/",
2149                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2150
2151                                         free(t);
2152                                 }
2153
2154                                 free(info.path);
2155                                 strv_free(info.argv);
2156
2157                                 dbus_message_iter_next(&sub);
2158                         }
2159
2160                         return 0;
2161                 }
2162
2163                 break;
2164         }
2165
2166         if (arg_all)
2167                 printf("%s=[unprintable]\n", name);
2168
2169         return 0;
2170 }
2171
2172 static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2173         DBusMessage *m = NULL, *reply = NULL;
2174         const char *interface = "";
2175         int r;
2176         DBusError error;
2177         DBusMessageIter iter, sub, sub2, sub3;
2178         UnitStatusInfo info;
2179         ExecStatusInfo *p;
2180
2181         assert(bus);
2182         assert(path);
2183         assert(new_line);
2184
2185         zero(info);
2186         dbus_error_init(&error);
2187
2188         if (!(m = dbus_message_new_method_call(
2189                               "org.freedesktop.systemd1",
2190                               path,
2191                               "org.freedesktop.DBus.Properties",
2192                               "GetAll"))) {
2193                 log_error("Could not allocate message.");
2194                 r = -ENOMEM;
2195                 goto finish;
2196         }
2197
2198         if (!dbus_message_append_args(m,
2199                                       DBUS_TYPE_STRING, &interface,
2200                                       DBUS_TYPE_INVALID)) {
2201                 log_error("Could not append arguments to message.");
2202                 r = -ENOMEM;
2203                 goto finish;
2204         }
2205
2206         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2207                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2208                 r = -EIO;
2209                 goto finish;
2210         }
2211
2212         if (!dbus_message_iter_init(reply, &iter) ||
2213             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2214             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2215                 log_error("Failed to parse reply.");
2216                 r = -EIO;
2217                 goto finish;
2218         }
2219
2220         dbus_message_iter_recurse(&iter, &sub);
2221
2222         if (*new_line)
2223                 printf("\n");
2224
2225         *new_line = true;
2226
2227         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2228                 const char *name;
2229
2230                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2231                         log_error("Failed to parse reply.");
2232                         r = -EIO;
2233                         goto finish;
2234                 }
2235
2236                 dbus_message_iter_recurse(&sub, &sub2);
2237
2238                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2239                         log_error("Failed to parse reply.");
2240                         r = -EIO;
2241                         goto finish;
2242                 }
2243
2244                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2245                         log_error("Failed to parse reply.");
2246                         r = -EIO;
2247                         goto finish;
2248                 }
2249
2250                 dbus_message_iter_recurse(&sub2, &sub3);
2251
2252                 if (show_properties)
2253                         r = print_property(name, &sub3);
2254                 else
2255                         r = status_property(name, &sub3, &info);
2256
2257                 if (r < 0) {
2258                         log_error("Failed to parse reply.");
2259                         r = -EIO;
2260                         goto finish;
2261                 }
2262
2263                 dbus_message_iter_next(&sub);
2264         }
2265
2266         r = 0;
2267
2268         if (!show_properties)
2269                 print_status_info(&info);
2270
2271         if (!streq_ptr(info.active_state, "active") &&
2272             !streq_ptr(info.active_state, "reloading"))
2273                 /* According to LSB: "program not running" */
2274                 r = 3;
2275
2276         while ((p = info.exec)) {
2277                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2278                 exec_status_info_free(p);
2279         }
2280
2281 finish:
2282         if (m)
2283                 dbus_message_unref(m);
2284
2285         if (reply)
2286                 dbus_message_unref(reply);
2287
2288         dbus_error_free(&error);
2289
2290         return r;
2291 }
2292
2293 static int show(DBusConnection *bus, char **args, unsigned n) {
2294         DBusMessage *m = NULL, *reply = NULL;
2295         int r, ret = 0;
2296         DBusError error;
2297         unsigned i;
2298         bool show_properties, new_line = false;
2299
2300         assert(bus);
2301         assert(args);
2302
2303         dbus_error_init(&error);
2304
2305         show_properties = !streq(args[0], "status");
2306
2307         if (show_properties && n <= 1) {
2308                 /* If not argument is specified inspect the manager
2309                  * itself */
2310
2311                 ret = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2312                 goto finish;
2313         }
2314
2315         for (i = 1; i < n; i++) {
2316                 const char *path = NULL;
2317                 uint32_t id;
2318
2319                 if (safe_atou32(args[i], &id) < 0) {
2320
2321                         /* Interpret as unit name */
2322
2323                         if (!(m = dbus_message_new_method_call(
2324                                               "org.freedesktop.systemd1",
2325                                               "/org/freedesktop/systemd1",
2326                                               "org.freedesktop.systemd1.Manager",
2327                                               "LoadUnit"))) {
2328                                 log_error("Could not allocate message.");
2329                                 ret = -ENOMEM;
2330                                 goto finish;
2331                         }
2332
2333                         if (!dbus_message_append_args(m,
2334                                                       DBUS_TYPE_STRING, &args[i],
2335                                                       DBUS_TYPE_INVALID)) {
2336                                 log_error("Could not append arguments to message.");
2337                                 ret = -ENOMEM;
2338                                 goto finish;
2339                         }
2340
2341                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2342
2343                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2344                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2345                                         ret = -EIO;
2346                                         goto finish;
2347                                 }
2348
2349                                 dbus_error_free(&error);
2350
2351                                 dbus_message_unref(m);
2352                                 if (!(m = dbus_message_new_method_call(
2353                                                       "org.freedesktop.systemd1",
2354                                                       "/org/freedesktop/systemd1",
2355                                                       "org.freedesktop.systemd1.Manager",
2356                                                       "GetUnit"))) {
2357                                         log_error("Could not allocate message.");
2358                                         ret = -ENOMEM;
2359                                         goto finish;
2360                                 }
2361
2362                                 if (!dbus_message_append_args(m,
2363                                                               DBUS_TYPE_STRING, &args[i],
2364                                                               DBUS_TYPE_INVALID)) {
2365                                         log_error("Could not append arguments to message.");
2366                                         ret = -ENOMEM;
2367                                         goto finish;
2368                                 }
2369
2370                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2371                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2372
2373                                         if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
2374                                                 ret = 4; /* According to LSB: "program or service status is unknown" */
2375                                         else
2376                                                 ret = -EIO;
2377                                         goto finish;
2378                                 }
2379                         }
2380
2381                 } else if (show_properties) {
2382
2383                         /* Interpret as job id */
2384
2385                         if (!(m = dbus_message_new_method_call(
2386                                               "org.freedesktop.systemd1",
2387                                               "/org/freedesktop/systemd1",
2388                                               "org.freedesktop.systemd1.Manager",
2389                                               "GetJob"))) {
2390                                 log_error("Could not allocate message.");
2391                                 ret = -ENOMEM;
2392                                 goto finish;
2393                         }
2394
2395                         if (!dbus_message_append_args(m,
2396                                                       DBUS_TYPE_UINT32, &id,
2397                                                       DBUS_TYPE_INVALID)) {
2398                                 log_error("Could not append arguments to message.");
2399                                 ret = -ENOMEM;
2400                                 goto finish;
2401                         }
2402
2403                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2404                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2405                                 ret = -EIO;
2406                                 goto finish;
2407                         }
2408                 } else {
2409
2410                         /* Interpret as PID */
2411
2412                         if (!(m = dbus_message_new_method_call(
2413                                               "org.freedesktop.systemd1",
2414                                               "/org/freedesktop/systemd1",
2415                                               "org.freedesktop.systemd1.Manager",
2416                                               "GetUnitByPID"))) {
2417                                 log_error("Could not allocate message.");
2418                                 ret = -ENOMEM;
2419                                 goto finish;
2420                         }
2421
2422                         if (!dbus_message_append_args(m,
2423                                                       DBUS_TYPE_UINT32, &id,
2424                                                       DBUS_TYPE_INVALID)) {
2425                                 log_error("Could not append arguments to message.");
2426                                 ret = -ENOMEM;
2427                                 goto finish;
2428                         }
2429
2430                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2431                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2432                                 ret = -EIO;
2433                                 goto finish;
2434                         }
2435                 }
2436
2437                 if (!dbus_message_get_args(reply, &error,
2438                                            DBUS_TYPE_OBJECT_PATH, &path,
2439                                            DBUS_TYPE_INVALID)) {
2440                         log_error("Failed to parse reply: %s", bus_error_message(&error));
2441                         ret = -EIO;
2442                         goto finish;
2443                 }
2444
2445                 if ((r = show_one(bus, path, show_properties, &new_line)) != 0)
2446                         ret = r;
2447
2448                 dbus_message_unref(m);
2449                 dbus_message_unref(reply);
2450                 m = reply = NULL;
2451         }
2452
2453 finish:
2454         if (m)
2455                 dbus_message_unref(m);
2456
2457         if (reply)
2458                 dbus_message_unref(reply);
2459
2460         dbus_error_free(&error);
2461
2462         return ret;
2463 }
2464
2465 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
2466         DBusError error;
2467         DBusMessage *m = NULL, *reply = NULL;
2468
2469         assert(connection);
2470         assert(message);
2471
2472         dbus_error_init(&error);
2473
2474         log_debug("Got D-Bus request: %s.%s() on %s",
2475                   dbus_message_get_interface(message),
2476                   dbus_message_get_member(message),
2477                   dbus_message_get_path(message));
2478
2479         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
2480                 log_error("Warning! D-Bus connection terminated.");
2481                 dbus_connection_close(connection);
2482
2483         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
2484                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2485                 const char *id, *path;
2486
2487                 if (!dbus_message_get_args(message, &error,
2488                                            DBUS_TYPE_STRING, &id,
2489                                            DBUS_TYPE_OBJECT_PATH, &path,
2490                                            DBUS_TYPE_INVALID))
2491                         log_error("Failed to parse message: %s", bus_error_message(&error));
2492                 else if (streq(dbus_message_get_member(message), "UnitNew"))
2493                         printf("Unit %s added.\n", id);
2494                 else
2495                         printf("Unit %s removed.\n", id);
2496
2497         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
2498                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2499                 uint32_t id;
2500                 const char *path;
2501
2502                 if (!dbus_message_get_args(message, &error,
2503                                            DBUS_TYPE_UINT32, &id,
2504                                            DBUS_TYPE_OBJECT_PATH, &path,
2505                                            DBUS_TYPE_INVALID))
2506                         log_error("Failed to parse message: %s", bus_error_message(&error));
2507                 else if (streq(dbus_message_get_member(message), "JobNew"))
2508                         printf("Job %u added.\n", id);
2509                 else
2510                         printf("Job %u removed.\n", id);
2511
2512
2513         } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2514
2515                 const char *path, *interface, *property = "Id";
2516                 DBusMessageIter iter, sub;
2517
2518                 path = dbus_message_get_path(message);
2519
2520                 if (!dbus_message_get_args(message, &error,
2521                                           DBUS_TYPE_STRING, &interface,
2522                                           DBUS_TYPE_INVALID)) {
2523                         log_error("Failed to parse message: %s", bus_error_message(&error));
2524                         goto finish;
2525                 }
2526
2527                 if (!streq(interface, "org.freedesktop.systemd1.Job") &&
2528                     !streq(interface, "org.freedesktop.systemd1.Unit"))
2529                         goto finish;
2530
2531                 if (!(m = dbus_message_new_method_call(
2532                               "org.freedesktop.systemd1",
2533                               path,
2534                               "org.freedesktop.DBus.Properties",
2535                               "Get"))) {
2536                         log_error("Could not allocate message.");
2537                         goto oom;
2538                 }
2539
2540                 if (!dbus_message_append_args(m,
2541                                               DBUS_TYPE_STRING, &interface,
2542                                               DBUS_TYPE_STRING, &property,
2543                                               DBUS_TYPE_INVALID)) {
2544                         log_error("Could not append arguments to message.");
2545                         goto finish;
2546                 }
2547
2548                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
2549                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2550                         goto finish;
2551                 }
2552
2553                 if (!dbus_message_iter_init(reply, &iter) ||
2554                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2555                         log_error("Failed to parse reply.");
2556                         goto finish;
2557                 }
2558
2559                 dbus_message_iter_recurse(&iter, &sub);
2560
2561                 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
2562                         const char *id;
2563
2564                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2565                                 log_error("Failed to parse reply.");
2566                                 goto finish;
2567                         }
2568
2569                         dbus_message_iter_get_basic(&sub, &id);
2570                         printf("Unit %s changed.\n", id);
2571                 } else {
2572                         uint32_t id;
2573
2574                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)  {
2575                                 log_error("Failed to parse reply.");
2576                                 goto finish;
2577                         }
2578
2579                         dbus_message_iter_get_basic(&sub, &id);
2580                         printf("Job %u changed.\n", id);
2581                 }
2582         }
2583
2584 finish:
2585         if (m)
2586                 dbus_message_unref(m);
2587
2588         if (reply)
2589                 dbus_message_unref(reply);
2590
2591         dbus_error_free(&error);
2592         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2593
2594 oom:
2595         if (m)
2596                 dbus_message_unref(m);
2597
2598         if (reply)
2599                 dbus_message_unref(reply);
2600
2601         dbus_error_free(&error);
2602         return DBUS_HANDLER_RESULT_NEED_MEMORY;
2603 }
2604
2605 static int monitor(DBusConnection *bus, char **args, unsigned n) {
2606         DBusMessage *m = NULL, *reply = NULL;
2607         DBusError error;
2608         int r;
2609
2610         dbus_error_init(&error);
2611
2612         if (!private_bus) {
2613                 dbus_bus_add_match(bus,
2614                                    "type='signal',"
2615                                    "sender='org.freedesktop.systemd1',"
2616                                    "interface='org.freedesktop.systemd1.Manager',"
2617                                    "path='/org/freedesktop/systemd1'",
2618                                    &error);
2619
2620                 if (dbus_error_is_set(&error)) {
2621                         log_error("Failed to add match: %s", bus_error_message(&error));
2622                         r = -EIO;
2623                         goto finish;
2624                 }
2625
2626                 dbus_bus_add_match(bus,
2627                                    "type='signal',"
2628                                    "sender='org.freedesktop.systemd1',"
2629                                    "interface='org.freedesktop.DBus.Properties',"
2630                                    "member='PropertiesChanged'",
2631                                    &error);
2632
2633                 if (dbus_error_is_set(&error)) {
2634                         log_error("Failed to add match: %s", bus_error_message(&error));
2635                         r = -EIO;
2636                         goto finish;
2637                 }
2638         }
2639
2640         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
2641                 log_error("Failed to add filter.");
2642                 r = -ENOMEM;
2643                 goto finish;
2644         }
2645
2646         if (!(m = dbus_message_new_method_call(
2647                               "org.freedesktop.systemd1",
2648                               "/org/freedesktop/systemd1",
2649                               "org.freedesktop.systemd1.Manager",
2650                               "Subscribe"))) {
2651                 log_error("Could not allocate message.");
2652                 r = -ENOMEM;
2653                 goto finish;
2654         }
2655
2656         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2657                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2658                 r = -EIO;
2659                 goto finish;
2660         }
2661
2662         while (dbus_connection_read_write_dispatch(bus, -1))
2663                 ;
2664
2665         r = 0;
2666
2667 finish:
2668
2669         /* This is slightly dirty, since we don't undo the filter or the matches. */
2670
2671         if (m)
2672                 dbus_message_unref(m);
2673
2674         if (reply)
2675                 dbus_message_unref(reply);
2676
2677         dbus_error_free(&error);
2678
2679         return r;
2680 }
2681
2682 static int dump(DBusConnection *bus, char **args, unsigned n) {
2683         DBusMessage *m = NULL, *reply = NULL;
2684         DBusError error;
2685         int r;
2686         const char *text;
2687
2688         dbus_error_init(&error);
2689
2690         if (!(m = dbus_message_new_method_call(
2691                               "org.freedesktop.systemd1",
2692                               "/org/freedesktop/systemd1",
2693                               "org.freedesktop.systemd1.Manager",
2694                               "Dump"))) {
2695                 log_error("Could not allocate message.");
2696                 return -ENOMEM;
2697         }
2698
2699         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2700                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2701                 r = -EIO;
2702                 goto finish;
2703         }
2704
2705         if (!dbus_message_get_args(reply, &error,
2706                                    DBUS_TYPE_STRING, &text,
2707                                    DBUS_TYPE_INVALID)) {
2708                 log_error("Failed to parse reply: %s", bus_error_message(&error));
2709                 r = -EIO;
2710                 goto finish;
2711         }
2712
2713         fputs(text, stdout);
2714
2715         r = 0;
2716
2717 finish:
2718         if (m)
2719                 dbus_message_unref(m);
2720
2721         if (reply)
2722                 dbus_message_unref(reply);
2723
2724         dbus_error_free(&error);
2725
2726         return r;
2727 }
2728
2729 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
2730         DBusMessage *m = NULL, *reply = NULL;
2731         DBusError error;
2732         int r;
2733         const char *name = "", *path, *id;
2734         dbus_bool_t cleanup = FALSE;
2735         DBusMessageIter iter, sub;
2736         const char
2737                 *interface = "org.freedesktop.systemd1.Unit",
2738                 *property = "Id";
2739
2740         dbus_error_init(&error);
2741
2742         if (!(m = dbus_message_new_method_call(
2743                               "org.freedesktop.systemd1",
2744                               "/org/freedesktop/systemd1",
2745                               "org.freedesktop.systemd1.Manager",
2746                               "CreateSnapshot"))) {
2747                 log_error("Could not allocate message.");
2748                 return -ENOMEM;
2749         }
2750
2751         if (n > 1)
2752                 name = args[1];
2753
2754         if (!dbus_message_append_args(m,
2755                                       DBUS_TYPE_STRING, &name,
2756                                       DBUS_TYPE_BOOLEAN, &cleanup,
2757                                       DBUS_TYPE_INVALID)) {
2758                 log_error("Could not append arguments to message.");
2759                 r = -ENOMEM;
2760                 goto finish;
2761         }
2762
2763         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2764                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2765                 r = -EIO;
2766                 goto finish;
2767         }
2768
2769         if (!dbus_message_get_args(reply, &error,
2770                                    DBUS_TYPE_OBJECT_PATH, &path,
2771                                    DBUS_TYPE_INVALID)) {
2772                 log_error("Failed to parse reply: %s", bus_error_message(&error));
2773                 r = -EIO;
2774                 goto finish;
2775         }
2776
2777         dbus_message_unref(m);
2778         if (!(m = dbus_message_new_method_call(
2779                               "org.freedesktop.systemd1",
2780                               path,
2781                               "org.freedesktop.DBus.Properties",
2782                               "Get"))) {
2783                 log_error("Could not allocate message.");
2784                 return -ENOMEM;
2785         }
2786
2787         if (!dbus_message_append_args(m,
2788                                       DBUS_TYPE_STRING, &interface,
2789                                       DBUS_TYPE_STRING, &property,
2790                                       DBUS_TYPE_INVALID)) {
2791                 log_error("Could not append arguments to message.");
2792                 r = -ENOMEM;
2793                 goto finish;
2794         }
2795
2796         dbus_message_unref(reply);
2797         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2798                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2799                 r = -EIO;
2800                 goto finish;
2801         }
2802
2803         if (!dbus_message_iter_init(reply, &iter) ||
2804             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2805                 log_error("Failed to parse reply.");
2806                 r = -EIO;
2807                 goto finish;
2808         }
2809
2810         dbus_message_iter_recurse(&iter, &sub);
2811
2812         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2813                 log_error("Failed to parse reply.");
2814                 r = -EIO;
2815                 goto finish;
2816         }
2817
2818         dbus_message_iter_get_basic(&sub, &id);
2819
2820         if (!arg_quiet)
2821                 puts(id);
2822         r = 0;
2823
2824 finish:
2825         if (m)
2826                 dbus_message_unref(m);
2827
2828         if (reply)
2829                 dbus_message_unref(reply);
2830
2831         dbus_error_free(&error);
2832
2833         return r;
2834 }
2835
2836 static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
2837         DBusMessage *m = NULL, *reply = NULL;
2838         int r;
2839         DBusError error;
2840         unsigned i;
2841
2842         assert(bus);
2843         assert(args);
2844
2845         dbus_error_init(&error);
2846
2847         for (i = 1; i < n; i++) {
2848                 const char *path = NULL;
2849
2850                 if (!(m = dbus_message_new_method_call(
2851                                       "org.freedesktop.systemd1",
2852                                       "/org/freedesktop/systemd1",
2853                                       "org.freedesktop.systemd1.Manager",
2854                                       "GetUnit"))) {
2855                         log_error("Could not allocate message.");
2856                         r = -ENOMEM;
2857                         goto finish;
2858                 }
2859
2860                 if (!dbus_message_append_args(m,
2861                                               DBUS_TYPE_STRING, &args[i],
2862                                               DBUS_TYPE_INVALID)) {
2863                         log_error("Could not append arguments to message.");
2864                         r = -ENOMEM;
2865                         goto finish;
2866                 }
2867
2868                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2869                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2870                         r = -EIO;
2871                         goto finish;
2872                 }
2873
2874                 if (!dbus_message_get_args(reply, &error,
2875                                            DBUS_TYPE_OBJECT_PATH, &path,
2876                                            DBUS_TYPE_INVALID)) {
2877                         log_error("Failed to parse reply: %s", bus_error_message(&error));
2878                         r = -EIO;
2879                         goto finish;
2880                 }
2881
2882                 dbus_message_unref(m);
2883                 if (!(m = dbus_message_new_method_call(
2884                                       "org.freedesktop.systemd1",
2885                                       path,
2886                                       "org.freedesktop.systemd1.Snapshot",
2887                                       "Remove"))) {
2888                         log_error("Could not allocate message.");
2889                         r = -ENOMEM;
2890                         goto finish;
2891                 }
2892
2893                 dbus_message_unref(reply);
2894                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2895                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2896                         r = -EIO;
2897                         goto finish;
2898                 }
2899
2900                 dbus_message_unref(m);
2901                 dbus_message_unref(reply);
2902                 m = reply = NULL;
2903         }
2904
2905         r = 0;
2906
2907 finish:
2908         if (m)
2909                 dbus_message_unref(m);
2910
2911         if (reply)
2912                 dbus_message_unref(reply);
2913
2914         dbus_error_free(&error);
2915
2916         return r;
2917 }
2918
2919 static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
2920         DBusMessage *m = NULL, *reply = NULL;
2921         DBusError error;
2922         int r;
2923         const char *method;
2924
2925         dbus_error_init(&error);
2926
2927         if (arg_action == ACTION_RELOAD)
2928                 method = "Reload";
2929         else if (arg_action == ACTION_REEXEC)
2930                 method = "Reexecute";
2931         else {
2932                 assert(arg_action == ACTION_SYSTEMCTL);
2933
2934                 method =
2935                         streq(args[0], "clear-jobs")        ||
2936                         streq(args[0], "cancel")            ? "ClearJobs" :
2937                         streq(args[0], "daemon-reexec")     ? "Reexecute" :
2938                         streq(args[0], "reset-failed")      ? "ResetFailed" :
2939                         streq(args[0], "daemon-exit")       ? "Exit" :
2940                                                               "Reload";
2941         }
2942
2943         if (!(m = dbus_message_new_method_call(
2944                               "org.freedesktop.systemd1",
2945                               "/org/freedesktop/systemd1",
2946                               "org.freedesktop.systemd1.Manager",
2947                               method))) {
2948                 log_error("Could not allocate message.");
2949                 return -ENOMEM;
2950         }
2951
2952         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2953
2954                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2955                         /* There's always a fallback possible for
2956                          * legacy actions. */
2957                         r = -EADDRNOTAVAIL;
2958                         goto finish;
2959                 }
2960
2961                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2962                 r = -EIO;
2963                 goto finish;
2964         }
2965
2966         r = 0;
2967
2968 finish:
2969         if (m)
2970                 dbus_message_unref(m);
2971
2972         if (reply)
2973                 dbus_message_unref(reply);
2974
2975         dbus_error_free(&error);
2976
2977         return r;
2978 }
2979
2980 static int reset_failed(DBusConnection *bus, char **args, unsigned n) {
2981         DBusMessage *m = NULL, *reply = NULL;
2982         unsigned i;
2983         int r;
2984         DBusError error;
2985
2986         assert(bus);
2987         dbus_error_init(&error);
2988
2989         if (n <= 1)
2990                 return daemon_reload(bus, args, n);
2991
2992         for (i = 1; i < n; i++) {
2993
2994                 if (!(m = dbus_message_new_method_call(
2995                                       "org.freedesktop.systemd1",
2996                                       "/org/freedesktop/systemd1",
2997                                       "org.freedesktop.systemd1.Manager",
2998                                       "ResetFailedUnit"))) {
2999                         log_error("Could not allocate message.");
3000                         r = -ENOMEM;
3001                         goto finish;
3002                 }
3003
3004                 if (!dbus_message_append_args(m,
3005                                               DBUS_TYPE_STRING, args + i,
3006                                               DBUS_TYPE_INVALID)) {
3007                         log_error("Could not append arguments to message.");
3008                         r = -ENOMEM;
3009                         goto finish;
3010                 }
3011
3012                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3013                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3014                         r = -EIO;
3015                         goto finish;
3016                 }
3017
3018                 dbus_message_unref(m);
3019                 dbus_message_unref(reply);
3020                 m = reply = NULL;
3021         }
3022
3023         r = 0;
3024
3025 finish:
3026         if (m)
3027                 dbus_message_unref(m);
3028
3029         if (reply)
3030                 dbus_message_unref(reply);
3031
3032         dbus_error_free(&error);
3033
3034         return r;
3035 }
3036
3037 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
3038         DBusMessage *m = NULL, *reply = NULL;
3039         DBusError error;
3040         DBusMessageIter iter, sub, sub2;
3041         int r;
3042         const char
3043                 *interface = "org.freedesktop.systemd1.Manager",
3044                 *property = "Environment";
3045
3046         dbus_error_init(&error);
3047
3048         if (!(m = dbus_message_new_method_call(
3049                               "org.freedesktop.systemd1",
3050                               "/org/freedesktop/systemd1",
3051                               "org.freedesktop.DBus.Properties",
3052                               "Get"))) {
3053                 log_error("Could not allocate message.");
3054                 return -ENOMEM;
3055         }
3056
3057         if (!dbus_message_append_args(m,
3058                                       DBUS_TYPE_STRING, &interface,
3059                                       DBUS_TYPE_STRING, &property,
3060                                       DBUS_TYPE_INVALID)) {
3061                 log_error("Could not append arguments to message.");
3062                 r = -ENOMEM;
3063                 goto finish;
3064         }
3065
3066         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3067                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3068                 r = -EIO;
3069                 goto finish;
3070         }
3071
3072         if (!dbus_message_iter_init(reply, &iter) ||
3073             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3074                 log_error("Failed to parse reply.");
3075                 r = -EIO;
3076                 goto finish;
3077         }
3078
3079         dbus_message_iter_recurse(&iter, &sub);
3080
3081         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3082             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3083                 log_error("Failed to parse reply.");
3084                 r = -EIO;
3085                 goto finish;
3086         }
3087
3088         dbus_message_iter_recurse(&sub, &sub2);
3089
3090         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3091                 const char *text;
3092
3093                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3094                         log_error("Failed to parse reply.");
3095                         r = -EIO;
3096                         goto finish;
3097                 }
3098
3099                 dbus_message_iter_get_basic(&sub2, &text);
3100                 printf("%s\n", text);
3101
3102                 dbus_message_iter_next(&sub2);
3103         }
3104
3105         r = 0;
3106
3107 finish:
3108         if (m)
3109                 dbus_message_unref(m);
3110
3111         if (reply)
3112                 dbus_message_unref(reply);
3113
3114         dbus_error_free(&error);
3115
3116         return r;
3117 }
3118
3119 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
3120         DBusMessage *m = NULL, *reply = NULL;
3121         DBusError error;
3122         int r;
3123         const char *method;
3124         DBusMessageIter iter, sub;
3125         unsigned i;
3126
3127         dbus_error_init(&error);
3128
3129         method = streq(args[0], "set-environment")
3130                 ? "SetEnvironment"
3131                 : "UnsetEnvironment";
3132
3133         if (!(m = dbus_message_new_method_call(
3134                               "org.freedesktop.systemd1",
3135                               "/org/freedesktop/systemd1",
3136                               "org.freedesktop.systemd1.Manager",
3137                               method))) {
3138
3139                 log_error("Could not allocate message.");
3140                 return -ENOMEM;
3141         }
3142
3143         dbus_message_iter_init_append(m, &iter);
3144
3145         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3146                 log_error("Could not append arguments to message.");
3147                 r = -ENOMEM;
3148                 goto finish;
3149         }
3150
3151         for (i = 1; i < n; i++)
3152                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
3153                         log_error("Could not append arguments to message.");
3154                         r = -ENOMEM;
3155                         goto finish;
3156                 }
3157
3158         if (!dbus_message_iter_close_container(&iter, &sub)) {
3159                 log_error("Could not append arguments to message.");
3160                 r = -ENOMEM;
3161                 goto finish;
3162         }
3163
3164         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3165                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3166                 r = -EIO;
3167                 goto finish;
3168         }
3169
3170         r = 0;
3171
3172 finish:
3173         if (m)
3174                 dbus_message_unref(m);
3175
3176         if (reply)
3177                 dbus_message_unref(reply);
3178
3179         dbus_error_free(&error);
3180
3181         return r;
3182 }
3183
3184 typedef struct {
3185         char *name;
3186         char *path;
3187
3188         char **aliases;
3189         char **wanted_by;
3190 } InstallInfo;
3191
3192 static Hashmap *will_install = NULL, *have_installed = NULL;
3193 static Set *remove_symlinks_to = NULL;
3194
3195 static void install_info_free(InstallInfo *i) {
3196         assert(i);
3197
3198         free(i->name);
3199         free(i->path);
3200         strv_free(i->aliases);
3201         strv_free(i->wanted_by);
3202         free(i);
3203 }
3204
3205 static void install_info_hashmap_free(Hashmap *m) {
3206         InstallInfo *i;
3207
3208         while ((i = hashmap_steal_first(m)))
3209                 install_info_free(i);
3210
3211         hashmap_free(m);
3212 }
3213
3214 static bool unit_name_valid(const char *name) {
3215
3216         /* This is a minimal version of unit_name_valid() from
3217          * unit-name.c */
3218
3219         if (!*name)
3220                 return false;
3221
3222         if (ignore_file(name))
3223                 return false;
3224
3225         return true;
3226 }
3227
3228 static int install_info_add(const char *name) {
3229         InstallInfo *i;
3230         int r;
3231
3232         assert(will_install);
3233
3234         if (!unit_name_valid(name))
3235                 return -EINVAL;
3236
3237         if (hashmap_get(have_installed, name) ||
3238             hashmap_get(will_install, name))
3239                 return 0;
3240
3241         if (!(i = new0(InstallInfo, 1))) {
3242                 r = -ENOMEM;
3243                 goto fail;
3244         }
3245
3246         if (!(i->name = strdup(name))) {
3247                 r = -ENOMEM;
3248                 goto fail;
3249         }
3250
3251         if ((r = hashmap_put(will_install, i->name, i)) < 0)
3252                 goto fail;
3253
3254         return 0;
3255
3256 fail:
3257         if (i)
3258                 install_info_free(i);
3259
3260         return r;
3261 }
3262
3263 static int config_parse_also(
3264                 const char *filename,
3265                 unsigned line,
3266                 const char *section,
3267                 const char *lvalue,
3268                 const char *rvalue,
3269                 void *data,
3270                 void *userdata) {
3271
3272         char *w;
3273         size_t l;
3274         char *state;
3275
3276         assert(filename);
3277         assert(lvalue);
3278         assert(rvalue);
3279
3280         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3281                 char *n;
3282                 int r;
3283
3284                 if (!(n = strndup(w, l)))
3285                         return -ENOMEM;
3286
3287                 r = install_info_add(n);
3288                 free(n);
3289
3290                 if (r < 0)
3291                         return r;
3292         }
3293
3294         return 0;
3295 }
3296
3297 static int mark_symlink_for_removal(const char *p) {
3298         char *n;
3299         int r;
3300
3301         assert(p);
3302         assert(path_is_absolute(p));
3303
3304         if (!remove_symlinks_to)
3305                 return 0;
3306
3307         if (!(n = strdup(p)))
3308                 return -ENOMEM;
3309
3310         path_kill_slashes(n);
3311
3312         if ((r = set_put(remove_symlinks_to, n)) < 0) {
3313                 free(n);
3314                 return r == -EEXIST ? 0 : r;
3315         }
3316
3317         return 0;
3318 }
3319
3320 static int remove_marked_symlinks_fd(int fd, const char *config_path, const char *root, bool *deleted) {
3321         int r = 0;
3322         DIR *d;
3323         struct dirent *de;
3324
3325         assert(fd >= 0);
3326         assert(root);
3327         assert(deleted);
3328
3329         if (!(d = fdopendir(fd))) {
3330                 close_nointr_nofail(fd);
3331                 return -errno;
3332         }
3333
3334         rewinddir(d);
3335
3336         while ((de = readdir(d))) {
3337                 bool is_dir = false, is_link = false;
3338
3339                 if (ignore_file(de->d_name))
3340                         continue;
3341
3342                 if (de->d_type == DT_LNK)
3343                         is_link = true;
3344                 else if (de->d_type == DT_DIR)
3345                         is_dir = true;
3346                 else if (de->d_type == DT_UNKNOWN) {
3347                         struct stat st;
3348
3349                         if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
3350                                 log_error("Failed to stat %s/%s: %m", root, de->d_name);
3351
3352                                 if (r == 0)
3353                                         r = -errno;
3354                                 continue;
3355                         }
3356
3357                         is_link = S_ISLNK(st.st_mode);
3358                         is_dir = S_ISDIR(st.st_mode);
3359                 } else
3360                         continue;
3361
3362                 if (is_dir) {
3363                         int nfd, q;
3364                         char *p;
3365
3366                         if ((nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0) {
3367                                 log_error("Failed to open %s/%s: %m", root, de->d_name);
3368
3369                                 if (r == 0)
3370                                         r = -errno;
3371                                 continue;
3372                         }
3373
3374                         if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
3375                                 log_error("Failed to allocate directory string.");
3376                                 close_nointr_nofail(nfd);
3377                                 r = -ENOMEM;
3378                                 break;
3379                         }
3380
3381                         /* This will close nfd, regardless whether it succeeds or not */
3382                         q = remove_marked_symlinks_fd(nfd, config_path, p, deleted);
3383                         free(p);
3384
3385                         if (r == 0)
3386                                 r = q;
3387
3388                 } else if (is_link) {
3389                         char *p, *dest, *c;
3390                         int q;
3391
3392                         if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
3393                                 log_error("Failed to allocate symlink string.");
3394                                 r = -ENOMEM;
3395                                 break;
3396                         }
3397
3398                         if ((q = readlink_and_make_absolute(p, &dest)) < 0) {
3399                                 log_error("Cannot read symlink %s: %s", p, strerror(-q));
3400                                 free(p);
3401
3402                                 if (r == 0)
3403                                         r = q;
3404                                 continue;
3405                         }
3406
3407                         if ((c = canonicalize_file_name(dest))) {
3408                                 /* This might fail if the destination
3409                                  * is already removed */
3410
3411                                 free(dest);
3412                                 dest = c;
3413                         }
3414
3415                         path_kill_slashes(dest);
3416                         if (set_get(remove_symlinks_to, dest)) {
3417
3418                                 if (!arg_quiet)
3419                                         log_info("rm '%s'", p);
3420
3421                                 if (unlink(p) < 0) {
3422                                         log_error("Cannot unlink symlink %s: %m", p);
3423
3424                                         if (r == 0)
3425                                                 r = -errno;
3426                                 } else {
3427                                         rmdir_parents(p, config_path);
3428                                         path_kill_slashes(p);
3429
3430                                         if (!set_get(remove_symlinks_to, p)) {
3431
3432                                                 if ((r = mark_symlink_for_removal(p)) < 0) {
3433                                                         if (r == 0)
3434                                                                 r = q;
3435                                                 } else
3436                                                         *deleted = true;
3437                                         }
3438                                 }
3439                         }
3440
3441                         free(p);
3442                         free(dest);
3443                 }
3444         }
3445
3446         closedir(d);
3447
3448         return r;
3449 }
3450
3451 static int remove_marked_symlinks(const char *config_path) {
3452         int fd, r = 0;
3453         bool deleted;
3454
3455         assert(config_path);
3456
3457         if (set_size(remove_symlinks_to) <= 0)
3458                 return 0;
3459
3460         if ((fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0)
3461                 return -errno;
3462
3463         do {
3464                 int q, cfd;
3465                 deleted = false;
3466
3467                 if ((cfd = dup(fd)) < 0) {
3468                         r = -errno;
3469                         break;
3470                 }
3471
3472                 /* This takes possession of cfd and closes it */
3473                 if ((q = remove_marked_symlinks_fd(cfd, config_path, config_path, &deleted)) < 0) {
3474                         if (r == 0)
3475                                 r = q;
3476                 }
3477         } while (deleted);
3478
3479         close_nointr_nofail(fd);
3480
3481         return r;
3482 }
3483
3484 static int create_symlink(const char *verb, const char *old_path, const char *new_path) {
3485         int r;
3486
3487         assert(old_path);
3488         assert(new_path);
3489         assert(verb);
3490
3491         if (streq(verb, "enable")) {
3492                 char *dest;
3493
3494                 mkdir_parents(new_path, 0755);
3495
3496                 if (symlink(old_path, new_path) >= 0) {
3497
3498                         if (!arg_quiet)
3499                                 log_info("ln -s '%s' '%s'", old_path, new_path);
3500
3501                         return 0;
3502                 }
3503
3504                 if (errno != EEXIST) {
3505                         log_error("Cannot link %s to %s: %m", old_path, new_path);
3506                         return -errno;
3507                 }
3508
3509                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
3510
3511                         if (errno == EINVAL) {
3512                                 log_error("Cannot link %s to %s, file exists already and is not a symlink.", old_path, new_path);
3513                                 return -EEXIST;
3514                         }
3515
3516                         log_error("readlink() failed: %s", strerror(-r));
3517                         return r;
3518                 }
3519
3520                 if (streq(dest, old_path)) {
3521                         free(dest);
3522                         return 0;
3523                 }
3524
3525                 if (!arg_force) {
3526                         log_error("Cannot link %s to %s, symlink exists already and points to %s.", old_path, new_path, dest);
3527                         free(dest);
3528                         return -EEXIST;
3529                 }
3530
3531                 free(dest);
3532                 unlink(new_path);
3533
3534                 if (!arg_quiet)
3535                         log_info("ln -s '%s' '%s'", old_path, new_path);
3536
3537                 if (symlink(old_path, new_path) >= 0)
3538                         return 0;
3539
3540                 log_error("Cannot link %s to %s: %m", old_path, new_path);
3541                 return -errno;
3542
3543         } else if (streq(verb, "disable")) {
3544                 char *dest;
3545
3546                 if ((r = mark_symlink_for_removal(old_path)) < 0)
3547                         return r;
3548
3549                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
3550                         if (errno == ENOENT)
3551                                 return 0;
3552
3553                         if (errno == EINVAL) {
3554                                 log_warning("File %s not a symlink, ignoring.", old_path);
3555                                 return 0;
3556                         }
3557
3558                         log_error("readlink() failed: %s", strerror(-r));
3559                         return r;
3560                 }
3561
3562                 if (!streq(dest, old_path)) {
3563                         log_warning("File %s not a symlink to %s but points to %s, ignoring.", new_path, old_path, dest);
3564                         free(dest);
3565                         return 0;
3566                 }
3567
3568                 free(dest);
3569
3570                 if ((r = mark_symlink_for_removal(new_path)) < 0)
3571                         return r;
3572
3573                 if (!arg_quiet)
3574                         log_info("rm '%s'", new_path);
3575
3576                 if (unlink(new_path) >= 0)
3577                         return 0;
3578
3579                 log_error("Cannot unlink %s: %m", new_path);
3580                 return -errno;
3581
3582         } else if (streq(verb, "is-enabled")) {
3583                 char *dest;
3584
3585                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
3586
3587                         if (errno == ENOENT || errno == EINVAL)
3588                                 return 0;
3589
3590                         log_error("readlink() failed: %s", strerror(-r));
3591                         return r;
3592                 }
3593
3594                 if (streq(dest, old_path)) {
3595                         free(dest);
3596                         return 1;
3597                 }
3598
3599                 return 0;
3600         }
3601
3602         assert_not_reached("Unknown action.");
3603 }
3604
3605 static int install_info_symlink_alias(const char *verb, InstallInfo *i, const char *config_path) {
3606         char **s;
3607         char *alias_path = NULL;
3608         int r;
3609
3610         assert(verb);
3611         assert(i);
3612         assert(config_path);
3613
3614         STRV_FOREACH(s, i->aliases) {
3615
3616                 if (!unit_name_valid(*s)) {
3617                         log_error("Invalid name %s.", *s);
3618                         r = -EINVAL;
3619                         goto finish;
3620                 }
3621
3622                 free(alias_path);
3623                 if (!(alias_path = path_make_absolute(*s, config_path))) {
3624                         log_error("Out of memory");
3625                         r = -ENOMEM;
3626                         goto finish;
3627                 }
3628
3629                 if ((r = create_symlink(verb, i->path, alias_path)) != 0)
3630                         goto finish;
3631
3632                 if (streq(verb, "disable"))
3633                         rmdir_parents(alias_path, config_path);
3634         }
3635
3636         r = 0;
3637
3638 finish:
3639         free(alias_path);
3640
3641         return r;
3642 }
3643
3644 static int install_info_symlink_wants(const char *verb, InstallInfo *i, const char *config_path) {
3645         char **s;
3646         char *alias_path = NULL;
3647         int r;
3648
3649         assert(verb);
3650         assert(i);
3651         assert(config_path);
3652
3653         STRV_FOREACH(s, i->wanted_by) {
3654                 if (!unit_name_valid(*s)) {
3655                         log_error("Invalid name %s.", *s);
3656                         r = -EINVAL;
3657                         goto finish;
3658                 }
3659
3660                 free(alias_path);
3661                 alias_path = NULL;
3662
3663                 if (asprintf(&alias_path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) {
3664                         log_error("Out of memory");
3665                         r = -ENOMEM;
3666                         goto finish;
3667                 }
3668
3669                 if ((r = create_symlink(verb, i->path, alias_path)) != 0)
3670                         goto finish;
3671
3672                 if (streq(verb, "disable"))
3673                         rmdir_parents(alias_path, config_path);
3674         }
3675
3676         r = 0;
3677
3678 finish:
3679         free(alias_path);
3680
3681         return r;
3682 }
3683
3684 static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo *i, const char *config_path) {
3685
3686         const ConfigItem items[] = {
3687                 { "Alias",    config_parse_strv, &i->aliases,   "Install" },
3688                 { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
3689                 { "Also",     config_parse_also, NULL,          "Install" },
3690
3691                 { NULL, NULL, NULL, NULL }
3692         };
3693
3694         char **p;
3695         char *filename = NULL;
3696         FILE *f = NULL;
3697         int r;
3698
3699         assert(paths);
3700         assert(i);
3701
3702         STRV_FOREACH(p, paths->unit_path) {
3703                 int fd;
3704
3705                 if (!(filename = path_make_absolute(i->name, *p))) {
3706                         log_error("Out of memory");
3707                         return -ENOMEM;
3708                 }
3709
3710                 /* Ensure that we don't follow symlinks */
3711                 if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
3712                         if ((f = fdopen(fd, "re")))
3713                                 break;
3714
3715                 if (errno == ELOOP) {
3716                         log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
3717                         free(filename);
3718                         return -errno;
3719                 }
3720
3721                 if (errno != ENOENT) {
3722                         log_error("Failed to open %s: %m", filename);
3723                         free(filename);
3724                         return -errno;
3725                 }
3726
3727                 free(filename);
3728                 filename = NULL;
3729         }
3730
3731         if (!f) {
3732                 log_error("Couldn't find %s.", i->name);
3733                 return -ENOENT;
3734         }
3735
3736         i->path = filename;
3737
3738         if ((r = config_parse(filename, f, NULL, items, true, i)) < 0) {
3739                 fclose(f);
3740                 return r;
3741         }
3742
3743         fclose(f);
3744
3745         if ((r = install_info_symlink_alias(verb, i, config_path)) != 0)
3746                 return r;
3747
3748         if ((r = install_info_symlink_wants(verb, i, config_path)) != 0)
3749                 return r;
3750
3751         if ((r = mark_symlink_for_removal(filename)) < 0)
3752                 return r;
3753
3754         if ((r = remove_marked_symlinks(config_path)) < 0)
3755                 return r;
3756
3757         return 0;
3758 }
3759
3760 static char *get_config_path(void) {
3761
3762         if (arg_session && arg_global)
3763                 return strdup(SESSION_CONFIG_UNIT_PATH);
3764
3765         if (arg_session) {
3766                 char *p;
3767
3768                 if (session_config_home(&p) < 0)
3769                         return NULL;
3770
3771                 return p;
3772         }
3773
3774         return strdup(SYSTEM_CONFIG_UNIT_PATH);
3775 }
3776
3777 static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
3778         DBusError error;
3779         int r;
3780         LookupPaths paths;
3781         char *config_path = NULL;
3782         unsigned j;
3783         InstallInfo *i;
3784         const char *verb = args[0];
3785
3786         dbus_error_init(&error);
3787
3788         zero(paths);
3789         if ((r = lookup_paths_init(&paths, arg_session ? MANAGER_SESSION : MANAGER_SYSTEM)) < 0) {
3790                 log_error("Failed to determine lookup paths: %s", strerror(-r));
3791                 goto finish;
3792         }
3793
3794         if (!(config_path = get_config_path())) {
3795                 log_error("Failed to determine config path");
3796                 r = -ENOMEM;
3797                 goto finish;
3798         }
3799
3800         will_install = hashmap_new(string_hash_func, string_compare_func);
3801         have_installed = hashmap_new(string_hash_func, string_compare_func);
3802
3803         if (!will_install || !have_installed) {
3804                 log_error("Failed to allocate unit sets.");
3805                 r = -ENOMEM;
3806                 goto finish;
3807         }
3808
3809         if (!arg_defaults && streq(verb, "disable"))
3810                 if (!(remove_symlinks_to = set_new(string_hash_func, string_compare_func))) {
3811                         log_error("Failed to allocate symlink sets.");
3812                         r = -ENOMEM;
3813                         goto finish;
3814                 }
3815
3816         for (j = 1; j < n; j++)
3817                 if ((r = install_info_add(args[j])) < 0)
3818                         goto finish;
3819
3820         while ((i = hashmap_first(will_install))) {
3821                 int q;
3822
3823                 assert_se(hashmap_move_one(have_installed, will_install, i->name) == 0);
3824
3825                 if ((q = install_info_apply(verb, &paths, i, config_path)) != 0) {
3826
3827                         if (q < 0) {
3828                                 if (r == 0)
3829                                         r = q;
3830                                 goto finish;
3831                         }
3832
3833                         /* In test mode and found something */
3834                         r = 1;
3835                         break;
3836                 }
3837         }
3838
3839         if (streq(verb, "is-enabled"))
3840                 r = r > 0 ? 0 : -ENOENT;
3841         else if (bus &&
3842                  /* Don't try to reload anything if the user asked us to not do this */
3843                  !arg_no_reload &&
3844                  /* Don't try to reload anything when updating a unit globally */
3845                  !arg_global &&
3846                  /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */
3847                  (arg_session || sd_booted() > 0) &&
3848                  /* Don't try to reload anything if we are running in a chroot environment */
3849                  (arg_session || running_in_chroot() <= 0) ) {
3850                 int q;
3851
3852                 if ((q = daemon_reload(bus, args, n)) < 0)
3853                         r = q;
3854         }
3855
3856 finish:
3857         install_info_hashmap_free(will_install);
3858         install_info_hashmap_free(have_installed);
3859
3860         set_free_free(remove_symlinks_to);
3861
3862         lookup_paths_free(&paths);
3863
3864         free(config_path);
3865
3866         return r;
3867 }
3868
3869 static int systemctl_help(void) {
3870
3871         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3872                "Send control commands to or query the systemd manager.\n\n"
3873                "  -h --help          Show this help\n"
3874                "     --version       Show package version\n"
3875                "  -t --type=TYPE     List only units of a particular type\n"
3876                "  -p --property=NAME Show only properties by this name\n"
3877                "  -a --all           Show all units/properties, including dead/empty ones\n"
3878                "     --full          Don't ellipsize unit names on output\n"
3879                "     --fail          When queueing a new job, fail if conflicting jobs are\n"
3880                "                     pending\n"
3881                "  -q --quiet         Suppress output\n"
3882                "     --no-block      Do not wait until operation finished\n"
3883                "     --system        Connect to system bus\n"
3884                "     --session       Connect to session bus\n"
3885                "     --order         When generating graph for dot, show only order\n"
3886                "     --require       When generating graph for dot, show only requirement\n"
3887                "     --no-wall       Don't send wall message before halt/power-off/reboot\n"
3888                "     --global        Enable/disable unit files globally\n"
3889                "     --no-reload     When enabling/disabling unit files, don't reload daemon\n"
3890                "                     configuration\n"
3891                "     --force         When enabling unit files, override existing symlinks\n"
3892                "     --defaults      When disabling unit files, remove default symlinks only\n\n"
3893                "Commands:\n"
3894                "  list-units                      List units\n"
3895                "  start [NAME...]                 Start (activate) one or more units\n"
3896                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
3897                "  reload [NAME...]                Reload one or more units\n"
3898                "  restart [NAME...]               Start or restart one or more units\n"
3899                "  try-restart [NAME...]           Restart one or more units if active\n"
3900                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
3901                "                                  otherwise start or restart\n"
3902                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
3903                "                                  otherwise restart if active\n"
3904                "  isolate [NAME]                  Start one unit and stop all others\n"
3905                "  is-active [NAME...]             Check whether units are active\n"
3906                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
3907                "  show [NAME...|JOB...]           Show properties of one or more\n"
3908                "                                  units/jobs or the manager\n"
3909                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
3910                "                                  units\n"
3911                "  enable [NAME...]                Enable one or more unit files\n"
3912                "  disable [NAME...]               Disable one or more unit files\n"
3913                "  is-enabled [NAME...]            Check whether unit files are enabled\n"
3914                "  load [NAME...]                  Load one or more units\n"
3915                "  list-jobs                       List jobs\n"
3916                "  cancel [JOB...]                 Cancel all, one, or more jobs\n"
3917                "  monitor                         Monitor unit/job changes\n"
3918                "  dump                            Dump server status\n"
3919                "  dot                             Dump dependency graph for dot(1)\n"
3920                "  snapshot [NAME]                 Create a snapshot\n"
3921                "  delete [NAME...]                Remove one or more snapshots\n"
3922                "  daemon-reload                   Reload systemd manager configuration\n"
3923                "  daemon-reexec                   Reexecute systemd manager\n"
3924                "  daemon-exit                     Ask the systemd manager to quit\n"
3925                "  show-environment                Dump environment\n"
3926                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
3927                "  unset-environment [NAME...]     Unset one or more environment variables\n"
3928                "  halt                            Shut down and halt the system\n"
3929                "  poweroff                        Shut down and power-off the system\n"
3930                "  reboot                          Shut down and reboot the system\n"
3931                "  rescue                          Enter system rescue mode\n"
3932                "  emergency                       Enter system emergency mode\n"
3933                "  default                         Enter system default mode\n",
3934                program_invocation_short_name);
3935
3936         return 0;
3937 }
3938
3939 static int halt_help(void) {
3940
3941         printf("%s [OPTIONS...]\n\n"
3942                "%s the system.\n\n"
3943                "     --help      Show this help\n"
3944                "     --halt      Halt the machine\n"
3945                "  -p --poweroff  Switch off the machine\n"
3946                "     --reboot    Reboot the machine\n"
3947                "  -f --force     Force immediate halt/power-off/reboot\n"
3948                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
3949                "  -d --no-wtmp   Don't write wtmp record\n"
3950                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
3951                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
3952                program_invocation_short_name,
3953                arg_action == ACTION_REBOOT   ? "Reboot" :
3954                arg_action == ACTION_POWEROFF ? "Power off" :
3955                                                "Halt");
3956
3957         return 0;
3958 }
3959
3960 static int shutdown_help(void) {
3961
3962         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
3963                "Shut down the system.\n\n"
3964                "     --help      Show this help\n"
3965                "  -H --halt      Halt the machine\n"
3966                "  -P --poweroff  Power-off the machine\n"
3967                "  -r --reboot    Reboot the machine\n"
3968                "  -h             Equivalent to --poweroff, overriden by --halt\n"
3969                "  -k             Don't halt/power-off/reboot, just send warnings\n"
3970                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
3971                "  -c             Cancel a pending shutdown\n",
3972                program_invocation_short_name);
3973
3974         return 0;
3975 }
3976
3977 static int telinit_help(void) {
3978
3979         printf("%s [OPTIONS...] {COMMAND}\n\n"
3980                "Send control commands to the init daemon.\n\n"
3981                "     --help      Show this help\n"
3982                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
3983                "Commands:\n"
3984                "  0              Power-off the machine\n"
3985                "  6              Reboot the machine\n"
3986                "  2, 3, 4, 5     Start runlevelX.target unit\n"
3987                "  1, s, S        Enter rescue mode\n"
3988                "  q, Q           Reload init daemon configuration\n"
3989                "  u, U           Reexecute init daemon\n",
3990                program_invocation_short_name);
3991
3992         return 0;
3993 }
3994
3995 static int runlevel_help(void) {
3996
3997         printf("%s [OPTIONS...]\n\n"
3998                "Prints the previous and current runlevel of the init system.\n\n"
3999                "     --help      Show this help\n",
4000                program_invocation_short_name);
4001
4002         return 0;
4003 }
4004
4005 static int systemctl_parse_argv(int argc, char *argv[]) {
4006
4007         enum {
4008                 ARG_FAIL = 0x100,
4009                 ARG_VERSION,
4010                 ARG_SESSION,
4011                 ARG_SYSTEM,
4012                 ARG_GLOBAL,
4013                 ARG_NO_BLOCK,
4014                 ARG_NO_WALL,
4015                 ARG_ORDER,
4016                 ARG_REQUIRE,
4017                 ARG_FULL,
4018                 ARG_FORCE,
4019                 ARG_NO_RELOAD,
4020                 ARG_DEFAULTS
4021         };
4022
4023         static const struct option options[] = {
4024                 { "help",      no_argument,       NULL, 'h'           },
4025                 { "version",   no_argument,       NULL, ARG_VERSION   },
4026                 { "type",      required_argument, NULL, 't'           },
4027                 { "property",  required_argument, NULL, 'p'           },
4028                 { "all",       no_argument,       NULL, 'a'           },
4029                 { "full",      no_argument,       NULL, ARG_FULL      },
4030                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4031                 { "session",   no_argument,       NULL, ARG_SESSION   },
4032                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4033                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4034                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4035                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4036                 { "quiet",     no_argument,       NULL, 'q'           },
4037                 { "order",     no_argument,       NULL, ARG_ORDER     },
4038                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4039                 { "force",     no_argument,       NULL, ARG_FORCE     },
4040                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4041                 { "defaults",  no_argument,       NULL, ARG_DEFAULTS  },
4042                 { NULL,        0,                 NULL, 0             }
4043         };
4044
4045         int c;
4046
4047         assert(argc >= 0);
4048         assert(argv);
4049
4050         while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
4051
4052                 switch (c) {
4053
4054                 case 'h':
4055                         systemctl_help();
4056                         return 0;
4057
4058                 case ARG_VERSION:
4059                         puts(PACKAGE_STRING);
4060                         puts(DISTRIBUTION);
4061                         puts(SYSTEMD_FEATURES);
4062                         return 0;
4063
4064                 case 't':
4065                         arg_type = optarg;
4066                         break;
4067
4068                 case 'p': {
4069                         char **l;
4070
4071                         if (!(l = strv_append(arg_property, optarg)))
4072                                 return -ENOMEM;
4073
4074                         strv_free(arg_property);
4075                         arg_property = l;
4076
4077                         /* If the user asked for a particular
4078                          * property, show it to him, even if it is
4079                          * empty. */
4080                         arg_all = true;
4081                         break;
4082                 }
4083
4084                 case 'a':
4085                         arg_all = true;
4086                         break;
4087
4088                 case ARG_FAIL:
4089                         arg_fail = true;
4090                         break;
4091
4092                 case ARG_SESSION:
4093                         arg_session = true;
4094                         break;
4095
4096                 case ARG_SYSTEM:
4097                         arg_session = false;
4098                         break;
4099
4100                 case ARG_NO_BLOCK:
4101                         arg_no_block = true;
4102                         break;
4103
4104                 case ARG_NO_WALL:
4105                         arg_no_wall = true;
4106                         break;
4107
4108                 case ARG_ORDER:
4109                         arg_dot = DOT_ORDER;
4110                         break;
4111
4112                 case ARG_REQUIRE:
4113                         arg_dot = DOT_REQUIRE;
4114                         break;
4115
4116                 case ARG_FULL:
4117                         arg_full = true;
4118                         break;
4119
4120                 case 'q':
4121                         arg_quiet = true;
4122                         break;
4123
4124                 case ARG_FORCE:
4125                         arg_force = true;
4126                         break;
4127
4128                 case ARG_NO_RELOAD:
4129                         arg_no_reload = true;
4130                         break;
4131
4132                 case ARG_GLOBAL:
4133                         arg_global = true;
4134                         arg_session = true;
4135                         break;
4136
4137                 case ARG_DEFAULTS:
4138                         arg_defaults = true;
4139                         break;
4140
4141                 case '?':
4142                         return -EINVAL;
4143
4144                 default:
4145                         log_error("Unknown option code %c", c);
4146                         return -EINVAL;
4147                 }
4148         }
4149
4150         return 1;
4151 }
4152
4153 static int halt_parse_argv(int argc, char *argv[]) {
4154
4155         enum {
4156                 ARG_HELP = 0x100,
4157                 ARG_HALT,
4158                 ARG_REBOOT,
4159                 ARG_NO_WALL
4160         };
4161
4162         static const struct option options[] = {
4163                 { "help",      no_argument,       NULL, ARG_HELP    },
4164                 { "halt",      no_argument,       NULL, ARG_HALT    },
4165                 { "poweroff",  no_argument,       NULL, 'p'         },
4166                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4167                 { "force",     no_argument,       NULL, 'f'         },
4168                 { "wtmp-only", no_argument,       NULL, 'w'         },
4169                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4170                 { "no-sync",   no_argument,       NULL, 'n'         },
4171                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4172                 { NULL,        0,                 NULL, 0           }
4173         };
4174
4175         int c, runlevel;
4176
4177         assert(argc >= 0);
4178         assert(argv);
4179
4180         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4181                 if (runlevel == '0' || runlevel == '6')
4182                         arg_immediate = true;
4183
4184         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4185                 switch (c) {
4186
4187                 case ARG_HELP:
4188                         halt_help();
4189                         return 0;
4190
4191                 case ARG_HALT:
4192                         arg_action = ACTION_HALT;
4193                         break;
4194
4195                 case 'p':
4196                         if (arg_action != ACTION_REBOOT)
4197                                 arg_action = ACTION_POWEROFF;
4198                         break;
4199
4200                 case ARG_REBOOT:
4201                         arg_action = ACTION_REBOOT;
4202                         break;
4203
4204                 case 'f':
4205                         arg_immediate = true;
4206                         break;
4207
4208                 case 'w':
4209                         arg_dry = true;
4210                         break;
4211
4212                 case 'd':
4213                         arg_no_wtmp = true;
4214                         break;
4215
4216                 case 'n':
4217                         arg_no_sync = true;
4218                         break;
4219
4220                 case ARG_NO_WALL:
4221                         arg_no_wall = true;
4222                         break;
4223
4224                 case 'i':
4225                 case 'h':
4226                         /* Compatibility nops */
4227                         break;
4228
4229                 case '?':
4230                         return -EINVAL;
4231
4232                 default:
4233                         log_error("Unknown option code %c", c);
4234                         return -EINVAL;
4235                 }
4236         }
4237
4238         if (optind < argc) {
4239                 log_error("Too many arguments.");
4240                 return -EINVAL;
4241         }
4242
4243         return 1;
4244 }
4245
4246 static int parse_time_spec(const char *t, usec_t *_u) {
4247         assert(t);
4248         assert(_u);
4249
4250         if (streq(t, "now"))
4251                 *_u = 0;
4252         else if (t[0] == '+') {
4253                 uint64_t u;
4254
4255                 if (safe_atou64(t + 1, &u) < 0)
4256                         return -EINVAL;
4257
4258                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4259         } else {
4260                 char *e = NULL;
4261                 long hour, minute;
4262                 struct tm tm;
4263                 time_t s;
4264                 usec_t n;
4265
4266                 errno = 0;
4267                 hour = strtol(t, &e, 10);
4268                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4269                         return -EINVAL;
4270
4271                 minute = strtol(e+1, &e, 10);
4272                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4273                         return -EINVAL;
4274
4275                 n = now(CLOCK_REALTIME);
4276                 s = (time_t) (n / USEC_PER_SEC);
4277
4278                 zero(tm);
4279                 assert_se(localtime_r(&s, &tm));
4280
4281                 tm.tm_hour = (int) hour;
4282                 tm.tm_min = (int) minute;
4283                 tm.tm_sec = 0;
4284
4285                 assert_se(s = mktime(&tm));
4286
4287                 *_u = (usec_t) s * USEC_PER_SEC;
4288
4289                 while (*_u <= n)
4290                         *_u += USEC_PER_DAY;
4291         }
4292
4293         return 0;
4294 }
4295
4296 static int shutdown_parse_argv(int argc, char *argv[]) {
4297
4298         enum {
4299                 ARG_HELP = 0x100,
4300                 ARG_NO_WALL
4301         };
4302
4303         static const struct option options[] = {
4304                 { "help",      no_argument,       NULL, ARG_HELP    },
4305                 { "halt",      no_argument,       NULL, 'H'         },
4306                 { "poweroff",  no_argument,       NULL, 'P'         },
4307                 { "reboot",    no_argument,       NULL, 'r'         },
4308                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4309                 { NULL,        0,                 NULL, 0           }
4310         };
4311
4312         int c, r;
4313
4314         assert(argc >= 0);
4315         assert(argv);
4316
4317         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4318                 switch (c) {
4319
4320                 case ARG_HELP:
4321                         shutdown_help();
4322                         return 0;
4323
4324                 case 'H':
4325                         arg_action = ACTION_HALT;
4326                         break;
4327
4328                 case 'P':
4329                         arg_action = ACTION_POWEROFF;
4330                         break;
4331
4332                 case 'r':
4333                         arg_action = ACTION_REBOOT;
4334                         break;
4335
4336                 case 'h':
4337                         if (arg_action != ACTION_HALT)
4338                                 arg_action = ACTION_POWEROFF;
4339                         break;
4340
4341                 case 'k':
4342                         arg_dry = true;
4343                         break;
4344
4345                 case ARG_NO_WALL:
4346                         arg_no_wall = true;
4347                         break;
4348
4349                 case 't':
4350                 case 'a':
4351                         /* Compatibility nops */
4352                         break;
4353
4354                 case 'c':
4355                         arg_action = ACTION_CANCEL_SHUTDOWN;
4356                         break;
4357
4358                 case '?':
4359                         return -EINVAL;
4360
4361                 default:
4362                         log_error("Unknown option code %c", c);
4363                         return -EINVAL;
4364                 }
4365         }
4366
4367         if (argc > optind) {
4368                 if ((r = parse_time_spec(argv[optind], &arg_when)) < 0) {
4369                         log_error("Failed to parse time specification: %s", argv[optind]);
4370                         return r;
4371                 }
4372         } else
4373                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4374
4375         /* We skip the time argument */
4376         if (argc > optind + 1)
4377                 arg_wall = argv + optind + 1;
4378
4379         optind = argc;
4380
4381         return 1;
4382 }
4383
4384 static int telinit_parse_argv(int argc, char *argv[]) {
4385
4386         enum {
4387                 ARG_HELP = 0x100,
4388                 ARG_NO_WALL
4389         };
4390
4391         static const struct option options[] = {
4392                 { "help",      no_argument,       NULL, ARG_HELP    },
4393                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4394                 { NULL,        0,                 NULL, 0           }
4395         };
4396
4397         static const struct {
4398                 char from;
4399                 enum action to;
4400         } table[] = {
4401                 { '0', ACTION_POWEROFF },
4402                 { '6', ACTION_REBOOT },
4403                 { '1', ACTION_RESCUE },
4404                 { '2', ACTION_RUNLEVEL2 },
4405                 { '3', ACTION_RUNLEVEL3 },
4406                 { '4', ACTION_RUNLEVEL4 },
4407                 { '5', ACTION_RUNLEVEL5 },
4408                 { 's', ACTION_RESCUE },
4409                 { 'S', ACTION_RESCUE },
4410                 { 'q', ACTION_RELOAD },
4411                 { 'Q', ACTION_RELOAD },
4412                 { 'u', ACTION_REEXEC },
4413                 { 'U', ACTION_REEXEC }
4414         };
4415
4416         unsigned i;
4417         int c;
4418
4419         assert(argc >= 0);
4420         assert(argv);
4421
4422         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4423                 switch (c) {
4424
4425                 case ARG_HELP:
4426                         telinit_help();
4427                         return 0;
4428
4429                 case ARG_NO_WALL:
4430                         arg_no_wall = true;
4431                         break;
4432
4433                 case '?':
4434                         return -EINVAL;
4435
4436                 default:
4437                         log_error("Unknown option code %c", c);
4438                         return -EINVAL;
4439                 }
4440         }
4441
4442         if (optind >= argc) {
4443                 telinit_help();
4444                 return -EINVAL;
4445         }
4446
4447         if (optind + 1 < argc) {
4448                 log_error("Too many arguments.");
4449                 return -EINVAL;
4450         }
4451
4452         if (strlen(argv[optind]) != 1) {
4453                 log_error("Expected single character argument.");
4454                 return -EINVAL;
4455         }
4456
4457         for (i = 0; i < ELEMENTSOF(table); i++)
4458                 if (table[i].from == argv[optind][0])
4459                         break;
4460
4461         if (i >= ELEMENTSOF(table)) {
4462                 log_error("Unknown command %s.", argv[optind]);
4463                 return -EINVAL;
4464         }
4465
4466         arg_action = table[i].to;
4467
4468         optind ++;
4469
4470         return 1;
4471 }
4472
4473 static int runlevel_parse_argv(int argc, char *argv[]) {
4474
4475         enum {
4476                 ARG_HELP = 0x100,
4477         };
4478
4479         static const struct option options[] = {
4480                 { "help",      no_argument,       NULL, ARG_HELP    },
4481                 { NULL,        0,                 NULL, 0           }
4482         };
4483
4484         int c;
4485
4486         assert(argc >= 0);
4487         assert(argv);
4488
4489         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4490                 switch (c) {
4491
4492                 case ARG_HELP:
4493                         runlevel_help();
4494                         return 0;
4495
4496                 case '?':
4497                         return -EINVAL;
4498
4499                 default:
4500                         log_error("Unknown option code %c", c);
4501                         return -EINVAL;
4502                 }
4503         }
4504
4505         if (optind < argc) {
4506                 log_error("Too many arguments.");
4507                 return -EINVAL;
4508         }
4509
4510         return 1;
4511 }
4512
4513 static int parse_argv(int argc, char *argv[]) {
4514         assert(argc >= 0);
4515         assert(argv);
4516
4517         if (program_invocation_short_name) {
4518
4519                 if (strstr(program_invocation_short_name, "halt")) {
4520                         arg_action = ACTION_HALT;
4521                         return halt_parse_argv(argc, argv);
4522                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4523                         arg_action = ACTION_POWEROFF;
4524                         return halt_parse_argv(argc, argv);
4525                 } else if (strstr(program_invocation_short_name, "reboot")) {
4526                         arg_action = ACTION_REBOOT;
4527                         return halt_parse_argv(argc, argv);
4528                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4529                         arg_action = ACTION_POWEROFF;
4530                         return shutdown_parse_argv(argc, argv);
4531                 } else if (strstr(program_invocation_short_name, "init")) {
4532
4533                         if (sd_booted() > 0) {
4534                                 arg_action = ACTION_INVALID;
4535                                 return telinit_parse_argv(argc, argv);
4536                         } else {
4537                                 /* Hmm, so some other init system is
4538                                  * running, we need to forward this
4539                                  * request to it. For now we simply
4540                                  * guess that it is Upstart. */
4541
4542                                 execv("/lib/upstart/telinit", argv);
4543
4544                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4545                                 return -EIO;
4546                         }
4547
4548                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4549                         arg_action = ACTION_RUNLEVEL;
4550                         return runlevel_parse_argv(argc, argv);
4551                 }
4552         }
4553
4554         arg_action = ACTION_SYSTEMCTL;
4555         return systemctl_parse_argv(argc, argv);
4556 }
4557
4558 static int action_to_runlevel(void) {
4559
4560         static const char table[_ACTION_MAX] = {
4561                 [ACTION_HALT] =      '0',
4562                 [ACTION_POWEROFF] =  '0',
4563                 [ACTION_REBOOT] =    '6',
4564                 [ACTION_RUNLEVEL2] = '2',
4565                 [ACTION_RUNLEVEL3] = '3',
4566                 [ACTION_RUNLEVEL4] = '4',
4567                 [ACTION_RUNLEVEL5] = '5',
4568                 [ACTION_RESCUE] =    '1'
4569         };
4570
4571         assert(arg_action < _ACTION_MAX);
4572
4573         return table[arg_action];
4574 }
4575
4576 static int talk_upstart(void) {
4577         DBusMessage *m = NULL, *reply = NULL;
4578         DBusError error;
4579         int previous, rl, r;
4580         char
4581                 env1_buf[] = "RUNLEVEL=X",
4582                 env2_buf[] = "PREVLEVEL=X";
4583         char *env1 = env1_buf, *env2 = env2_buf;
4584         const char *emit = "runlevel";
4585         dbus_bool_t b_false = FALSE;
4586         DBusMessageIter iter, sub;
4587         DBusConnection *bus;
4588
4589         dbus_error_init(&error);
4590
4591         if (!(rl = action_to_runlevel()))
4592                 return 0;
4593
4594         if (utmp_get_runlevel(&previous, NULL) < 0)
4595                 previous = 'N';
4596
4597         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4598                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4599                         r = 0;
4600                         goto finish;
4601                 }
4602
4603                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4604                 r = -EIO;
4605                 goto finish;
4606         }
4607
4608         if ((r = bus_check_peercred(bus)) < 0) {
4609                 log_error("Failed to verify owner of bus.");
4610                 goto finish;
4611         }
4612
4613         if (!(m = dbus_message_new_method_call(
4614                               "com.ubuntu.Upstart",
4615                               "/com/ubuntu/Upstart",
4616                               "com.ubuntu.Upstart0_6",
4617                               "EmitEvent"))) {
4618
4619                 log_error("Could not allocate message.");
4620                 r = -ENOMEM;
4621                 goto finish;
4622         }
4623
4624         dbus_message_iter_init_append(m, &iter);
4625
4626         env1_buf[sizeof(env1_buf)-2] = rl;
4627         env2_buf[sizeof(env2_buf)-2] = previous;
4628
4629         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4630             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4631             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4632             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4633             !dbus_message_iter_close_container(&iter, &sub) ||
4634             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4635                 log_error("Could not append arguments to message.");
4636                 r = -ENOMEM;
4637                 goto finish;
4638         }
4639
4640         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4641
4642                 if (error_is_no_service(&error)) {
4643                         r = -EADDRNOTAVAIL;
4644                         goto finish;
4645                 }
4646
4647                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4648                 r = -EIO;
4649                 goto finish;
4650         }
4651
4652         r = 0;
4653
4654 finish:
4655         if (m)
4656                 dbus_message_unref(m);
4657
4658         if (reply)
4659                 dbus_message_unref(reply);
4660
4661         if (bus) {
4662                 dbus_connection_flush(bus);
4663                 dbus_connection_close(bus);
4664                 dbus_connection_unref(bus);
4665         }
4666
4667         dbus_error_free(&error);
4668
4669         return r;
4670 }
4671
4672 static int talk_initctl(void) {
4673         struct init_request request;
4674         int r, fd;
4675         char rl;
4676
4677         if (!(rl = action_to_runlevel()))
4678                 return 0;
4679
4680         zero(request);
4681         request.magic = INIT_MAGIC;
4682         request.sleeptime = 0;
4683         request.cmd = INIT_CMD_RUNLVL;
4684         request.runlevel = rl;
4685
4686         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4687
4688                 if (errno == ENOENT)
4689                         return 0;
4690
4691                 log_error("Failed to open "INIT_FIFO": %m");
4692                 return -errno;
4693         }
4694
4695         errno = 0;
4696         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4697         close_nointr_nofail(fd);
4698
4699         if (r < 0) {
4700                 log_error("Failed to write to "INIT_FIFO": %m");
4701                 return errno ? -errno : -EIO;
4702         }
4703
4704         return 1;
4705 }
4706
4707 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4708
4709         static const struct {
4710                 const char* verb;
4711                 const enum {
4712                         MORE,
4713                         LESS,
4714                         EQUAL
4715                 } argc_cmp;
4716                 const int argc;
4717                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
4718         } verbs[] = {
4719                 { "list-units",            LESS,  1, list_units        },
4720                 { "list-jobs",             EQUAL, 1, list_jobs         },
4721                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
4722                 { "load",                  MORE,  2, load_unit         },
4723                 { "cancel",                MORE,  2, cancel_job        },
4724                 { "start",                 MORE,  2, start_unit        },
4725                 { "stop",                  MORE,  2, start_unit        },
4726                 { "reload",                MORE,  2, start_unit        },
4727                 { "restart",               MORE,  2, start_unit        },
4728                 { "try-restart",           MORE,  2, start_unit        },
4729                 { "reload-or-restart",     MORE,  2, start_unit        },
4730                 { "reload-or-try-restart", MORE,  2, start_unit        },
4731                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
4732                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
4733                 { "isolate",               EQUAL, 2, start_unit        },
4734                 { "is-active",             MORE,  2, check_unit        },
4735                 { "check",                 MORE,  2, check_unit        },
4736                 { "show",                  MORE,  1, show              },
4737                 { "status",                MORE,  2, show              },
4738                 { "monitor",               EQUAL, 1, monitor           },
4739                 { "dump",                  EQUAL, 1, dump              },
4740                 { "dot",                   EQUAL, 1, dot               },
4741                 { "snapshot",              LESS,  2, snapshot          },
4742                 { "delete",                MORE,  2, delete_snapshot   },
4743                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
4744                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
4745                 { "daemon-exit",           EQUAL, 1, daemon_reload     },
4746                 { "show-environment",      EQUAL, 1, show_enviroment   },
4747                 { "set-environment",       MORE,  2, set_environment   },
4748                 { "unset-environment",     MORE,  2, set_environment   },
4749                 { "halt",                  EQUAL, 1, start_special     },
4750                 { "poweroff",              EQUAL, 1, start_special     },
4751                 { "reboot",                EQUAL, 1, start_special     },
4752                 { "default",               EQUAL, 1, start_special     },
4753                 { "rescue",                EQUAL, 1, start_special     },
4754                 { "emergency",             EQUAL, 1, start_special     },
4755                 { "reset-failed",          MORE,  1, reset_failed      },
4756                 { "enable",                MORE,  2, enable_unit       },
4757                 { "disable",               MORE,  2, enable_unit       },
4758                 { "is-enabled",            MORE,  2, enable_unit       }
4759         };
4760
4761         int left;
4762         unsigned i;
4763
4764         assert(argc >= 0);
4765         assert(argv);
4766         assert(error);
4767
4768         left = argc - optind;
4769
4770         if (left <= 0)
4771                 /* Special rule: no arguments means "list-units" */
4772                 i = 0;
4773         else {
4774                 if (streq(argv[optind], "help")) {
4775                         systemctl_help();
4776                         return 0;
4777                 }
4778
4779                 for (i = 0; i < ELEMENTSOF(verbs); i++)
4780                         if (streq(argv[optind], verbs[i].verb))
4781                                 break;
4782
4783                 if (i >= ELEMENTSOF(verbs)) {
4784                         log_error("Unknown operation %s", argv[optind]);
4785                         return -EINVAL;
4786                 }
4787         }
4788
4789         switch (verbs[i].argc_cmp) {
4790
4791         case EQUAL:
4792                 if (left != verbs[i].argc) {
4793                         log_error("Invalid number of arguments.");
4794                         return -EINVAL;
4795                 }
4796
4797                 break;
4798
4799         case MORE:
4800                 if (left < verbs[i].argc) {
4801                         log_error("Too few arguments.");
4802                         return -EINVAL;
4803                 }
4804
4805                 break;
4806
4807         case LESS:
4808                 if (left > verbs[i].argc) {
4809                         log_error("Too many arguments.");
4810                         return -EINVAL;
4811                 }
4812
4813                 break;
4814
4815         default:
4816                 assert_not_reached("Unknown comparison operator.");
4817         }
4818
4819         /* Require a bus connection for all operations but
4820          * enable/disable */
4821         if (!streq(verbs[i].verb, "enable") &&
4822             !streq(verbs[i].verb, "disable") &&
4823             !bus) {
4824                 log_error("Failed to get D-Bus connection: %s", error->message);
4825                 return -EIO;
4826         }
4827
4828         return verbs[i].dispatch(bus, argv + optind, left);
4829 }
4830
4831 static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
4832         int fd = -1;
4833         struct msghdr msghdr;
4834         struct iovec iovec;
4835         union sockaddr_union sockaddr;
4836         struct shutdownd_command c;
4837
4838         zero(c);
4839         c.elapse = t;
4840         c.mode = mode;
4841         c.warn_wall = warn;
4842
4843         if (message)
4844                 strncpy(c.wall_message, message, sizeof(c.wall_message));
4845
4846         if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0)
4847                 return -errno;
4848
4849         zero(sockaddr);
4850         sockaddr.sa.sa_family = AF_UNIX;
4851         sockaddr.un.sun_path[0] = 0;
4852         strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
4853
4854         zero(iovec);
4855         iovec.iov_base = (char*) &c;
4856         iovec.iov_len = sizeof(c);
4857
4858         zero(msghdr);
4859         msghdr.msg_name = &sockaddr;
4860         msghdr.msg_namelen = sizeof(sa_family_t) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
4861
4862         msghdr.msg_iov = &iovec;
4863         msghdr.msg_iovlen = 1;
4864
4865         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
4866                 close_nointr_nofail(fd);
4867                 return -errno;
4868         }
4869
4870         close_nointr_nofail(fd);
4871         return 0;
4872 }
4873
4874 static int reload_with_fallback(DBusConnection *bus) {
4875
4876         if (bus) {
4877                 /* First, try systemd via D-Bus. */
4878                 if (daemon_reload(bus, NULL, 0) > 0)
4879                         return 0;
4880         }
4881
4882         /* Nothing else worked, so let's try signals */
4883         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
4884
4885         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
4886                 log_error("kill() failed: %m");
4887                 return -errno;
4888         }
4889
4890         return 0;
4891 }
4892
4893 static int start_with_fallback(DBusConnection *bus) {
4894
4895         if (bus) {
4896                 /* First, try systemd via D-Bus. */
4897                 if (start_unit(bus, NULL, 0) >= 0)
4898                         goto done;
4899         }
4900
4901         /* Hmm, talking to systemd via D-Bus didn't work. Then
4902          * let's try to talk to Upstart via D-Bus. */
4903         if (talk_upstart() > 0)
4904                 goto done;
4905
4906         /* Nothing else worked, so let's try
4907          * /dev/initctl */
4908         if (talk_initctl() > 0)
4909                 goto done;
4910
4911         log_error("Failed to talk to init daemon.");
4912         return -EIO;
4913
4914 done:
4915         warn_wall(arg_action);
4916         return 0;
4917 }
4918
4919 static int halt_main(DBusConnection *bus) {
4920         int r;
4921
4922         if (geteuid() != 0) {
4923                 log_error("Must be root.");
4924                 return -EPERM;
4925         }
4926
4927         if (arg_when > 0) {
4928                 char *m;
4929                 char date[FORMAT_TIMESTAMP_MAX];
4930
4931                 m = strv_join(arg_wall, " ");
4932                 r = send_shutdownd(arg_when,
4933                                    arg_action == ACTION_HALT     ? 'H' :
4934                                    arg_action == ACTION_POWEROFF ? 'P' :
4935                                                                    'r',
4936                                    !arg_no_wall,
4937                                    m);
4938                 free(m);
4939
4940                 if (r < 0)
4941                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
4942                 else {
4943                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
4944                                  format_timestamp(date, sizeof(date), arg_when));
4945                         return 0;
4946                 }
4947         }
4948
4949         if (!arg_dry && !arg_immediate)
4950                 return start_with_fallback(bus);
4951
4952         if (!arg_no_wtmp) {
4953                 if (sd_booted() > 0)
4954                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
4955                 else if ((r = utmp_put_shutdown(0)) < 0)
4956                         log_warning("Failed to write utmp record: %s", strerror(-r));
4957         }
4958
4959         if (!arg_no_sync)
4960                 sync();
4961
4962         if (arg_dry)
4963                 return 0;
4964
4965         /* Make sure C-A-D is handled by the kernel from this
4966          * point on... */
4967         reboot(RB_ENABLE_CAD);
4968
4969         switch (arg_action) {
4970
4971         case ACTION_HALT:
4972                 log_info("Halting.");
4973                 reboot(RB_HALT_SYSTEM);
4974                 break;
4975
4976         case ACTION_POWEROFF:
4977                 log_info("Powering off.");
4978                 reboot(RB_POWER_OFF);
4979                 break;
4980
4981         case ACTION_REBOOT:
4982                 log_info("Rebooting.");
4983                 reboot(RB_AUTOBOOT);
4984                 break;
4985
4986         default:
4987                 assert_not_reached("Unknown halt action.");
4988         }
4989
4990         /* We should never reach this. */
4991         return -ENOSYS;
4992 }
4993
4994 static int runlevel_main(void) {
4995         int r, runlevel, previous;
4996
4997         if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
4998                 printf("unknown\n");
4999                 return r;
5000         }
5001
5002         printf("%c %c\n",
5003                previous <= 0 ? 'N' : previous,
5004                runlevel <= 0 ? 'N' : runlevel);
5005
5006         return 0;
5007 }
5008
5009 int main(int argc, char*argv[]) {
5010         int r, retval = EXIT_FAILURE;
5011         DBusConnection *bus = NULL;
5012         DBusError error;
5013
5014         dbus_error_init(&error);
5015
5016         log_parse_environment();
5017         log_open();
5018
5019         if ((r = parse_argv(argc, argv)) < 0)
5020                 goto finish;
5021         else if (r == 0) {
5022                 retval = EXIT_SUCCESS;
5023                 goto finish;
5024         }
5025
5026         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5027          * let's shortcut this */
5028         if (arg_action == ACTION_RUNLEVEL) {
5029                 r = runlevel_main();
5030                 retval = r < 0 ? EXIT_FAILURE : r;
5031                 goto finish;
5032         }
5033
5034         bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
5035
5036         switch (arg_action) {
5037
5038         case ACTION_SYSTEMCTL:
5039                 r = systemctl_main(bus, argc, argv, &error);
5040                 break;
5041
5042         case ACTION_HALT:
5043         case ACTION_POWEROFF:
5044         case ACTION_REBOOT:
5045                 r = halt_main(bus);
5046                 break;
5047
5048         case ACTION_RUNLEVEL2:
5049         case ACTION_RUNLEVEL3:
5050         case ACTION_RUNLEVEL4:
5051         case ACTION_RUNLEVEL5:
5052         case ACTION_RESCUE:
5053         case ACTION_EMERGENCY:
5054         case ACTION_DEFAULT:
5055                 r = start_with_fallback(bus);
5056                 break;
5057
5058         case ACTION_RELOAD:
5059         case ACTION_REEXEC:
5060                 r = reload_with_fallback(bus);
5061                 break;
5062
5063         case ACTION_CANCEL_SHUTDOWN:
5064                 r = send_shutdownd(0, 0, false, NULL);
5065                 break;
5066
5067         case ACTION_INVALID:
5068         case ACTION_RUNLEVEL:
5069         default:
5070                 assert_not_reached("Unknown action");
5071         }
5072
5073         retval = r < 0 ? EXIT_FAILURE : r;
5074
5075 finish:
5076
5077         if (bus) {
5078                 dbus_connection_flush(bus);
5079                 dbus_connection_close(bus);
5080                 dbus_connection_unref(bus);
5081         }
5082
5083         dbus_error_free(&error);
5084
5085         dbus_shutdown();
5086
5087         strv_free(arg_property);
5088
5089         return retval;
5090 }