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