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