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