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