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