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