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