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