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