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