chiark / gitweb /
systemctl: minor optimizations
[elogind.git] / src / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <stddef.h>
35 #include <sys/prctl.h>
36
37 #include <dbus/dbus.h>
38
39 #include "log.h"
40 #include "util.h"
41 #include "macro.h"
42 #include "set.h"
43 #include "utmp-wtmp.h"
44 #include "special.h"
45 #include "initreq.h"
46 #include "strv.h"
47 #include "dbus-common.h"
48 #include "cgroup-show.h"
49 #include "cgroup-util.h"
50 #include "list.h"
51 #include "path-lookup.h"
52 #include "conf-parser.h"
53 #include "sd-daemon.h"
54 #include "shutdownd.h"
55 #include "exit-status.h"
56 #include "bus-errors.h"
57 #include "build.h"
58 #include "unit-name.h"
59
60 static const char *arg_type = NULL;
61 static char **arg_property = NULL;
62 static bool arg_all = false;
63 static bool arg_fail = false;
64 static bool arg_user = false;
65 static bool arg_global = false;
66 static bool arg_immediate = false;
67 static bool arg_no_block = false;
68 static bool arg_no_pager = false;
69 static bool arg_no_wtmp = false;
70 static bool arg_no_sync = false;
71 static bool arg_no_wall = false;
72 static bool arg_no_reload = false;
73 static bool arg_dry = false;
74 static bool arg_quiet = false;
75 static bool arg_full = false;
76 static bool arg_force = false;
77 static bool arg_defaults = false;
78 static bool arg_ask_password = false;
79 static char **arg_wall = NULL;
80 static const char *arg_kill_who = NULL;
81 static const char *arg_kill_mode = NULL;
82 static int arg_signal = SIGTERM;
83 static usec_t arg_when = 0;
84 static enum action {
85         ACTION_INVALID,
86         ACTION_SYSTEMCTL,
87         ACTION_HALT,
88         ACTION_POWEROFF,
89         ACTION_REBOOT,
90         ACTION_KEXEC,
91         ACTION_EXIT,
92         ACTION_RUNLEVEL2,
93         ACTION_RUNLEVEL3,
94         ACTION_RUNLEVEL4,
95         ACTION_RUNLEVEL5,
96         ACTION_RESCUE,
97         ACTION_EMERGENCY,
98         ACTION_DEFAULT,
99         ACTION_RELOAD,
100         ACTION_REEXEC,
101         ACTION_RUNLEVEL,
102         ACTION_CANCEL_SHUTDOWN,
103         _ACTION_MAX
104 } arg_action = ACTION_SYSTEMCTL;
105 static enum dot {
106         DOT_ALL,
107         DOT_ORDER,
108         DOT_REQUIRE
109 } arg_dot = DOT_ALL;
110
111 static bool private_bus = false;
112
113 static pid_t pager_pid = 0;
114
115 static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
116 static void pager_open(void);
117
118 static bool on_tty(void) {
119         static int t = -1;
120
121         /* Note that this is invoked relatively early, before we start
122          * the pager. That means the value we return reflects whether
123          * we originally were started on a tty, not if we currently
124          * are. But this is intended, since we want colour and so on
125          * when run in our own pager. */
126
127         if (_unlikely_(t < 0))
128                 t = isatty(STDOUT_FILENO) > 0;
129
130         return t;
131 }
132
133 static void spawn_ask_password_agent(void) {
134         pid_t parent, child;
135
136         /* We check STDIN here, not STDOUT, since this is about input,
137          * not output */
138         if (!isatty(STDIN_FILENO))
139                 return;
140
141         if (!arg_ask_password)
142                 return;
143
144         if (arg_user)
145                 return;
146
147         parent = getpid();
148
149         /* Spawns a temporary TTY agent, making sure it goes away when
150          * we go away */
151
152         if ((child = fork()) < 0)
153                 return;
154
155         if (child == 0) {
156                 /* In the child */
157                 const char * const args[] = {
158                         SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
159                         "--watch",
160                         NULL
161                 };
162
163                 int fd;
164                 bool stdout_is_tty, stderr_is_tty;
165
166                 /* Make sure the agent goes away when the parent dies */
167                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
168                         _exit(EXIT_FAILURE);
169
170                 /* Check whether our parent died before we were able
171                  * to set the death signal */
172                 if (getppid() != parent)
173                         _exit(EXIT_SUCCESS);
174
175                 /* Don't leak fds to the agent */
176                 close_all_fds(NULL, 0);
177
178                 stdout_is_tty = isatty(STDOUT_FILENO);
179                 stderr_is_tty = isatty(STDERR_FILENO);
180
181                 if (!stdout_is_tty || !stderr_is_tty) {
182                         /* Detach from stdout/stderr. and reopen
183                          * /dev/tty for them. This is important to
184                          * ensure that when systemctl is started via
185                          * popen() or a similar call that expects to
186                          * read EOF we actually do generate EOF and
187                          * not delay this indefinitely by because we
188                          * keep an unused copy of stdin around. */
189                         if ((fd = open("/dev/tty", O_WRONLY)) < 0) {
190                                 log_error("Failed to open /dev/tty: %m");
191                                 _exit(EXIT_FAILURE);
192                         }
193
194                         if (!stdout_is_tty)
195                                 dup2(fd, STDOUT_FILENO);
196
197                         if (!stderr_is_tty)
198                                 dup2(fd, STDERR_FILENO);
199
200                         if (fd > 2)
201                                 close(fd);
202                 }
203
204                 execv(args[0], (char **) args);
205                 _exit(EXIT_FAILURE);
206         }
207 }
208
209 static const char *ansi_highlight(bool b) {
210
211         if (!on_tty())
212                 return "";
213
214         return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
215 }
216
217 static const char *ansi_highlight_green(bool b) {
218
219         if (!on_tty())
220                 return "";
221
222         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
223 }
224
225 static bool error_is_no_service(const DBusError *error) {
226         assert(error);
227
228         if (!dbus_error_is_set(error))
229                 return false;
230
231         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
232                 return true;
233
234         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
235                 return true;
236
237         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
238 }
239
240 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
241         assert(error);
242
243         if (!dbus_error_is_set(error))
244                 return r;
245
246         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
247             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
248             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
249             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
250                 return EXIT_NOPERMISSION;
251
252         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
253                 return EXIT_NOTINSTALLED;
254
255         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
256             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
257                 return EXIT_NOTIMPLEMENTED;
258
259         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
260                 return EXIT_NOTCONFIGURED;
261
262         if (r != 0)
263                 return r;
264
265         return EXIT_FAILURE;
266 }
267
268 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
269
270         assert(iter);
271         assert(data);
272
273         if (dbus_message_iter_get_arg_type(iter) != type)
274                 return -EIO;
275
276         dbus_message_iter_get_basic(iter, data);
277
278         if (!dbus_message_iter_next(iter) != !next)
279                 return -EIO;
280
281         return 0;
282 }
283
284 static void warn_wall(enum action action) {
285         static const char *table[_ACTION_MAX] = {
286                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
287                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
288                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
289                 [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
290                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
291                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
292         };
293
294         if (arg_no_wall)
295                 return;
296
297         if (arg_wall) {
298                 char *p;
299
300                 if (!(p = strv_join(arg_wall, " "))) {
301                         log_error("Failed to join strings.");
302                         return;
303                 }
304
305                 if (*p) {
306                         utmp_wall(p, NULL);
307                         free(p);
308                         return;
309                 }
310
311                 free(p);
312         }
313
314         if (!table[action])
315                 return;
316
317         utmp_wall(table[action], NULL);
318 }
319
320 struct unit_info {
321         const char *id;
322         const char *description;
323         const char *load_state;
324         const char *active_state;
325         const char *sub_state;
326         const char *following;
327         const char *unit_path;
328         uint32_t job_id;
329         const char *job_type;
330         const char *job_path;
331 };
332
333 static int compare_unit_info(const void *a, const void *b) {
334         const char *d1, *d2;
335         const struct unit_info *u = a, *v = b;
336
337         d1 = strrchr(u->id, '.');
338         d2 = strrchr(v->id, '.');
339
340         if (d1 && d2) {
341                 int r;
342
343                 if ((r = strcasecmp(d1, d2)) != 0)
344                         return r;
345         }
346
347         return strcasecmp(u->id, v->id);
348 }
349
350 static bool output_show_job(const struct unit_info *u) {
351         const char *dot;
352
353         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
354                               streq(dot+1, arg_type))) &&
355                 (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
356 }
357
358 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
359         unsigned active_len, sub_len, job_len, n_shown = 0;
360         const struct unit_info *u;
361
362         active_len = sizeof("ACTIVE")-1;
363         sub_len = sizeof("SUB")-1;
364         job_len = sizeof("JOB")-1;
365
366         for (u = unit_infos; u < unit_infos + c; u++) {
367                 if (!output_show_job(u))
368                         continue;
369
370                 active_len = MAX(active_len, strlen(u->active_state));
371                 sub_len = MAX(sub_len, strlen(u->sub_state));
372                 if (u->job_id != 0)
373                         job_len = MAX(job_len, strlen(u->job_type));
374         }
375
376         if (on_tty()) {
377                 printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
378                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
379                 if (columns() >= 80+12 || arg_full)
380                         printf(" %s\n", "DESCRIPTION");
381                 else
382                         printf("\n");
383         }
384
385         for (u = unit_infos; u < unit_infos + c; u++) {
386                 char *e;
387                 int a = 0, b = 0;
388                 const char *on_loaded, *off_loaded;
389                 const char *on_active, *off_active;
390
391                 if (!output_show_job(u))
392                         continue;
393
394                 n_shown++;
395
396                 if (!streq(u->load_state, "loaded") &&
397                     !streq(u->load_state, "banned")) {
398                         on_loaded = ansi_highlight(true);
399                         off_loaded = ansi_highlight(false);
400                 } else
401                         on_loaded = off_loaded = "";
402
403                 if (streq(u->active_state, "failed")) {
404                         on_active = ansi_highlight(true);
405                         off_active = ansi_highlight(false);
406                 } else
407                         on_active = off_active = "";
408
409                 e = arg_full ? NULL : ellipsize(u->id, 25, 33);
410
411                 printf("%-25s %s%-6s%s %s%-*s %-*s%s%n",
412                        e ? e : u->id,
413                        on_loaded, u->load_state, off_loaded,
414                        on_active, active_len, u->active_state,
415                        sub_len, u->sub_state, off_active,
416                        &a);
417
418                 free(e);
419
420                 a -= strlen(on_loaded) + strlen(off_loaded);
421                 a -= strlen(on_active) + strlen(off_active);
422
423                 if (u->job_id != 0)
424                         printf(" %-*s", job_len, u->job_type);
425                 else
426                         b = 1 + job_len;
427
428                 if (a + b + 1 < columns()) {
429                         if (u->job_id == 0)
430                                 printf(" %-*s", job_len, "");
431
432                         if (arg_full)
433                                 printf(" %s", u->description);
434                         else
435                                 printf(" %.*s", columns() - a - b - 1, u->description);
436                 }
437
438                 fputs("\n", stdout);
439         }
440
441         if (on_tty()) {
442                 printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
443                        "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
444                        "SUB    = The low-level unit activation state, values depend on unit type.\n"
445                        "JOB    = Pending job for the unit.\n");
446
447                 if (arg_all)
448                         printf("\n%u units listed.\n", n_shown);
449                 else
450                         printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
451         }
452 }
453
454 static int list_units(DBusConnection *bus, char **args, unsigned n) {
455         DBusMessage *m = NULL, *reply = NULL;
456         DBusError error;
457         int r;
458         DBusMessageIter iter, sub, sub2;
459         unsigned c = 0, n_units = 0;
460         struct unit_info *unit_infos = NULL;
461
462         dbus_error_init(&error);
463
464         assert(bus);
465
466         pager_open();
467
468         if (!(m = dbus_message_new_method_call(
469                               "org.freedesktop.systemd1",
470                               "/org/freedesktop/systemd1",
471                               "org.freedesktop.systemd1.Manager",
472                               "ListUnits"))) {
473                 log_error("Could not allocate message.");
474                 return -ENOMEM;
475         }
476
477         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
478                 log_error("Failed to issue method call: %s", bus_error_message(&error));
479                 r = -EIO;
480                 goto finish;
481         }
482
483         if (!dbus_message_iter_init(reply, &iter) ||
484             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
485             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
486                 log_error("Failed to parse reply.");
487                 r = -EIO;
488                 goto finish;
489         }
490
491         dbus_message_iter_recurse(&iter, &sub);
492
493         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
494                 struct unit_info *u;
495
496                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
497                         log_error("Failed to parse reply.");
498                         r = -EIO;
499                         goto finish;
500                 }
501
502                 if (c >= n_units) {
503                         struct unit_info *w;
504
505                         n_units = MAX(2*c, 16);
506                         w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
507
508                         if (!w) {
509                                 log_error("Failed to allocate unit array.");
510                                 r = -ENOMEM;
511                                 goto finish;
512                         }
513
514                         unit_infos = w;
515                 }
516
517                 u = unit_infos+c;
518
519                 dbus_message_iter_recurse(&sub, &sub2);
520
521                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
522                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
523                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
524                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
525                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
526                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
527                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
528                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
529                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
530                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
531                         log_error("Failed to parse reply.");
532                         r = -EIO;
533                         goto finish;
534                 }
535
536                 dbus_message_iter_next(&sub);
537                 c++;
538         }
539
540         if (c > 0) {
541                 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
542                 output_units_list(unit_infos, c);
543         }
544
545         r = 0;
546
547 finish:
548         if (m)
549                 dbus_message_unref(m);
550
551         if (reply)
552                 dbus_message_unref(reply);
553
554         free(unit_infos);
555
556         dbus_error_free(&error);
557
558         return r;
559 }
560
561 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
562         static const char * const colors[] = {
563                 "Requires",              "[color=\"black\"]",
564                 "RequiresOverridable",   "[color=\"black\"]",
565                 "Requisite",             "[color=\"darkblue\"]",
566                 "RequisiteOverridable",  "[color=\"darkblue\"]",
567                 "Wants",                 "[color=\"darkgrey\"]",
568                 "Conflicts",             "[color=\"red\"]",
569                 "ConflictedBy",          "[color=\"red\"]",
570                 "After",                 "[color=\"green\"]"
571         };
572
573         const char *c = NULL;
574         unsigned i;
575
576         assert(name);
577         assert(prop);
578         assert(iter);
579
580         for (i = 0; i < ELEMENTSOF(colors); i += 2)
581                 if (streq(colors[i], prop)) {
582                         c = colors[i+1];
583                         break;
584                 }
585
586         if (!c)
587                 return 0;
588
589         if (arg_dot != DOT_ALL)
590                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
591                         return 0;
592
593         switch (dbus_message_iter_get_arg_type(iter)) {
594
595         case DBUS_TYPE_ARRAY:
596
597                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
598                         DBusMessageIter sub;
599
600                         dbus_message_iter_recurse(iter, &sub);
601
602                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
603                                 const char *s;
604
605                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
606                                 dbus_message_iter_get_basic(&sub, &s);
607                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
608
609                                 dbus_message_iter_next(&sub);
610                         }
611
612                         return 0;
613                 }
614         }
615
616         return 0;
617 }
618
619 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
620         DBusMessage *m = NULL, *reply = NULL;
621         const char *interface = "org.freedesktop.systemd1.Unit";
622         int r;
623         DBusError error;
624         DBusMessageIter iter, sub, sub2, sub3;
625
626         assert(bus);
627         assert(path);
628
629         dbus_error_init(&error);
630
631         if (!(m = dbus_message_new_method_call(
632                               "org.freedesktop.systemd1",
633                               path,
634                               "org.freedesktop.DBus.Properties",
635                               "GetAll"))) {
636                 log_error("Could not allocate message.");
637                 r = -ENOMEM;
638                 goto finish;
639         }
640
641         if (!dbus_message_append_args(m,
642                                       DBUS_TYPE_STRING, &interface,
643                                       DBUS_TYPE_INVALID)) {
644                 log_error("Could not append arguments to message.");
645                 r = -ENOMEM;
646                 goto finish;
647         }
648
649         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
650                 log_error("Failed to issue method call: %s", bus_error_message(&error));
651                 r = -EIO;
652                 goto finish;
653         }
654
655         if (!dbus_message_iter_init(reply, &iter) ||
656             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
657             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
658                 log_error("Failed to parse reply.");
659                 r = -EIO;
660                 goto finish;
661         }
662
663         dbus_message_iter_recurse(&iter, &sub);
664
665         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
666                 const char *prop;
667
668                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
669                         log_error("Failed to parse reply.");
670                         r = -EIO;
671                         goto finish;
672                 }
673
674                 dbus_message_iter_recurse(&sub, &sub2);
675
676                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
677                         log_error("Failed to parse reply.");
678                         r = -EIO;
679                         goto finish;
680                 }
681
682                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
683                         log_error("Failed to parse reply.");
684                         r = -EIO;
685                         goto finish;
686                 }
687
688                 dbus_message_iter_recurse(&sub2, &sub3);
689
690                 if (dot_one_property(name, prop, &sub3)) {
691                         log_error("Failed to parse reply.");
692                         r = -EIO;
693                         goto finish;
694                 }
695
696                 dbus_message_iter_next(&sub);
697         }
698
699         r = 0;
700
701 finish:
702         if (m)
703                 dbus_message_unref(m);
704
705         if (reply)
706                 dbus_message_unref(reply);
707
708         dbus_error_free(&error);
709
710         return r;
711 }
712
713 static int dot(DBusConnection *bus, char **args, unsigned n) {
714         DBusMessage *m = NULL, *reply = NULL;
715         DBusError error;
716         int r;
717         DBusMessageIter iter, sub, sub2;
718
719         dbus_error_init(&error);
720
721         assert(bus);
722
723         if (!(m = dbus_message_new_method_call(
724                               "org.freedesktop.systemd1",
725                               "/org/freedesktop/systemd1",
726                               "org.freedesktop.systemd1.Manager",
727                               "ListUnits"))) {
728                 log_error("Could not allocate message.");
729                 return -ENOMEM;
730         }
731
732         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
733                 log_error("Failed to issue method call: %s", bus_error_message(&error));
734                 r = -EIO;
735                 goto finish;
736         }
737
738         if (!dbus_message_iter_init(reply, &iter) ||
739             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
740             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
741                 log_error("Failed to parse reply.");
742                 r = -EIO;
743                 goto finish;
744         }
745
746         printf("digraph systemd {\n");
747
748         dbus_message_iter_recurse(&iter, &sub);
749         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
750                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
751
752                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
753                         log_error("Failed to parse reply.");
754                         r = -EIO;
755                         goto finish;
756                 }
757
758                 dbus_message_iter_recurse(&sub, &sub2);
759
760                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
761                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
762                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
763                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
764                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
765                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
766                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
767                         log_error("Failed to parse reply.");
768                         r = -EIO;
769                         goto finish;
770                 }
771
772                 if ((r = dot_one(bus, id, unit_path)) < 0)
773                         goto finish;
774
775                 /* printf("\t\"%s\";\n", id); */
776                 dbus_message_iter_next(&sub);
777         }
778
779         printf("}\n");
780
781         log_info("   Color legend: black     = Requires\n"
782                  "                 dark blue = Requisite\n"
783                  "                 dark grey = Wants\n"
784                  "                 red       = Conflicts\n"
785                  "                 green     = After\n");
786
787         if (isatty(fileno(stdout)))
788                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
789                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
790
791         r = 0;
792
793 finish:
794         if (m)
795                 dbus_message_unref(m);
796
797         if (reply)
798                 dbus_message_unref(reply);
799
800         dbus_error_free(&error);
801
802         return r;
803 }
804
805 static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
806         DBusMessage *m = NULL, *reply = NULL;
807         DBusError error;
808         int r;
809         DBusMessageIter iter, sub, sub2;
810         unsigned k = 0;
811
812         dbus_error_init(&error);
813
814         assert(bus);
815
816         pager_open();
817
818         if (!(m = dbus_message_new_method_call(
819                               "org.freedesktop.systemd1",
820                               "/org/freedesktop/systemd1",
821                               "org.freedesktop.systemd1.Manager",
822                               "ListJobs"))) {
823                 log_error("Could not allocate message.");
824                 return -ENOMEM;
825         }
826
827         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
828                 log_error("Failed to issue method call: %s", bus_error_message(&error));
829                 r = -EIO;
830                 goto finish;
831         }
832
833         if (!dbus_message_iter_init(reply, &iter) ||
834             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
835             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
836                 log_error("Failed to parse reply.");
837                 r = -EIO;
838                 goto finish;
839         }
840
841         dbus_message_iter_recurse(&iter, &sub);
842
843         if (isatty(STDOUT_FILENO))
844                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
845
846         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
847                 const char *name, *type, *state, *job_path, *unit_path;
848                 uint32_t id;
849                 char *e;
850
851                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
852                         log_error("Failed to parse reply.");
853                         r = -EIO;
854                         goto finish;
855                 }
856
857                 dbus_message_iter_recurse(&sub, &sub2);
858
859                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
860                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
861                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
862                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
863                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
864                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
865                         log_error("Failed to parse reply.");
866                         r = -EIO;
867                         goto finish;
868                 }
869
870                 e = arg_full ? NULL : ellipsize(name, 25, 33);
871                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
872                 free(e);
873
874                 k++;
875
876                 dbus_message_iter_next(&sub);
877         }
878
879         if (isatty(STDOUT_FILENO))
880                 printf("\n%u jobs listed.\n", k);
881
882         r = 0;
883
884 finish:
885         if (m)
886                 dbus_message_unref(m);
887
888         if (reply)
889                 dbus_message_unref(reply);
890
891         dbus_error_free(&error);
892
893         return r;
894 }
895
896 static int load_unit(DBusConnection *bus, char **args, unsigned n) {
897         DBusMessage *m = NULL, *reply = NULL;
898         DBusError error;
899         int r;
900         unsigned i;
901
902         dbus_error_init(&error);
903
904         assert(bus);
905         assert(args);
906
907         for (i = 1; i < n; i++) {
908
909                 if (!(m = dbus_message_new_method_call(
910                                       "org.freedesktop.systemd1",
911                                       "/org/freedesktop/systemd1",
912                                       "org.freedesktop.systemd1.Manager",
913                                       "LoadUnit"))) {
914                         log_error("Could not allocate message.");
915                         r = -ENOMEM;
916                         goto finish;
917                 }
918
919                 if (!dbus_message_append_args(m,
920                                               DBUS_TYPE_STRING, &args[i],
921                                               DBUS_TYPE_INVALID)) {
922                         log_error("Could not append arguments to message.");
923                         r = -ENOMEM;
924                         goto finish;
925                 }
926
927                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
928                         log_error("Failed to issue method call: %s", bus_error_message(&error));
929                         r = -EIO;
930                         goto finish;
931                 }
932
933                 dbus_message_unref(m);
934                 dbus_message_unref(reply);
935
936                 m = reply = NULL;
937         }
938
939         r = 0;
940
941 finish:
942         if (m)
943                 dbus_message_unref(m);
944
945         if (reply)
946                 dbus_message_unref(reply);
947
948         dbus_error_free(&error);
949
950         return r;
951 }
952
953 static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
954         DBusMessage *m = NULL, *reply = NULL;
955         DBusError error;
956         int r;
957         unsigned i;
958
959         dbus_error_init(&error);
960
961         assert(bus);
962         assert(args);
963
964         if (n <= 1)
965                 return daemon_reload(bus, args, n);
966
967         for (i = 1; i < n; i++) {
968                 unsigned id;
969                 const char *path;
970
971                 if (!(m = dbus_message_new_method_call(
972                                       "org.freedesktop.systemd1",
973                                       "/org/freedesktop/systemd1",
974                                       "org.freedesktop.systemd1.Manager",
975                                       "GetJob"))) {
976                         log_error("Could not allocate message.");
977                         r = -ENOMEM;
978                         goto finish;
979                 }
980
981                 if ((r = safe_atou(args[i], &id)) < 0) {
982                         log_error("Failed to parse job id: %s", strerror(-r));
983                         goto finish;
984                 }
985
986                 assert_cc(sizeof(uint32_t) == sizeof(id));
987                 if (!dbus_message_append_args(m,
988                                               DBUS_TYPE_UINT32, &id,
989                                               DBUS_TYPE_INVALID)) {
990                         log_error("Could not append arguments to message.");
991                         r = -ENOMEM;
992                         goto finish;
993                 }
994
995                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
996                         log_error("Failed to issue method call: %s", bus_error_message(&error));
997                         r = -EIO;
998                         goto finish;
999                 }
1000
1001                 if (!dbus_message_get_args(reply, &error,
1002                                            DBUS_TYPE_OBJECT_PATH, &path,
1003                                            DBUS_TYPE_INVALID)) {
1004                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1005                         r = -EIO;
1006                         goto finish;
1007                 }
1008
1009                 dbus_message_unref(m);
1010                 if (!(m = dbus_message_new_method_call(
1011                                       "org.freedesktop.systemd1",
1012                                       path,
1013                                       "org.freedesktop.systemd1.Job",
1014                                       "Cancel"))) {
1015                         log_error("Could not allocate message.");
1016                         r = -ENOMEM;
1017                         goto finish;
1018                 }
1019
1020                 dbus_message_unref(reply);
1021                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1022                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1023                         r = -EIO;
1024                         goto finish;
1025                 }
1026
1027                 dbus_message_unref(m);
1028                 dbus_message_unref(reply);
1029                 m = reply = NULL;
1030         }
1031
1032         r = 0;
1033
1034 finish:
1035         if (m)
1036                 dbus_message_unref(m);
1037
1038         if (reply)
1039                 dbus_message_unref(reply);
1040
1041         dbus_error_free(&error);
1042
1043         return r;
1044 }
1045
1046 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1047         DBusMessage *m = NULL, *reply = NULL;
1048         dbus_bool_t b = FALSE;
1049         DBusMessageIter iter, sub;
1050         const char
1051                 *interface = "org.freedesktop.systemd1.Unit",
1052                 *property = "NeedDaemonReload",
1053                 *path;
1054
1055         /* We ignore all errors here, since this is used to show a warning only */
1056
1057         if (!(m = dbus_message_new_method_call(
1058                               "org.freedesktop.systemd1",
1059                               "/org/freedesktop/systemd1",
1060                               "org.freedesktop.systemd1.Manager",
1061                               "GetUnit")))
1062                 goto finish;
1063
1064         if (!dbus_message_append_args(m,
1065                                       DBUS_TYPE_STRING, &unit,
1066                                       DBUS_TYPE_INVALID))
1067                 goto finish;
1068
1069         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1070                 goto finish;
1071
1072         if (!dbus_message_get_args(reply, NULL,
1073                                    DBUS_TYPE_OBJECT_PATH, &path,
1074                                    DBUS_TYPE_INVALID))
1075                 goto finish;
1076
1077         dbus_message_unref(m);
1078         if (!(m = dbus_message_new_method_call(
1079                               "org.freedesktop.systemd1",
1080                               path,
1081                               "org.freedesktop.DBus.Properties",
1082                               "Get")))
1083                 goto finish;
1084
1085         if (!dbus_message_append_args(m,
1086                                       DBUS_TYPE_STRING, &interface,
1087                                       DBUS_TYPE_STRING, &property,
1088                                       DBUS_TYPE_INVALID)) {
1089                 goto finish;
1090         }
1091
1092         dbus_message_unref(reply);
1093         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1094                 goto finish;
1095
1096         if (!dbus_message_iter_init(reply, &iter) ||
1097             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1098                 goto finish;
1099
1100         dbus_message_iter_recurse(&iter, &sub);
1101
1102         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1103                 goto finish;
1104
1105         dbus_message_iter_get_basic(&sub, &b);
1106
1107 finish:
1108         if (m)
1109                 dbus_message_unref(m);
1110
1111         if (reply)
1112                 dbus_message_unref(reply);
1113
1114         return b;
1115 }
1116
1117 typedef struct WaitData {
1118         Set *set;
1119         bool failed;
1120 } WaitData;
1121
1122 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1123         DBusError error;
1124         WaitData *d = data;
1125
1126         assert(connection);
1127         assert(message);
1128         assert(d);
1129
1130         dbus_error_init(&error);
1131
1132         log_debug("Got D-Bus request: %s.%s() on %s",
1133                   dbus_message_get_interface(message),
1134                   dbus_message_get_member(message),
1135                   dbus_message_get_path(message));
1136
1137         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1138                 log_error("Warning! D-Bus connection terminated.");
1139                 dbus_connection_close(connection);
1140
1141         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1142                 uint32_t id;
1143                 const char *path;
1144                 dbus_bool_t success = true;
1145
1146                 if (!dbus_message_get_args(message, &error,
1147                                            DBUS_TYPE_UINT32, &id,
1148                                            DBUS_TYPE_OBJECT_PATH, &path,
1149                                            DBUS_TYPE_BOOLEAN, &success,
1150                                            DBUS_TYPE_INVALID))
1151                         log_error("Failed to parse message: %s", bus_error_message(&error));
1152                 else {
1153                         char *p;
1154
1155                         if ((p = set_remove(d->set, (char*) path)))
1156                                 free(p);
1157
1158                         if (!success)
1159                                 d->failed = true;
1160                 }
1161         }
1162
1163         dbus_error_free(&error);
1164         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1165 }
1166
1167 static int enable_wait_for_jobs(DBusConnection *bus) {
1168         DBusError error;
1169
1170         assert(bus);
1171
1172         if (private_bus)
1173                 return 0;
1174
1175         dbus_error_init(&error);
1176         dbus_bus_add_match(bus,
1177                            "type='signal',"
1178                            "sender='org.freedesktop.systemd1',"
1179                            "interface='org.freedesktop.systemd1.Manager',"
1180                            "member='JobRemoved',"
1181                            "path='/org/freedesktop/systemd1'",
1182                            &error);
1183
1184         if (dbus_error_is_set(&error)) {
1185                 log_error("Failed to add match: %s", bus_error_message(&error));
1186                 dbus_error_free(&error);
1187                 return -EIO;
1188         }
1189
1190         /* This is slightly dirty, since we don't undo the match registrations. */
1191         return 0;
1192 }
1193
1194 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1195         int r;
1196         WaitData d;
1197
1198         assert(bus);
1199         assert(s);
1200
1201         zero(d);
1202         d.set = s;
1203         d.failed = false;
1204
1205         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1206                 log_error("Failed to add filter.");
1207                 r = -ENOMEM;
1208                 goto finish;
1209         }
1210
1211         while (!set_isempty(s) &&
1212                dbus_connection_read_write_dispatch(bus, -1))
1213                 ;
1214
1215         if (!arg_quiet && d.failed)
1216                 log_error("Job failed. See system logs and 'systemctl status' for details.");
1217
1218         r = d.failed ? -EIO : 0;
1219
1220 finish:
1221         /* This is slightly dirty, since we don't undo the filter registration. */
1222
1223         return r;
1224 }
1225
1226 static int start_unit_one(
1227                 DBusConnection *bus,
1228                 const char *method,
1229                 const char *name,
1230                 const char *mode,
1231                 DBusError *error,
1232                 Set *s) {
1233
1234         DBusMessage *m = NULL, *reply = NULL;
1235         const char *path;
1236         int r;
1237
1238         assert(bus);
1239         assert(method);
1240         assert(name);
1241         assert(mode);
1242         assert(error);
1243         assert(arg_no_block || s);
1244
1245         if (!(m = dbus_message_new_method_call(
1246                               "org.freedesktop.systemd1",
1247                               "/org/freedesktop/systemd1",
1248                               "org.freedesktop.systemd1.Manager",
1249                               method))) {
1250                 log_error("Could not allocate message.");
1251                 r = -ENOMEM;
1252                 goto finish;
1253         }
1254
1255         if (!dbus_message_append_args(m,
1256                                       DBUS_TYPE_STRING, &name,
1257                                       DBUS_TYPE_STRING, &mode,
1258                                       DBUS_TYPE_INVALID)) {
1259                 log_error("Could not append arguments to message.");
1260                 r = -ENOMEM;
1261                 goto finish;
1262         }
1263
1264         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1265
1266                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1267                         /* There's always a fallback possible for
1268                          * legacy actions. */
1269                         r = -EADDRNOTAVAIL;
1270                         goto finish;
1271                 }
1272
1273                 log_error("Failed to issue method call: %s", bus_error_message(error));
1274                 r = -EIO;
1275                 goto finish;
1276         }
1277
1278         if (!dbus_message_get_args(reply, error,
1279                                    DBUS_TYPE_OBJECT_PATH, &path,
1280                                    DBUS_TYPE_INVALID)) {
1281                 log_error("Failed to parse reply: %s", bus_error_message(error));
1282                 r = -EIO;
1283                 goto finish;
1284         }
1285
1286         if (need_daemon_reload(bus, name))
1287                 log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1288                             arg_user ? "--user" : "--system");
1289
1290         if (!arg_no_block) {
1291                 char *p;
1292
1293                 if (!(p = strdup(path))) {
1294                         log_error("Failed to duplicate path.");
1295                         r = -ENOMEM;
1296                         goto finish;
1297                 }
1298
1299                 if ((r = set_put(s, p)) < 0) {
1300                         free(p);
1301                         log_error("Failed to add path to set.");
1302                         goto finish;
1303                 }
1304         }
1305
1306         r = 0;
1307
1308 finish:
1309         if (m)
1310                 dbus_message_unref(m);
1311
1312         if (reply)
1313                 dbus_message_unref(reply);
1314
1315         return r;
1316 }
1317
1318 static enum action verb_to_action(const char *verb) {
1319         if (streq(verb, "halt"))
1320                 return ACTION_HALT;
1321         else if (streq(verb, "poweroff"))
1322                 return ACTION_POWEROFF;
1323         else if (streq(verb, "reboot"))
1324                 return ACTION_REBOOT;
1325         else if (streq(verb, "kexec"))
1326                 return ACTION_KEXEC;
1327         else if (streq(verb, "rescue"))
1328                 return ACTION_RESCUE;
1329         else if (streq(verb, "emergency"))
1330                 return ACTION_EMERGENCY;
1331         else if (streq(verb, "default"))
1332                 return ACTION_DEFAULT;
1333         else if (streq(verb, "exit"))
1334                 return ACTION_EXIT;
1335         else
1336                 return ACTION_INVALID;
1337 }
1338
1339 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
1340
1341         static const char * const table[_ACTION_MAX] = {
1342                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1343                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1344                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1345                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1346                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1347                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1348                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1349                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1350                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1351                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1352                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1353                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET
1354         };
1355
1356         int r, ret = 0;
1357         unsigned i;
1358         const char *method, *mode, *one_name;
1359         Set *s = NULL;
1360         DBusError error;
1361
1362         dbus_error_init(&error);
1363
1364         assert(bus);
1365
1366         spawn_ask_password_agent();
1367
1368         if (arg_action == ACTION_SYSTEMCTL) {
1369                 method =
1370                         streq(args[0], "stop")                  ? "StopUnit" :
1371                         streq(args[0], "reload")                ? "ReloadUnit" :
1372                         streq(args[0], "restart")               ? "RestartUnit" :
1373                         streq(args[0], "try-restart")           ||
1374                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1375                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1376                         streq(args[0], "reload-or-try-restart") ||
1377                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1378                                                                   "StartUnit";
1379
1380                 mode =
1381                         (streq(args[0], "isolate") ||
1382                          streq(args[0], "rescue")  ||
1383                          streq(args[0], "emergency")) ? "isolate" :
1384                                              arg_fail ? "fail" :
1385                                                         "replace";
1386
1387                 one_name = table[verb_to_action(args[0])];
1388
1389         } else {
1390                 assert(arg_action < ELEMENTSOF(table));
1391                 assert(table[arg_action]);
1392
1393                 method = "StartUnit";
1394
1395                 mode = (arg_action == ACTION_EMERGENCY ||
1396                         arg_action == ACTION_RESCUE ||
1397                         arg_action == ACTION_RUNLEVEL2 ||
1398                         arg_action == ACTION_RUNLEVEL3 ||
1399                         arg_action == ACTION_RUNLEVEL4 ||
1400                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1401
1402                 one_name = table[arg_action];
1403         }
1404
1405         if (!arg_no_block) {
1406                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1407                         log_error("Could not watch jobs: %s", strerror(-ret));
1408                         goto finish;
1409                 }
1410
1411                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1412                         log_error("Failed to allocate set.");
1413                         ret = -ENOMEM;
1414                         goto finish;
1415                 }
1416         }
1417
1418         if (one_name) {
1419                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1420                         goto finish;
1421         } else {
1422                 for (i = 1; i < n; i++)
1423                         if ((r = start_unit_one(bus, method, args[i], mode, &error, s)) != 0) {
1424                                 ret = translate_bus_error_to_exit_status(r, &error);
1425                                 dbus_error_free(&error);
1426                         }
1427         }
1428
1429         if (!arg_no_block)
1430                 if ((r = wait_for_jobs(bus, s)) < 0) {
1431                         ret = r;
1432                         goto finish;
1433                 }
1434
1435 finish:
1436         if (s)
1437                 set_free_free(s);
1438
1439         dbus_error_free(&error);
1440
1441         return ret;
1442 }
1443
1444 static int start_special(DBusConnection *bus, char **args, unsigned n) {
1445         int r;
1446
1447         assert(bus);
1448         assert(args);
1449
1450         if (arg_force &&
1451             (streq(args[0], "halt") ||
1452              streq(args[0], "poweroff") ||
1453              streq(args[0], "reboot") ||
1454              streq(args[0], "kexec") ||
1455              streq(args[0], "exit")))
1456                 return daemon_reload(bus, args, n);
1457
1458         r = start_unit(bus, args, n);
1459
1460         if (r >= 0)
1461                 warn_wall(verb_to_action(args[0]));
1462
1463         return r;
1464 }
1465
1466 static int check_unit(DBusConnection *bus, char **args, unsigned n) {
1467         DBusMessage *m = NULL, *reply = NULL;
1468         const char
1469                 *interface = "org.freedesktop.systemd1.Unit",
1470                 *property = "ActiveState";
1471         int r = 3; /* According to LSB: "program is not running" */
1472         DBusError error;
1473         unsigned i;
1474
1475         assert(bus);
1476         assert(args);
1477
1478         dbus_error_init(&error);
1479
1480         for (i = 1; i < n; i++) {
1481                 const char *path = NULL;
1482                 const char *state;
1483                 DBusMessageIter iter, sub;
1484
1485                 if (!(m = dbus_message_new_method_call(
1486                                       "org.freedesktop.systemd1",
1487                                       "/org/freedesktop/systemd1",
1488                                       "org.freedesktop.systemd1.Manager",
1489                                       "GetUnit"))) {
1490                         log_error("Could not allocate message.");
1491                         r = -ENOMEM;
1492                         goto finish;
1493                 }
1494
1495                 if (!dbus_message_append_args(m,
1496                                               DBUS_TYPE_STRING, &args[i],
1497                                               DBUS_TYPE_INVALID)) {
1498                         log_error("Could not append arguments to message.");
1499                         r = -ENOMEM;
1500                         goto finish;
1501                 }
1502
1503                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1504
1505                         /* Hmm, cannot figure out anything about this unit... */
1506                         if (!arg_quiet)
1507                                 puts("unknown");
1508
1509                         dbus_error_free(&error);
1510                         dbus_message_unref(m);
1511                         continue;
1512                 }
1513
1514                 if (!dbus_message_get_args(reply, &error,
1515                                            DBUS_TYPE_OBJECT_PATH, &path,
1516                                            DBUS_TYPE_INVALID)) {
1517                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1518                         r = -EIO;
1519                         goto finish;
1520                 }
1521
1522                 dbus_message_unref(m);
1523                 if (!(m = dbus_message_new_method_call(
1524                                       "org.freedesktop.systemd1",
1525                                       path,
1526                                       "org.freedesktop.DBus.Properties",
1527                                       "Get"))) {
1528                         log_error("Could not allocate message.");
1529                         r = -ENOMEM;
1530                         goto finish;
1531                 }
1532
1533                 if (!dbus_message_append_args(m,
1534                                               DBUS_TYPE_STRING, &interface,
1535                                               DBUS_TYPE_STRING, &property,
1536                                               DBUS_TYPE_INVALID)) {
1537                         log_error("Could not append arguments to message.");
1538                         r = -ENOMEM;
1539                         goto finish;
1540                 }
1541
1542                 dbus_message_unref(reply);
1543                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1544                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1545                         r = -EIO;
1546                         goto finish;
1547                 }
1548
1549                 if (!dbus_message_iter_init(reply, &iter) ||
1550                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1551                         log_error("Failed to parse reply.");
1552                         r = -EIO;
1553                         goto finish;
1554                 }
1555
1556                 dbus_message_iter_recurse(&iter, &sub);
1557
1558                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1559                         log_error("Failed to parse reply.");
1560                         r = -EIO;
1561                         goto finish;
1562                 }
1563
1564                 dbus_message_iter_get_basic(&sub, &state);
1565
1566                 if (!arg_quiet)
1567                         puts(state);
1568
1569                 if (streq(state, "active") || streq(state, "reloading"))
1570                         r = 0;
1571
1572                 dbus_message_unref(m);
1573                 dbus_message_unref(reply);
1574                 m = reply = NULL;
1575         }
1576
1577 finish:
1578         if (m)
1579                 dbus_message_unref(m);
1580
1581         if (reply)
1582                 dbus_message_unref(reply);
1583
1584         dbus_error_free(&error);
1585
1586         return r;
1587 }
1588
1589 static int kill_unit(DBusConnection *bus, char **args, unsigned n) {
1590         DBusMessage *m = NULL, *reply = NULL;
1591         int r = 0;
1592         DBusError error;
1593         unsigned i;
1594
1595         assert(bus);
1596         assert(args);
1597
1598         dbus_error_init(&error);
1599
1600         if (!arg_kill_who)
1601                 arg_kill_who = "all";
1602
1603         if (!arg_kill_mode)
1604                 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
1605
1606         for (i = 1; i < n; i++) {
1607
1608                 if (!(m = dbus_message_new_method_call(
1609                                       "org.freedesktop.systemd1",
1610                                       "/org/freedesktop/systemd1",
1611                                       "org.freedesktop.systemd1.Manager",
1612                                       "KillUnit"))) {
1613                         log_error("Could not allocate message.");
1614                         r = -ENOMEM;
1615                         goto finish;
1616                 }
1617
1618                 if (!dbus_message_append_args(m,
1619                                               DBUS_TYPE_STRING, &args[i],
1620                                               DBUS_TYPE_STRING, &arg_kill_who,
1621                                               DBUS_TYPE_STRING, &arg_kill_mode,
1622                                               DBUS_TYPE_INT32, &arg_signal,
1623                                               DBUS_TYPE_INVALID)) {
1624                         log_error("Could not append arguments to message.");
1625                         r = -ENOMEM;
1626                         goto finish;
1627                 }
1628
1629                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1630                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1631                         dbus_error_free(&error);
1632                         r = -EIO;
1633                 }
1634
1635                 dbus_message_unref(m);
1636
1637                 if (reply)
1638                         dbus_message_unref(reply);
1639                 m = reply = NULL;
1640         }
1641
1642 finish:
1643         if (m)
1644                 dbus_message_unref(m);
1645
1646         if (reply)
1647                 dbus_message_unref(reply);
1648
1649         dbus_error_free(&error);
1650
1651         return r;
1652 }
1653
1654 typedef struct ExecStatusInfo {
1655         char *name;
1656
1657         char *path;
1658         char **argv;
1659
1660         bool ignore;
1661
1662         usec_t start_timestamp;
1663         usec_t exit_timestamp;
1664         pid_t pid;
1665         int code;
1666         int status;
1667
1668         LIST_FIELDS(struct ExecStatusInfo, exec);
1669 } ExecStatusInfo;
1670
1671 static void exec_status_info_free(ExecStatusInfo *i) {
1672         assert(i);
1673
1674         free(i->name);
1675         free(i->path);
1676         strv_free(i->argv);
1677         free(i);
1678 }
1679
1680 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1681         uint64_t start_timestamp, exit_timestamp;
1682         DBusMessageIter sub2, sub3;
1683         const char*path;
1684         unsigned n;
1685         uint32_t pid;
1686         int32_t code, status;
1687         dbus_bool_t ignore;
1688
1689         assert(i);
1690         assert(i);
1691
1692         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1693                 return -EIO;
1694
1695         dbus_message_iter_recurse(sub, &sub2);
1696
1697         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1698                 return -EIO;
1699
1700         if (!(i->path = strdup(path)))
1701                 return -ENOMEM;
1702
1703         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1704             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1705                 return -EIO;
1706
1707         n = 0;
1708         dbus_message_iter_recurse(&sub2, &sub3);
1709         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1710                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1711                 dbus_message_iter_next(&sub3);
1712                 n++;
1713         }
1714
1715
1716         if (!(i->argv = new0(char*, n+1)))
1717                 return -ENOMEM;
1718
1719         n = 0;
1720         dbus_message_iter_recurse(&sub2, &sub3);
1721         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1722                 const char *s;
1723
1724                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1725                 dbus_message_iter_get_basic(&sub3, &s);
1726                 dbus_message_iter_next(&sub3);
1727
1728                 if (!(i->argv[n++] = strdup(s)))
1729                         return -ENOMEM;
1730         }
1731
1732         if (!dbus_message_iter_next(&sub2) ||
1733             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1734             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1735             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1736             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1737             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1738             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1739                 return -EIO;
1740
1741         i->ignore = ignore;
1742         i->start_timestamp = (usec_t) start_timestamp;
1743         i->exit_timestamp = (usec_t) exit_timestamp;
1744         i->pid = (pid_t) pid;
1745         i->code = code;
1746         i->status = status;
1747
1748         return 0;
1749 }
1750
1751 typedef struct UnitStatusInfo {
1752         const char *id;
1753         const char *load_state;
1754         const char *active_state;
1755         const char *sub_state;
1756
1757         const char *description;
1758         const char *following;
1759
1760         const char *path;
1761         const char *default_control_group;
1762
1763         usec_t inactive_exit_timestamp;
1764         usec_t active_enter_timestamp;
1765         usec_t active_exit_timestamp;
1766         usec_t inactive_enter_timestamp;
1767
1768         bool need_daemon_reload;
1769
1770         /* Service */
1771         pid_t main_pid;
1772         pid_t control_pid;
1773         const char *status_text;
1774         bool running:1;
1775 #ifdef HAVE_SYSV_COMPAT
1776         bool is_sysv:1;
1777 #endif
1778
1779         usec_t start_timestamp;
1780         usec_t exit_timestamp;
1781
1782         int exit_code, exit_status;
1783
1784         /* Socket */
1785         unsigned n_accepted;
1786         unsigned n_connections;
1787         bool accept;
1788
1789         /* Device */
1790         const char *sysfs_path;
1791
1792         /* Mount, Automount */
1793         const char *where;
1794
1795         /* Swap */
1796         const char *what;
1797
1798         LIST_HEAD(ExecStatusInfo, exec);
1799 } UnitStatusInfo;
1800
1801 static void print_status_info(UnitStatusInfo *i) {
1802         ExecStatusInfo *p;
1803         const char *on, *off, *ss;
1804         usec_t timestamp;
1805         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
1806         char since2[FORMAT_TIMESTAMP_MAX], *s2;
1807
1808         assert(i);
1809
1810         /* This shows pretty information about a unit. See
1811          * print_property() for a low-level property printer */
1812
1813         printf("%s", strna(i->id));
1814
1815         if (i->description && !streq_ptr(i->id, i->description))
1816                 printf(" - %s", i->description);
1817
1818         printf("\n");
1819
1820         if (i->following)
1821                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
1822
1823         if (streq_ptr(i->load_state, "failed") ||
1824             streq_ptr(i->load_state, "banned")) {
1825                 on = ansi_highlight(true);
1826                 off = ansi_highlight(false);
1827         } else
1828                 on = off = "";
1829
1830         if (i->path)
1831                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
1832         else
1833                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
1834
1835         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
1836
1837         if (streq_ptr(i->active_state, "failed")) {
1838                 on = ansi_highlight(true);
1839                 off = ansi_highlight(false);
1840         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
1841                 on = ansi_highlight_green(true);
1842                 off = ansi_highlight_green(false);
1843         } else
1844                 on = off = "";
1845
1846         if (ss)
1847                 printf("\t  Active: %s%s (%s)%s",
1848                        on,
1849                        strna(i->active_state),
1850                        ss,
1851                        off);
1852         else
1853                 printf("\t  Active: %s%s%s",
1854                        on,
1855                        strna(i->active_state),
1856                        off);
1857
1858         timestamp = (streq_ptr(i->active_state, "active")      ||
1859                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
1860                     (streq_ptr(i->active_state, "inactive")    ||
1861                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
1862                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
1863                                                                   i->active_exit_timestamp;
1864
1865         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
1866         s2 = format_timestamp(since2, sizeof(since2), timestamp);
1867
1868         if (s1)
1869                 printf(" since %s; %s\n", s2, s1);
1870         else if (s2)
1871                 printf(" since %s\n", s2);
1872         else
1873                 printf("\n");
1874
1875         if (i->sysfs_path)
1876                 printf("\t  Device: %s\n", i->sysfs_path);
1877         if (i->where)
1878                 printf("\t   Where: %s\n", i->where);
1879         if (i->what)
1880                 printf("\t    What: %s\n", i->what);
1881
1882         if (i->accept)
1883                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1884
1885         LIST_FOREACH(exec, p, i->exec) {
1886                 char *t;
1887                 bool good;
1888
1889                 /* Only show exited processes here */
1890                 if (p->code == 0)
1891                         continue;
1892
1893                 t = strv_join(p->argv, " ");
1894                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
1895                 free(t);
1896
1897 #ifdef HAVE_SYSV_COMPAT
1898                 if (i->is_sysv)
1899                         good = is_clean_exit_lsb(p->code, p->status);
1900                 else
1901 #endif
1902                         good = is_clean_exit(p->code, p->status);
1903
1904                 if (!good) {
1905                         on = ansi_highlight(true);
1906                         off = ansi_highlight(false);
1907                 } else
1908                         on = off = "";
1909
1910                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
1911
1912                 if (p->code == CLD_EXITED) {
1913                         const char *c;
1914
1915                         printf("status=%i", p->status);
1916
1917 #ifdef HAVE_SYSV_COMPAT
1918                         if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
1919 #else
1920                         if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
1921 #endif
1922                                 printf("/%s", c);
1923
1924                 } else
1925                         printf("signal=%s", signal_to_string(p->status));
1926
1927                 printf(")%s\n", off);
1928
1929                 on = off = NULL;
1930
1931                 if (i->main_pid == p->pid &&
1932                     i->start_timestamp == p->start_timestamp &&
1933                     i->exit_timestamp == p->start_timestamp)
1934                         /* Let's not show this twice */
1935                         i->main_pid = 0;
1936
1937                 if (p->pid == i->control_pid)
1938                         i->control_pid = 0;
1939         }
1940
1941         if (i->main_pid > 0 || i->control_pid > 0) {
1942                 printf("\t");
1943
1944                 if (i->main_pid > 0) {
1945                         printf("Main PID: %u", (unsigned) i->main_pid);
1946
1947                         if (i->running) {
1948                                 char *t = NULL;
1949                                 get_process_name(i->main_pid, &t);
1950                                 if (t) {
1951                                         printf(" (%s)", t);
1952                                         free(t);
1953                                 }
1954                         } else if (i->exit_code > 0) {
1955                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1956
1957                                 if (i->exit_code == CLD_EXITED) {
1958                                         const char *c;
1959
1960                                         printf("status=%i", i->exit_status);
1961
1962 #ifdef HAVE_SYSV_COMPAT
1963                                         if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
1964 #else
1965                                         if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
1966 #endif
1967                                                 printf("/%s", c);
1968
1969                                 } else
1970                                         printf("signal=%s", signal_to_string(i->exit_status));
1971                                 printf(")");
1972                         }
1973                 }
1974
1975                 if (i->main_pid > 0 && i->control_pid > 0)
1976                         printf(";");
1977
1978                 if (i->control_pid > 0) {
1979                         char *t = NULL;
1980
1981                         printf(" Control: %u", (unsigned) i->control_pid);
1982
1983                         get_process_name(i->control_pid, &t);
1984                         if (t) {
1985                                 printf(" (%s)", t);
1986                                 free(t);
1987                         }
1988                 }
1989
1990                 printf("\n");
1991         }
1992
1993         if (i->status_text)
1994                 printf("\t  Status: \"%s\"\n", i->status_text);
1995
1996         if (i->default_control_group) {
1997                 unsigned c;
1998
1999                 printf("\t  CGroup: %s\n", i->default_control_group);
2000
2001                 if ((c = columns()) > 18)
2002                         c -= 18;
2003                 else
2004                         c = 0;
2005
2006                 show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
2007         }
2008
2009         if (i->need_daemon_reload)
2010                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2011                        ansi_highlight(true),
2012                        ansi_highlight(false),
2013                        arg_user ? "--user" : "--system");
2014 }
2015
2016 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2017
2018         switch (dbus_message_iter_get_arg_type(iter)) {
2019
2020         case DBUS_TYPE_STRING: {
2021                 const char *s;
2022
2023                 dbus_message_iter_get_basic(iter, &s);
2024
2025                 if (s[0]) {
2026                         if (streq(name, "Id"))
2027                                 i->id = s;
2028                         else if (streq(name, "LoadState"))
2029                                 i->load_state = s;
2030                         else if (streq(name, "ActiveState"))
2031                                 i->active_state = s;
2032                         else if (streq(name, "SubState"))
2033                                 i->sub_state = s;
2034                         else if (streq(name, "Description"))
2035                                 i->description = s;
2036                         else if (streq(name, "FragmentPath"))
2037                                 i->path = s;
2038 #ifdef HAVE_SYSV_COMPAT
2039                         else if (streq(name, "SysVPath")) {
2040                                 i->is_sysv = true;
2041                                 i->path = s;
2042                         }
2043 #endif
2044                         else if (streq(name, "DefaultControlGroup"))
2045                                 i->default_control_group = s;
2046                         else if (streq(name, "StatusText"))
2047                                 i->status_text = s;
2048                         else if (streq(name, "SysFSPath"))
2049                                 i->sysfs_path = s;
2050                         else if (streq(name, "Where"))
2051                                 i->where = s;
2052                         else if (streq(name, "What"))
2053                                 i->what = s;
2054                         else if (streq(name, "Following"))
2055                                 i->following = s;
2056                 }
2057
2058                 break;
2059         }
2060
2061         case DBUS_TYPE_BOOLEAN: {
2062                 dbus_bool_t b;
2063
2064                 dbus_message_iter_get_basic(iter, &b);
2065
2066                 if (streq(name, "Accept"))
2067                         i->accept = b;
2068                 else if (streq(name, "NeedDaemonReload"))
2069                         i->need_daemon_reload = b;
2070
2071                 break;
2072         }
2073
2074         case DBUS_TYPE_UINT32: {
2075                 uint32_t u;
2076
2077                 dbus_message_iter_get_basic(iter, &u);
2078
2079                 if (streq(name, "MainPID")) {
2080                         if (u > 0) {
2081                                 i->main_pid = (pid_t) u;
2082                                 i->running = true;
2083                         }
2084                 } else if (streq(name, "ControlPID"))
2085                         i->control_pid = (pid_t) u;
2086                 else if (streq(name, "ExecMainPID")) {
2087                         if (u > 0)
2088                                 i->main_pid = (pid_t) u;
2089                 } else if (streq(name, "NAccepted"))
2090                         i->n_accepted = u;
2091                 else if (streq(name, "NConnections"))
2092                         i->n_connections = u;
2093
2094                 break;
2095         }
2096
2097         case DBUS_TYPE_INT32: {
2098                 int32_t j;
2099
2100                 dbus_message_iter_get_basic(iter, &j);
2101
2102                 if (streq(name, "ExecMainCode"))
2103                         i->exit_code = (int) j;
2104                 else if (streq(name, "ExecMainStatus"))
2105                         i->exit_status = (int) j;
2106
2107                 break;
2108         }
2109
2110         case DBUS_TYPE_UINT64: {
2111                 uint64_t u;
2112
2113                 dbus_message_iter_get_basic(iter, &u);
2114
2115                 if (streq(name, "ExecMainStartTimestamp"))
2116                         i->start_timestamp = (usec_t) u;
2117                 else if (streq(name, "ExecMainExitTimestamp"))
2118                         i->exit_timestamp = (usec_t) u;
2119                 else if (streq(name, "ActiveEnterTimestamp"))
2120                         i->active_enter_timestamp = (usec_t) u;
2121                 else if (streq(name, "InactiveEnterTimestamp"))
2122                         i->inactive_enter_timestamp = (usec_t) u;
2123                 else if (streq(name, "InactiveExitTimestamp"))
2124                         i->inactive_exit_timestamp = (usec_t) u;
2125                 else if (streq(name, "ActiveExitTimestamp"))
2126                         i->active_exit_timestamp = (usec_t) u;
2127
2128                 break;
2129         }
2130
2131         case DBUS_TYPE_ARRAY: {
2132
2133                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2134                     startswith(name, "Exec")) {
2135                         DBusMessageIter sub;
2136
2137                         dbus_message_iter_recurse(iter, &sub);
2138                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2139                                 ExecStatusInfo *info;
2140                                 int r;
2141
2142                                 if (!(info = new0(ExecStatusInfo, 1)))
2143                                         return -ENOMEM;
2144
2145                                 if (!(info->name = strdup(name))) {
2146                                         free(info);
2147                                         return -ENOMEM;
2148                                 }
2149
2150                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2151                                         free(info);
2152                                         return r;
2153                                 }
2154
2155                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2156
2157                                 dbus_message_iter_next(&sub);
2158                         }
2159                 }
2160
2161                 break;
2162         }
2163         }
2164
2165         return 0;
2166 }
2167
2168 static int print_property(const char *name, DBusMessageIter *iter) {
2169         assert(name);
2170         assert(iter);
2171
2172         /* This is a low-level property printer, see
2173          * print_status_info() for the nicer output */
2174
2175         if (arg_property && !strv_find(arg_property, name))
2176                 return 0;
2177
2178         switch (dbus_message_iter_get_arg_type(iter)) {
2179
2180         case DBUS_TYPE_STRING: {
2181                 const char *s;
2182                 dbus_message_iter_get_basic(iter, &s);
2183
2184                 if (arg_all || s[0])
2185                         printf("%s=%s\n", name, s);
2186
2187                 return 0;
2188         }
2189
2190         case DBUS_TYPE_BOOLEAN: {
2191                 dbus_bool_t b;
2192                 dbus_message_iter_get_basic(iter, &b);
2193                 printf("%s=%s\n", name, yes_no(b));
2194
2195                 return 0;
2196         }
2197
2198         case DBUS_TYPE_UINT64: {
2199                 uint64_t u;
2200                 dbus_message_iter_get_basic(iter, &u);
2201
2202                 /* Yes, heuristics! But we can change this check
2203                  * should it turn out to not be sufficient */
2204
2205                 if (strstr(name, "Timestamp")) {
2206                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
2207
2208                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
2209                                 printf("%s=%s\n", name, strempty(t));
2210                 } else if (strstr(name, "USec")) {
2211                         char timespan[FORMAT_TIMESPAN_MAX];
2212
2213                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
2214                 } else
2215                         printf("%s=%llu\n", name, (unsigned long long) u);
2216
2217                 return 0;
2218         }
2219
2220         case DBUS_TYPE_UINT32: {
2221                 uint32_t u;
2222                 dbus_message_iter_get_basic(iter, &u);
2223
2224                 if (strstr(name, "UMask") || strstr(name, "Mode"))
2225                         printf("%s=%04o\n", name, u);
2226                 else
2227                         printf("%s=%u\n", name, (unsigned) u);
2228
2229                 return 0;
2230         }
2231
2232         case DBUS_TYPE_INT32: {
2233                 int32_t i;
2234                 dbus_message_iter_get_basic(iter, &i);
2235
2236                 printf("%s=%i\n", name, (int) i);
2237                 return 0;
2238         }
2239
2240         case DBUS_TYPE_DOUBLE: {
2241                 double d;
2242                 dbus_message_iter_get_basic(iter, &d);
2243
2244                 printf("%s=%g\n", name, d);
2245                 return 0;
2246         }
2247
2248         case DBUS_TYPE_STRUCT: {
2249                 DBusMessageIter sub;
2250                 dbus_message_iter_recurse(iter, &sub);
2251
2252                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2253                         uint32_t u;
2254
2255                         dbus_message_iter_get_basic(&sub, &u);
2256
2257                         if (u)
2258                                 printf("%s=%u\n", name, (unsigned) u);
2259                         else if (arg_all)
2260                                 printf("%s=\n", name);
2261
2262                         return 0;
2263                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2264                         const char *s;
2265
2266                         dbus_message_iter_get_basic(&sub, &s);
2267
2268                         if (arg_all || s[0])
2269                                 printf("%s=%s\n", name, s);
2270
2271                         return 0;
2272                 }
2273
2274                 break;
2275         }
2276
2277         case DBUS_TYPE_ARRAY:
2278
2279                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
2280                         DBusMessageIter sub;
2281                         bool space = false;
2282
2283                         dbus_message_iter_recurse(iter, &sub);
2284                         if (arg_all ||
2285                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2286                                 printf("%s=", name);
2287
2288                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2289                                         const char *s;
2290
2291                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
2292                                         dbus_message_iter_get_basic(&sub, &s);
2293                                         printf("%s%s", space ? " " : "", s);
2294
2295                                         space = true;
2296                                         dbus_message_iter_next(&sub);
2297                                 }
2298
2299                                 puts("");
2300                         }
2301
2302                         return 0;
2303
2304                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
2305                         DBusMessageIter sub;
2306
2307                         dbus_message_iter_recurse(iter, &sub);
2308                         if (arg_all ||
2309                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2310                                 printf("%s=", name);
2311
2312                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2313                                         uint8_t u;
2314
2315                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
2316                                         dbus_message_iter_get_basic(&sub, &u);
2317                                         printf("%02x", u);
2318
2319                                         dbus_message_iter_next(&sub);
2320                                 }
2321
2322                                 puts("");
2323                         }
2324
2325                         return 0;
2326
2327                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2328                         DBusMessageIter sub, sub2;
2329
2330                         dbus_message_iter_recurse(iter, &sub);
2331                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2332                                 const char *type, *path;
2333
2334                                 dbus_message_iter_recurse(&sub, &sub2);
2335
2336                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2337                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2338                                         printf("%s=%s\n", type, path);
2339
2340                                 dbus_message_iter_next(&sub);
2341                         }
2342
2343                         return 0;
2344
2345                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2346                         DBusMessageIter sub, sub2;
2347
2348                         dbus_message_iter_recurse(iter, &sub);
2349                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2350                                 const char *base;
2351                                 uint64_t value, next_elapse;
2352
2353                                 dbus_message_iter_recurse(&sub, &sub2);
2354
2355                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2356                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2357                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2358                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2359
2360                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2361                                                base,
2362                                                format_timespan(timespan1, sizeof(timespan1), value),
2363                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2364                                 }
2365
2366                                 dbus_message_iter_next(&sub);
2367                         }
2368
2369                         return 0;
2370
2371                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2372                         DBusMessageIter sub;
2373
2374                         dbus_message_iter_recurse(iter, &sub);
2375                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2376                                 ExecStatusInfo info;
2377
2378                                 zero(info);
2379                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2380                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2381                                         char *t;
2382
2383                                         t = strv_join(info.argv, " ");
2384
2385                                         printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2386                                                name,
2387                                                strna(info.path),
2388                                                strna(t),
2389                                                yes_no(info.ignore),
2390                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2391                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2392                                                (unsigned) info. pid,
2393                                                sigchld_code_to_string(info.code),
2394                                                info.status,
2395                                                info.code == CLD_EXITED ? "" : "/",
2396                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2397
2398                                         free(t);
2399                                 }
2400
2401                                 free(info.path);
2402                                 strv_free(info.argv);
2403
2404                                 dbus_message_iter_next(&sub);
2405                         }
2406
2407                         return 0;
2408                 }
2409
2410                 break;
2411         }
2412
2413         if (arg_all)
2414                 printf("%s=[unprintable]\n", name);
2415
2416         return 0;
2417 }
2418
2419 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2420         DBusMessage *m = NULL, *reply = NULL;
2421         const char *interface = "";
2422         int r;
2423         DBusError error;
2424         DBusMessageIter iter, sub, sub2, sub3;
2425         UnitStatusInfo info;
2426         ExecStatusInfo *p;
2427
2428         assert(bus);
2429         assert(path);
2430         assert(new_line);
2431
2432         zero(info);
2433         dbus_error_init(&error);
2434
2435         if (!(m = dbus_message_new_method_call(
2436                               "org.freedesktop.systemd1",
2437                               path,
2438                               "org.freedesktop.DBus.Properties",
2439                               "GetAll"))) {
2440                 log_error("Could not allocate message.");
2441                 r = -ENOMEM;
2442                 goto finish;
2443         }
2444
2445         if (!dbus_message_append_args(m,
2446                                       DBUS_TYPE_STRING, &interface,
2447                                       DBUS_TYPE_INVALID)) {
2448                 log_error("Could not append arguments to message.");
2449                 r = -ENOMEM;
2450                 goto finish;
2451         }
2452
2453         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2454                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2455                 r = -EIO;
2456                 goto finish;
2457         }
2458
2459         if (!dbus_message_iter_init(reply, &iter) ||
2460             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2461             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2462                 log_error("Failed to parse reply.");
2463                 r = -EIO;
2464                 goto finish;
2465         }
2466
2467         dbus_message_iter_recurse(&iter, &sub);
2468
2469         if (*new_line)
2470                 printf("\n");
2471
2472         *new_line = true;
2473
2474         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2475                 const char *name;
2476
2477                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2478                         log_error("Failed to parse reply.");
2479                         r = -EIO;
2480                         goto finish;
2481                 }
2482
2483                 dbus_message_iter_recurse(&sub, &sub2);
2484
2485                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2486                         log_error("Failed to parse reply.");
2487                         r = -EIO;
2488                         goto finish;
2489                 }
2490
2491                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2492                         log_error("Failed to parse reply.");
2493                         r = -EIO;
2494                         goto finish;
2495                 }
2496
2497                 dbus_message_iter_recurse(&sub2, &sub3);
2498
2499                 if (show_properties)
2500                         r = print_property(name, &sub3);
2501                 else
2502                         r = status_property(name, &sub3, &info);
2503
2504                 if (r < 0) {
2505                         log_error("Failed to parse reply.");
2506                         r = -EIO;
2507                         goto finish;
2508                 }
2509
2510                 dbus_message_iter_next(&sub);
2511         }
2512
2513         r = 0;
2514
2515         if (!show_properties)
2516                 print_status_info(&info);
2517
2518         if (!streq_ptr(info.active_state, "active") &&
2519             !streq_ptr(info.active_state, "reloading") &&
2520             streq(verb, "status"))
2521                 /* According to LSB: "program not running" */
2522                 r = 3;
2523
2524         while ((p = info.exec)) {
2525                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2526                 exec_status_info_free(p);
2527         }
2528
2529 finish:
2530         if (m)
2531                 dbus_message_unref(m);
2532
2533         if (reply)
2534                 dbus_message_unref(reply);
2535
2536         dbus_error_free(&error);
2537
2538         return r;
2539 }
2540
2541 static int show(DBusConnection *bus, char **args, unsigned n) {
2542         DBusMessage *m = NULL, *reply = NULL;
2543         int r, ret = 0;
2544         DBusError error;
2545         unsigned i;
2546         bool show_properties, new_line = false;
2547
2548         assert(bus);
2549         assert(args);
2550
2551         dbus_error_init(&error);
2552
2553         show_properties = !streq(args[0], "status");
2554
2555         if (show_properties)
2556                 pager_open();
2557
2558         if (show_properties && n <= 1) {
2559                 /* If not argument is specified inspect the manager
2560                  * itself */
2561
2562                 ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2563                 goto finish;
2564         }
2565
2566         for (i = 1; i < n; i++) {
2567                 const char *path = NULL;
2568                 uint32_t id;
2569
2570                 if (safe_atou32(args[i], &id) < 0) {
2571
2572                         /* Interpret as unit name */
2573
2574                         if (!(m = dbus_message_new_method_call(
2575                                               "org.freedesktop.systemd1",
2576                                               "/org/freedesktop/systemd1",
2577                                               "org.freedesktop.systemd1.Manager",
2578                                               "LoadUnit"))) {
2579                                 log_error("Could not allocate message.");
2580                                 ret = -ENOMEM;
2581                                 goto finish;
2582                         }
2583
2584                         if (!dbus_message_append_args(m,
2585                                                       DBUS_TYPE_STRING, &args[i],
2586                                                       DBUS_TYPE_INVALID)) {
2587                                 log_error("Could not append arguments to message.");
2588                                 ret = -ENOMEM;
2589                                 goto finish;
2590                         }
2591
2592                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2593
2594                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2595                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2596                                         ret = -EIO;
2597                                         goto finish;
2598                                 }
2599
2600                                 dbus_error_free(&error);
2601
2602                                 dbus_message_unref(m);
2603                                 if (!(m = dbus_message_new_method_call(
2604                                                       "org.freedesktop.systemd1",
2605                                                       "/org/freedesktop/systemd1",
2606                                                       "org.freedesktop.systemd1.Manager",
2607                                                       "GetUnit"))) {
2608                                         log_error("Could not allocate message.");
2609                                         ret = -ENOMEM;
2610                                         goto finish;
2611                                 }
2612
2613                                 if (!dbus_message_append_args(m,
2614                                                               DBUS_TYPE_STRING, &args[i],
2615                                                               DBUS_TYPE_INVALID)) {
2616                                         log_error("Could not append arguments to message.");
2617                                         ret = -ENOMEM;
2618                                         goto finish;
2619                                 }
2620
2621                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2622                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2623
2624                                         if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
2625                                                 ret = 4; /* According to LSB: "program or service status is unknown" */
2626                                         else
2627                                                 ret = -EIO;
2628                                         goto finish;
2629                                 }
2630                         }
2631
2632                 } else if (show_properties) {
2633
2634                         /* Interpret as job id */
2635
2636                         if (!(m = dbus_message_new_method_call(
2637                                               "org.freedesktop.systemd1",
2638                                               "/org/freedesktop/systemd1",
2639                                               "org.freedesktop.systemd1.Manager",
2640                                               "GetJob"))) {
2641                                 log_error("Could not allocate message.");
2642                                 ret = -ENOMEM;
2643                                 goto finish;
2644                         }
2645
2646                         if (!dbus_message_append_args(m,
2647                                                       DBUS_TYPE_UINT32, &id,
2648                                                       DBUS_TYPE_INVALID)) {
2649                                 log_error("Could not append arguments to message.");
2650                                 ret = -ENOMEM;
2651                                 goto finish;
2652                         }
2653
2654                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2655                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2656                                 ret = -EIO;
2657                                 goto finish;
2658                         }
2659                 } else {
2660
2661                         /* Interpret as PID */
2662
2663                         if (!(m = dbus_message_new_method_call(
2664                                               "org.freedesktop.systemd1",
2665                                               "/org/freedesktop/systemd1",
2666                                               "org.freedesktop.systemd1.Manager",
2667                                               "GetUnitByPID"))) {
2668                                 log_error("Could not allocate message.");
2669                                 ret = -ENOMEM;
2670                                 goto finish;
2671                         }
2672
2673                         if (!dbus_message_append_args(m,
2674                                                       DBUS_TYPE_UINT32, &id,
2675                                                       DBUS_TYPE_INVALID)) {
2676                                 log_error("Could not append arguments to message.");
2677                                 ret = -ENOMEM;
2678                                 goto finish;
2679                         }
2680
2681                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2682                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2683                                 ret = -EIO;
2684                                 goto finish;
2685                         }
2686                 }
2687
2688                 if (!dbus_message_get_args(reply, &error,
2689                                            DBUS_TYPE_OBJECT_PATH, &path,
2690                                            DBUS_TYPE_INVALID)) {
2691                         log_error("Failed to parse reply: %s", bus_error_message(&error));
2692                         ret = -EIO;
2693                         goto finish;
2694                 }
2695
2696                 if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
2697                         ret = r;
2698
2699                 dbus_message_unref(m);
2700                 dbus_message_unref(reply);
2701                 m = reply = NULL;
2702         }
2703
2704 finish:
2705         if (m)
2706                 dbus_message_unref(m);
2707
2708         if (reply)
2709                 dbus_message_unref(reply);
2710
2711         dbus_error_free(&error);
2712
2713         return ret;
2714 }
2715
2716 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
2717         DBusError error;
2718         DBusMessage *m = NULL, *reply = NULL;
2719
2720         assert(connection);
2721         assert(message);
2722
2723         dbus_error_init(&error);
2724
2725         log_debug("Got D-Bus request: %s.%s() on %s",
2726                   dbus_message_get_interface(message),
2727                   dbus_message_get_member(message),
2728                   dbus_message_get_path(message));
2729
2730         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
2731                 log_error("Warning! D-Bus connection terminated.");
2732                 dbus_connection_close(connection);
2733
2734         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
2735                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2736                 const char *id, *path;
2737
2738                 if (!dbus_message_get_args(message, &error,
2739                                            DBUS_TYPE_STRING, &id,
2740                                            DBUS_TYPE_OBJECT_PATH, &path,
2741                                            DBUS_TYPE_INVALID))
2742                         log_error("Failed to parse message: %s", bus_error_message(&error));
2743                 else if (streq(dbus_message_get_member(message), "UnitNew"))
2744                         printf("Unit %s added.\n", id);
2745                 else
2746                         printf("Unit %s removed.\n", id);
2747
2748         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
2749                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2750                 uint32_t id;
2751                 const char *path;
2752
2753                 if (!dbus_message_get_args(message, &error,
2754                                            DBUS_TYPE_UINT32, &id,
2755                                            DBUS_TYPE_OBJECT_PATH, &path,
2756                                            DBUS_TYPE_INVALID))
2757                         log_error("Failed to parse message: %s", bus_error_message(&error));
2758                 else if (streq(dbus_message_get_member(message), "JobNew"))
2759                         printf("Job %u added.\n", id);
2760                 else
2761                         printf("Job %u removed.\n", id);
2762
2763
2764         } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2765
2766                 const char *path, *interface, *property = "Id";
2767                 DBusMessageIter iter, sub;
2768
2769                 path = dbus_message_get_path(message);
2770
2771                 if (!dbus_message_get_args(message, &error,
2772                                           DBUS_TYPE_STRING, &interface,
2773                                           DBUS_TYPE_INVALID)) {
2774                         log_error("Failed to parse message: %s", bus_error_message(&error));
2775                         goto finish;
2776                 }
2777
2778                 if (!streq(interface, "org.freedesktop.systemd1.Job") &&
2779                     !streq(interface, "org.freedesktop.systemd1.Unit"))
2780                         goto finish;
2781
2782                 if (!(m = dbus_message_new_method_call(
2783                               "org.freedesktop.systemd1",
2784                               path,
2785                               "org.freedesktop.DBus.Properties",
2786                               "Get"))) {
2787                         log_error("Could not allocate message.");
2788                         goto oom;
2789                 }
2790
2791                 if (!dbus_message_append_args(m,
2792                                               DBUS_TYPE_STRING, &interface,
2793                                               DBUS_TYPE_STRING, &property,
2794                                               DBUS_TYPE_INVALID)) {
2795                         log_error("Could not append arguments to message.");
2796                         goto finish;
2797                 }
2798
2799                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
2800                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2801                         goto finish;
2802                 }
2803
2804                 if (!dbus_message_iter_init(reply, &iter) ||
2805                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2806                         log_error("Failed to parse reply.");
2807                         goto finish;
2808                 }
2809
2810                 dbus_message_iter_recurse(&iter, &sub);
2811
2812                 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
2813                         const char *id;
2814
2815                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2816                                 log_error("Failed to parse reply.");
2817                                 goto finish;
2818                         }
2819
2820                         dbus_message_iter_get_basic(&sub, &id);
2821                         printf("Unit %s changed.\n", id);
2822                 } else {
2823                         uint32_t id;
2824
2825                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)  {
2826                                 log_error("Failed to parse reply.");
2827                                 goto finish;
2828                         }
2829
2830                         dbus_message_iter_get_basic(&sub, &id);
2831                         printf("Job %u changed.\n", id);
2832                 }
2833         }
2834
2835 finish:
2836         if (m)
2837                 dbus_message_unref(m);
2838
2839         if (reply)
2840                 dbus_message_unref(reply);
2841
2842         dbus_error_free(&error);
2843         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2844
2845 oom:
2846         if (m)
2847                 dbus_message_unref(m);
2848
2849         if (reply)
2850                 dbus_message_unref(reply);
2851
2852         dbus_error_free(&error);
2853         return DBUS_HANDLER_RESULT_NEED_MEMORY;
2854 }
2855
2856 static int monitor(DBusConnection *bus, char **args, unsigned n) {
2857         DBusMessage *m = NULL, *reply = NULL;
2858         DBusError error;
2859         int r;
2860
2861         dbus_error_init(&error);
2862
2863         if (!private_bus) {
2864                 dbus_bus_add_match(bus,
2865                                    "type='signal',"
2866                                    "sender='org.freedesktop.systemd1',"
2867                                    "interface='org.freedesktop.systemd1.Manager',"
2868                                    "path='/org/freedesktop/systemd1'",
2869                                    &error);
2870
2871                 if (dbus_error_is_set(&error)) {
2872                         log_error("Failed to add match: %s", bus_error_message(&error));
2873                         r = -EIO;
2874                         goto finish;
2875                 }
2876
2877                 dbus_bus_add_match(bus,
2878                                    "type='signal',"
2879                                    "sender='org.freedesktop.systemd1',"
2880                                    "interface='org.freedesktop.DBus.Properties',"
2881                                    "member='PropertiesChanged'",
2882                                    &error);
2883
2884                 if (dbus_error_is_set(&error)) {
2885                         log_error("Failed to add match: %s", bus_error_message(&error));
2886                         r = -EIO;
2887                         goto finish;
2888                 }
2889         }
2890
2891         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
2892                 log_error("Failed to add filter.");
2893                 r = -ENOMEM;
2894                 goto finish;
2895         }
2896
2897         if (!(m = dbus_message_new_method_call(
2898                               "org.freedesktop.systemd1",
2899                               "/org/freedesktop/systemd1",
2900                               "org.freedesktop.systemd1.Manager",
2901                               "Subscribe"))) {
2902                 log_error("Could not allocate message.");
2903                 r = -ENOMEM;
2904                 goto finish;
2905         }
2906
2907         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2908                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2909                 r = -EIO;
2910                 goto finish;
2911         }
2912
2913         while (dbus_connection_read_write_dispatch(bus, -1))
2914                 ;
2915
2916         r = 0;
2917
2918 finish:
2919
2920         /* This is slightly dirty, since we don't undo the filter or the matches. */
2921
2922         if (m)
2923                 dbus_message_unref(m);
2924
2925         if (reply)
2926                 dbus_message_unref(reply);
2927
2928         dbus_error_free(&error);
2929
2930         return r;
2931 }
2932
2933 static int dump(DBusConnection *bus, char **args, unsigned n) {
2934         DBusMessage *m = NULL, *reply = NULL;
2935         DBusError error;
2936         int r;
2937         const char *text;
2938
2939         dbus_error_init(&error);
2940
2941         pager_open();
2942
2943         if (!(m = dbus_message_new_method_call(
2944                               "org.freedesktop.systemd1",
2945                               "/org/freedesktop/systemd1",
2946                               "org.freedesktop.systemd1.Manager",
2947                               "Dump"))) {
2948                 log_error("Could not allocate message.");
2949                 return -ENOMEM;
2950         }
2951
2952         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2953                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2954                 r = -EIO;
2955                 goto finish;
2956         }
2957
2958         if (!dbus_message_get_args(reply, &error,
2959                                    DBUS_TYPE_STRING, &text,
2960                                    DBUS_TYPE_INVALID)) {
2961                 log_error("Failed to parse reply: %s", bus_error_message(&error));
2962                 r = -EIO;
2963                 goto finish;
2964         }
2965
2966         fputs(text, stdout);
2967
2968         r = 0;
2969
2970 finish:
2971         if (m)
2972                 dbus_message_unref(m);
2973
2974         if (reply)
2975                 dbus_message_unref(reply);
2976
2977         dbus_error_free(&error);
2978
2979         return r;
2980 }
2981
2982 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
2983         DBusMessage *m = NULL, *reply = NULL;
2984         DBusError error;
2985         int r;
2986         const char *name = "", *path, *id;
2987         dbus_bool_t cleanup = FALSE;
2988         DBusMessageIter iter, sub;
2989         const char
2990                 *interface = "org.freedesktop.systemd1.Unit",
2991                 *property = "Id";
2992
2993         dbus_error_init(&error);
2994
2995         if (!(m = dbus_message_new_method_call(
2996                               "org.freedesktop.systemd1",
2997                               "/org/freedesktop/systemd1",
2998                               "org.freedesktop.systemd1.Manager",
2999                               "CreateSnapshot"))) {
3000                 log_error("Could not allocate message.");
3001                 return -ENOMEM;
3002         }
3003
3004         if (n > 1)
3005                 name = args[1];
3006
3007         if (!dbus_message_append_args(m,
3008                                       DBUS_TYPE_STRING, &name,
3009                                       DBUS_TYPE_BOOLEAN, &cleanup,
3010                                       DBUS_TYPE_INVALID)) {
3011                 log_error("Could not append arguments to message.");
3012                 r = -ENOMEM;
3013                 goto finish;
3014         }
3015
3016         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3017                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3018                 r = -EIO;
3019                 goto finish;
3020         }
3021
3022         if (!dbus_message_get_args(reply, &error,
3023                                    DBUS_TYPE_OBJECT_PATH, &path,
3024                                    DBUS_TYPE_INVALID)) {
3025                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3026                 r = -EIO;
3027                 goto finish;
3028         }
3029
3030         dbus_message_unref(m);
3031         if (!(m = dbus_message_new_method_call(
3032                               "org.freedesktop.systemd1",
3033                               path,
3034                               "org.freedesktop.DBus.Properties",
3035                               "Get"))) {
3036                 log_error("Could not allocate message.");
3037                 return -ENOMEM;
3038         }
3039
3040         if (!dbus_message_append_args(m,
3041                                       DBUS_TYPE_STRING, &interface,
3042                                       DBUS_TYPE_STRING, &property,
3043                                       DBUS_TYPE_INVALID)) {
3044                 log_error("Could not append arguments to message.");
3045                 r = -ENOMEM;
3046                 goto finish;
3047         }
3048
3049         dbus_message_unref(reply);
3050         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3051                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3052                 r = -EIO;
3053                 goto finish;
3054         }
3055
3056         if (!dbus_message_iter_init(reply, &iter) ||
3057             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3058                 log_error("Failed to parse reply.");
3059                 r = -EIO;
3060                 goto finish;
3061         }
3062
3063         dbus_message_iter_recurse(&iter, &sub);
3064
3065         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3066                 log_error("Failed to parse reply.");
3067                 r = -EIO;
3068                 goto finish;
3069         }
3070
3071         dbus_message_iter_get_basic(&sub, &id);
3072
3073         if (!arg_quiet)
3074                 puts(id);
3075         r = 0;
3076
3077 finish:
3078         if (m)
3079                 dbus_message_unref(m);
3080
3081         if (reply)
3082                 dbus_message_unref(reply);
3083
3084         dbus_error_free(&error);
3085
3086         return r;
3087 }
3088
3089 static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
3090         DBusMessage *m = NULL, *reply = NULL;
3091         int r;
3092         DBusError error;
3093         unsigned i;
3094
3095         assert(bus);
3096         assert(args);
3097
3098         dbus_error_init(&error);
3099
3100         for (i = 1; i < n; i++) {
3101                 const char *path = NULL;
3102
3103                 if (!(m = dbus_message_new_method_call(
3104                                       "org.freedesktop.systemd1",
3105                                       "/org/freedesktop/systemd1",
3106                                       "org.freedesktop.systemd1.Manager",
3107                                       "GetUnit"))) {
3108                         log_error("Could not allocate message.");
3109                         r = -ENOMEM;
3110                         goto finish;
3111                 }
3112
3113                 if (!dbus_message_append_args(m,
3114                                               DBUS_TYPE_STRING, &args[i],
3115                                               DBUS_TYPE_INVALID)) {
3116                         log_error("Could not append arguments to message.");
3117                         r = -ENOMEM;
3118                         goto finish;
3119                 }
3120
3121                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3122                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3123                         r = -EIO;
3124                         goto finish;
3125                 }
3126
3127                 if (!dbus_message_get_args(reply, &error,
3128                                            DBUS_TYPE_OBJECT_PATH, &path,
3129                                            DBUS_TYPE_INVALID)) {
3130                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3131                         r = -EIO;
3132                         goto finish;
3133                 }
3134
3135                 dbus_message_unref(m);
3136                 if (!(m = dbus_message_new_method_call(
3137                                       "org.freedesktop.systemd1",
3138                                       path,
3139                                       "org.freedesktop.systemd1.Snapshot",
3140                                       "Remove"))) {
3141                         log_error("Could not allocate message.");
3142                         r = -ENOMEM;
3143                         goto finish;
3144                 }