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