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