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