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