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