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