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