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