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