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