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