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