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