chiark / gitweb /
systemctl: make LOAD column width dynamic
[elogind.git] / src / systemctl / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <linux/reboot.h>
24 #include <sys/syscall.h>
25 #include <stdio.h>
26 #include <getopt.h>
27 #include <locale.h>
28 #include <stdbool.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/ioctl.h>
32 #include <termios.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <stddef.h>
38 #include <sys/prctl.h>
39 #include <dbus/dbus.h>
40
41 #include <systemd/sd-daemon.h>
42 #include <systemd/sd-shutdown.h>
43 #include <systemd/sd-login.h>
44
45 #include "log.h"
46 #include "util.h"
47 #include "macro.h"
48 #include "set.h"
49 #include "utmp-wtmp.h"
50 #include "special.h"
51 #include "initreq.h"
52 #include "path-util.h"
53 #include "strv.h"
54 #include "dbus-common.h"
55 #include "cgroup-show.h"
56 #include "cgroup-util.h"
57 #include "list.h"
58 #include "path-lookup.h"
59 #include "conf-parser.h"
60 #include "exit-status.h"
61 #include "bus-errors.h"
62 #include "build.h"
63 #include "unit-name.h"
64 #include "pager.h"
65 #include "spawn-ask-password-agent.h"
66 #include "spawn-polkit-agent.h"
67 #include "install.h"
68 #include "logs-show.h"
69 #include "path-util.h"
70 #include "socket-util.h"
71 #include "fileio.h"
72
73 static char **arg_types = NULL;
74 static char **arg_states = NULL;
75 static char **arg_properties = NULL;
76 static bool arg_all = false;
77 static bool original_stdout_is_tty;
78 static enum dependency {
79         DEPENDENCY_FORWARD,
80         DEPENDENCY_REVERSE,
81         DEPENDENCY_AFTER,
82         DEPENDENCY_BEFORE,
83 } arg_dependency = DEPENDENCY_FORWARD;
84 static const char *arg_job_mode = "replace";
85 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
86 static bool arg_no_block = false;
87 static bool arg_no_legend = false;
88 static bool arg_no_pager = false;
89 static bool arg_no_wtmp = false;
90 static bool arg_no_wall = false;
91 static bool arg_no_reload = false;
92 static bool arg_show_types = false;
93 static bool arg_ignore_inhibitors = false;
94 static bool arg_dry = false;
95 static bool arg_quiet = false;
96 static bool arg_full = false;
97 static int arg_force = 0;
98 static bool arg_ask_password = true;
99 static bool arg_runtime = false;
100 static char **arg_wall = NULL;
101 static const char *arg_kill_who = NULL;
102 static int arg_signal = SIGTERM;
103 static const char *arg_root = NULL;
104 static usec_t arg_when = 0;
105 static enum action {
106         ACTION_INVALID,
107         ACTION_SYSTEMCTL,
108         ACTION_HALT,
109         ACTION_POWEROFF,
110         ACTION_REBOOT,
111         ACTION_KEXEC,
112         ACTION_EXIT,
113         ACTION_SUSPEND,
114         ACTION_HIBERNATE,
115         ACTION_HYBRID_SLEEP,
116         ACTION_RUNLEVEL2,
117         ACTION_RUNLEVEL3,
118         ACTION_RUNLEVEL4,
119         ACTION_RUNLEVEL5,
120         ACTION_RESCUE,
121         ACTION_EMERGENCY,
122         ACTION_DEFAULT,
123         ACTION_RELOAD,
124         ACTION_REEXEC,
125         ACTION_RUNLEVEL,
126         ACTION_CANCEL_SHUTDOWN,
127         _ACTION_MAX
128 } arg_action = ACTION_SYSTEMCTL;
129 static enum transport {
130         TRANSPORT_NORMAL,
131         TRANSPORT_SSH,
132         TRANSPORT_POLKIT
133 } arg_transport = TRANSPORT_NORMAL;
134 static char *arg_host = NULL;
135 static char *arg_user = NULL;
136 static unsigned arg_lines = 10;
137 static OutputMode arg_output = OUTPUT_SHORT;
138 static bool arg_plain = false;
139
140 static bool private_bus = false;
141
142 static int daemon_reload(DBusConnection *bus, char **args);
143 static void halt_now(enum action a);
144
145 static void pager_open_if_enabled(void) {
146
147         if (arg_no_pager)
148                 return;
149
150         pager_open(false);
151 }
152
153 static void ask_password_agent_open_if_enabled(void) {
154
155         /* Open the password agent as a child process if necessary */
156
157         if (!arg_ask_password)
158                 return;
159
160         if (arg_scope != UNIT_FILE_SYSTEM)
161                 return;
162
163         ask_password_agent_open();
164 }
165
166 #ifdef HAVE_LOGIND
167 static void polkit_agent_open_if_enabled(void) {
168
169         /* Open the polkit agent as a child process if necessary */
170
171         if (!arg_ask_password)
172                 return;
173
174         if (arg_scope != UNIT_FILE_SYSTEM)
175                 return;
176
177         polkit_agent_open();
178 }
179 #endif
180
181 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
182         assert(error);
183
184         if (!dbus_error_is_set(error))
185                 return r;
186
187         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
188             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
189             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
190             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
191                 return EXIT_NOPERMISSION;
192
193         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
194                 return EXIT_NOTINSTALLED;
195
196         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
197             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
198                 return EXIT_NOTIMPLEMENTED;
199
200         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
201                 return EXIT_NOTCONFIGURED;
202
203         if (r != 0)
204                 return r;
205
206         return EXIT_FAILURE;
207 }
208
209 static void warn_wall(enum action a) {
210         static const char *table[_ACTION_MAX] = {
211                 [ACTION_HALT]            = "The system is going down for system halt NOW!",
212                 [ACTION_REBOOT]          = "The system is going down for reboot NOW!",
213                 [ACTION_POWEROFF]        = "The system is going down for power-off NOW!",
214                 [ACTION_KEXEC]           = "The system is going down for kexec reboot NOW!",
215                 [ACTION_RESCUE]          = "The system is going down to rescue mode NOW!",
216                 [ACTION_EMERGENCY]       = "The system is going down to emergency mode NOW!",
217                 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
218         };
219
220         if (arg_no_wall)
221                 return;
222
223         if (arg_wall) {
224                 _cleanup_free_ char *p;
225
226                 p = strv_join(arg_wall, " ");
227                 if (!p) {
228                         log_oom();
229                         return;
230                 }
231
232                 if (*p) {
233                         utmp_wall(p, NULL);
234                         return;
235                 }
236         }
237
238         if (!table[a])
239                 return;
240
241         utmp_wall(table[a], NULL);
242 }
243
244 static bool avoid_bus(void) {
245
246         if (running_in_chroot() > 0)
247                 return true;
248
249         if (sd_booted() <= 0)
250                 return true;
251
252         if (!isempty(arg_root))
253                 return true;
254
255         if (arg_scope == UNIT_FILE_GLOBAL)
256                 return true;
257
258         return false;
259 }
260
261 static int compare_unit_info(const void *a, const void *b) {
262         const char *d1, *d2;
263         const struct unit_info *u = a, *v = b;
264
265         d1 = strrchr(u->id, '.');
266         d2 = strrchr(v->id, '.');
267
268         if (d1 && d2) {
269                 int r;
270
271                 r = strcasecmp(d1, d2);
272                 if (r != 0)
273                         return r;
274         }
275
276         return strcasecmp(u->id, v->id);
277 }
278
279 static bool output_show_unit(const struct unit_info *u) {
280         const char *dot;
281
282         if (!strv_isempty(arg_states))
283                 return strv_contains(arg_states, u->load_state) || strv_contains(arg_states, u->sub_state) || strv_contains(arg_states, u->active_state);
284
285         return (!arg_types || ((dot = strrchr(u->id, '.')) &&
286                                strv_find(arg_types, dot+1))) &&
287                 (arg_all || !(streq(u->active_state, "inactive")
288                               || u->following[0]) || u->job_id > 0);
289 }
290
291 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
292         unsigned id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len;
293         unsigned n_shown = 0;
294         const struct unit_info *u;
295         int job_count = 0;
296
297         max_id_len = strlen("UNIT");
298         load_len = strlen("LOAD");
299         active_len = strlen("ACTIVE");
300         sub_len = strlen("SUB");
301         job_len = strlen("JOB");
302         desc_len = 0;
303
304         for (u = unit_infos; u < unit_infos + c; u++) {
305                 if (!output_show_unit(u))
306                         continue;
307
308                 max_id_len = MAX(max_id_len, strlen(u->id));
309                 load_len = MAX(load_len, strlen(u->load_state));
310                 active_len = MAX(active_len, strlen(u->active_state));
311                 sub_len = MAX(sub_len, strlen(u->sub_state));
312                 if (u->job_id != 0) {
313                         job_len = MAX(job_len, strlen(u->job_type));
314                         job_count++;
315                 }
316         }
317
318         if (!arg_full && original_stdout_is_tty) {
319                 unsigned basic_len;
320                 id_len = MIN(max_id_len, 25u);
321                 basic_len = 5 + id_len + 5 + active_len + sub_len;
322                 if (job_count)
323                         basic_len += job_len + 1;
324                 if (basic_len < (unsigned) columns()) {
325                         unsigned extra_len, incr;
326                         extra_len = columns() - basic_len;
327                         /* Either UNIT already got 25, or is fully satisfied.
328                          * Grant up to 25 to DESC now. */
329                         incr = MIN(extra_len, 25u);
330                         desc_len += incr;
331                         extra_len -= incr;
332                         /* split the remaining space between UNIT and DESC,
333                          * but do not give UNIT more than it needs. */
334                         if (extra_len > 0) {
335                                 incr = MIN(extra_len / 2, max_id_len - id_len);
336                                 id_len += incr;
337                                 desc_len += extra_len - incr;
338                         }
339                 }
340         } else
341                 id_len = max_id_len;
342
343         for (u = unit_infos; u < unit_infos + c; u++) {
344                 _cleanup_free_ char *e = NULL;
345                 const char *on_loaded, *off_loaded, *on = "";
346                 const char *on_active, *off_active, *off = "";
347
348                 if (!output_show_unit(u))
349                         continue;
350
351                 if (!n_shown && !arg_no_legend) {
352                         printf("%-*s %-*s %-*s %-*s ", id_len, "UNIT", load_len, "LOAD",
353                                active_len, "ACTIVE", sub_len, "SUB");
354                         if (job_count)
355                                 printf("%-*s ", job_len, "JOB");
356                         if (!arg_full && arg_no_pager)
357                                 printf("%.*s\n", desc_len, "DESCRIPTION");
358                         else
359                                 printf("%s\n", "DESCRIPTION");
360                 }
361
362                 n_shown++;
363
364                 if (streq(u->load_state, "error") ||
365                     streq(u->load_state, "not-found")) {
366                         on_loaded = on = ansi_highlight_red();
367                         off_loaded = off = ansi_highlight_off();
368                 } else
369                         on_loaded = off_loaded = "";
370
371                 if (streq(u->active_state, "failed")) {
372                         on_active = on = ansi_highlight_red();
373                         off_active = off = ansi_highlight_off();
374                 } else
375                         on_active = off_active = "";
376
377                 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
378
379                 printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
380                        on, id_len, e ? e : u->id, off,
381                        on_loaded, load_len, u->load_state, off_loaded,
382                        on_active, active_len, u->active_state,
383                        sub_len, u->sub_state, off_active,
384                        job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
385                 if (desc_len > 0)
386                         printf("%.*s\n", desc_len, u->description);
387                 else
388                         printf("%s\n", u->description);
389         }
390
391         if (!arg_no_legend) {
392                 const char *on, *off;
393
394                 if (n_shown) {
395                         printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
396                                "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
397                                "SUB    = The low-level unit activation state, values depend on unit type.\n");
398                         if (job_count)
399                                 printf("JOB    = Pending job for the unit.\n");
400                         puts("");
401                         on = ansi_highlight();
402                         off = ansi_highlight_off();
403                 } else {
404                         on = ansi_highlight_red();
405                         off = ansi_highlight_off();
406                 }
407
408                 if (arg_all)
409                         printf("%s%u loaded units listed.%s\n"
410                                "To show all installed unit files use 'systemctl list-unit-files'.\n",
411                                on, n_shown, off);
412                 else
413                         printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
414                                "To show all installed unit files use 'systemctl list-unit-files'.\n",
415                                on, n_shown, off);
416         }
417 }
418
419 static int get_unit_list(
420                 DBusConnection *bus,
421                 DBusMessage **reply,
422                 struct unit_info **unit_infos,
423                 unsigned *c) {
424
425         DBusMessageIter iter, sub;
426         size_t size = 0;
427         int r;
428
429         assert(bus);
430         assert(unit_infos);
431         assert(c);
432
433         r = bus_method_call_with_reply(
434                         bus,
435                         "org.freedesktop.systemd1",
436                         "/org/freedesktop/systemd1",
437                         "org.freedesktop.systemd1.Manager",
438                         "ListUnits",
439                         reply,
440                         NULL,
441                         DBUS_TYPE_INVALID);
442         if (r < 0)
443                 return r;
444
445         if (!dbus_message_iter_init(*reply, &iter) ||
446             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
447             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
448                 log_error("Failed to parse reply.");
449                 return -EIO;
450         }
451
452         dbus_message_iter_recurse(&iter, &sub);
453
454         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
455                 if (!GREEDY_REALLOC(*unit_infos, size, *c + 1))
456                         return log_oom();
457
458                 bus_parse_unit_info(&sub, *unit_infos + *c);
459                 (*c)++;
460
461                 dbus_message_iter_next(&sub);
462         }
463
464         return 0;
465 }
466
467 static int list_units(DBusConnection *bus, char **args) {
468         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
469         _cleanup_free_ struct unit_info *unit_infos = NULL;
470         unsigned c = 0;
471         int r;
472
473         pager_open_if_enabled();
474
475         r = get_unit_list(bus, &reply, &unit_infos, &c);
476         if (r < 0)
477                 return r;
478
479         qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
480
481         output_units_list(unit_infos, c);
482
483         return 0;
484 }
485
486 static int get_triggered_units(
487                 DBusConnection *bus,
488                 const char* unit_path,
489                 char*** triggered) {
490
491         const char *interface = "org.freedesktop.systemd1.Unit",
492                    *triggers_property = "Triggers";
493         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
494         DBusMessageIter iter, sub;
495         int r;
496
497         r = bus_method_call_with_reply(bus,
498                                        "org.freedesktop.systemd1",
499                                        unit_path,
500                                        "org.freedesktop.DBus.Properties",
501                                        "Get",
502                                        &reply,
503                                        NULL,
504                                        DBUS_TYPE_STRING, &interface,
505                                        DBUS_TYPE_STRING, &triggers_property,
506                                        DBUS_TYPE_INVALID);
507         if (r < 0)
508                 return r;
509
510         if (!dbus_message_iter_init(reply, &iter) ||
511             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
512                 log_error("Failed to parse reply.");
513                 return -EBADMSG;
514         }
515
516         dbus_message_iter_recurse(&iter, &sub);
517         dbus_message_iter_recurse(&sub, &iter);
518         sub = iter;
519
520         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
521                 const char *unit;
522
523                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
524                         log_error("Failed to parse reply.");
525                         return -EBADMSG;
526                 }
527
528                 dbus_message_iter_get_basic(&sub, &unit);
529                 r = strv_extend(triggered, unit);
530                 if (r < 0)
531                         return r;
532
533                 dbus_message_iter_next(&sub);
534         }
535
536         return 0;
537 }
538
539 static int get_listening(DBusConnection *bus, const char* unit_path,
540                          char*** listen, unsigned *c)
541 {
542         const char *interface = "org.freedesktop.systemd1.Socket",
543                    *listen_property = "Listen";
544         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
545         DBusMessageIter iter, sub;
546         int r;
547
548         r = bus_method_call_with_reply(bus,
549                                        "org.freedesktop.systemd1",
550                                        unit_path,
551                                        "org.freedesktop.DBus.Properties",
552                                        "Get",
553                                        &reply,
554                                        NULL,
555                                        DBUS_TYPE_STRING, &interface,
556                                        DBUS_TYPE_STRING, &listen_property,
557                                        DBUS_TYPE_INVALID);
558         if (r < 0)
559                 return r;
560
561         if (!dbus_message_iter_init(reply, &iter) ||
562             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
563                 log_error("Failed to parse reply.");
564                 return -EBADMSG;
565         }
566
567         dbus_message_iter_recurse(&iter, &sub);
568         dbus_message_iter_recurse(&sub, &iter);
569         sub = iter;
570
571         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
572                 DBusMessageIter sub2;
573                 const char *type, *path;
574
575                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
576                         log_error("Failed to parse reply.");
577                         return -EBADMSG;
578                 }
579
580                 dbus_message_iter_recurse(&sub, &sub2);
581
582                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
583                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
584                         r = strv_extend(listen, type);
585                         if (r < 0)
586                                 return r;
587
588                         r = strv_extend(listen, path);
589                         if (r < 0)
590                                 return r;
591
592                         (*c) ++;
593                 }
594
595                 dbus_message_iter_next(&sub);
596         }
597
598         return 0;
599 }
600
601 struct socket_info {
602         const char* id;
603
604         char* type;
605         char* path;
606
607         /* Note: triggered is a list here, although it almost certainly
608          * will always be one unit. Nevertheless, dbus API allows for multiple
609          * values, so let's follow that.*/
610         char** triggered;
611
612         /* The strv above is shared. free is set only in the first one. */
613         bool own_triggered;
614 };
615
616 static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
617         int o = strcmp(a->path, b->path);
618         if (o == 0)
619                 o = strcmp(a->type, b->type);
620         return o;
621 }
622
623 static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
624         struct socket_info *s;
625         unsigned pathlen = sizeof("LISTEN") - 1,
626                 typelen = (sizeof("TYPE") - 1) * arg_show_types,
627                 socklen = sizeof("UNIT") - 1,
628                 servlen = sizeof("ACTIVATES") - 1;
629         const char *on, *off;
630
631         for (s = socket_infos; s < socket_infos + cs; s++) {
632                 char **a;
633                 unsigned tmp = 0;
634
635                 socklen = MAX(socklen, strlen(s->id));
636                 if (arg_show_types)
637                         typelen = MAX(typelen, strlen(s->type));
638                 pathlen = MAX(pathlen, strlen(s->path));
639
640                 STRV_FOREACH(a, s->triggered)
641                         tmp += strlen(*a) + 2*(a != s->triggered);
642                 servlen = MAX(servlen, tmp);
643         }
644
645         if (cs) {
646                 if (!arg_no_legend)
647                         printf("%-*s %-*.*s%-*s %s\n",
648                                pathlen, "LISTEN",
649                                typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
650                                socklen, "UNIT",
651                                "ACTIVATES");
652
653                 for (s = socket_infos; s < socket_infos + cs; s++) {
654                         char **a;
655
656                         if (arg_show_types)
657                                 printf("%-*s %-*s %-*s",
658                                        pathlen, s->path, typelen, s->type, socklen, s->id);
659                         else
660                                 printf("%-*s %-*s",
661                                        pathlen, s->path, socklen, s->id);
662                         STRV_FOREACH(a, s->triggered)
663                                 printf("%s %s",
664                                        a == s->triggered ? "" : ",", *a);
665                         printf("\n");
666                 }
667
668                 on = ansi_highlight();
669                 off = ansi_highlight_off();
670                 if (!arg_no_legend)
671                         printf("\n");
672         } else {
673                 on = ansi_highlight_red();
674                 off = ansi_highlight_off();
675         }
676
677         if (!arg_no_legend) {
678                 printf("%s%u sockets listed.%s\n", on, cs, off);
679                 if (!arg_all)
680                         printf("Pass --all to see loaded but inactive sockets, too.\n");
681         }
682
683         return 0;
684 }
685
686 static int list_sockets(DBusConnection *bus, char **args) {
687         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
688         _cleanup_free_ struct unit_info *unit_infos = NULL;
689         struct socket_info *socket_infos = NULL;
690         const struct unit_info *u;
691         struct socket_info *s;
692         unsigned cu = 0, cs = 0;
693         size_t size = 0;
694         int r;
695
696         pager_open_if_enabled();
697
698         r = get_unit_list(bus, &reply, &unit_infos, &cu);
699         if (r < 0)
700                 return r;
701
702         for (u = unit_infos; u < unit_infos + cu; u++) {
703                 const char *dot;
704                 _cleanup_strv_free_ char **listen = NULL, **triggered = NULL;
705                 unsigned c = 0, i;
706
707                 if (!output_show_unit(u))
708                         continue;
709
710                 if ((dot = strrchr(u->id, '.')) && !streq(dot+1, "socket"))
711                         continue;
712
713                 r = get_triggered_units(bus, u->unit_path, &triggered);
714                 if (r < 0)
715                         goto cleanup;
716
717                 r = get_listening(bus, u->unit_path, &listen, &c);
718                 if (r < 0)
719                         goto cleanup;
720
721                 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
722                         r = log_oom();
723                         goto cleanup;
724                 }
725
726                 for (i = 0; i < c; i++)
727                         socket_infos[cs + i] = (struct socket_info) {
728                                 .id = u->id,
729                                 .type = listen[i*2],
730                                 .path = listen[i*2 + 1],
731                                 .triggered = triggered,
732                                 .own_triggered = i==0,
733                         };
734
735                 /* from this point on we will cleanup those socket_infos */
736                 cs += c;
737                 free(listen);
738                 listen = triggered = NULL; /* avoid cleanup */
739         }
740
741         qsort_safe(socket_infos, cs, sizeof(struct socket_info),
742                    (__compar_fn_t) socket_info_compare);
743
744         output_sockets_list(socket_infos, cs);
745
746  cleanup:
747         assert(cs == 0 || socket_infos);
748         for (s = socket_infos; s < socket_infos + cs; s++) {
749                 free(s->type);
750                 free(s->path);
751                 if (s->own_triggered)
752                         strv_free(s->triggered);
753         }
754         free(socket_infos);
755
756         return r;
757 }
758
759 static int compare_unit_file_list(const void *a, const void *b) {
760         const char *d1, *d2;
761         const UnitFileList *u = a, *v = b;
762
763         d1 = strrchr(u->path, '.');
764         d2 = strrchr(v->path, '.');
765
766         if (d1 && d2) {
767                 int r;
768
769                 r = strcasecmp(d1, d2);
770                 if (r != 0)
771                         return r;
772         }
773
774         return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
775 }
776
777 static bool output_show_unit_file(const UnitFileList *u) {
778         const char *dot;
779
780         return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
781 }
782
783 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
784         unsigned max_id_len, id_cols, state_cols, n_shown = 0;
785         const UnitFileList *u;
786
787         max_id_len = sizeof("UNIT FILE")-1;
788         state_cols = sizeof("STATE")-1;
789         for (u = units; u < units + c; u++) {
790                 if (!output_show_unit_file(u))
791                         continue;
792
793                 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
794                 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
795         }
796
797         if (!arg_full) {
798                 unsigned basic_cols;
799                 id_cols = MIN(max_id_len, 25u);
800                 basic_cols = 1 + id_cols + state_cols;
801                 if (basic_cols < (unsigned) columns())
802                         id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
803         } else
804                 id_cols = max_id_len;
805
806         if (!arg_no_legend)
807                 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
808
809         for (u = units; u < units + c; u++) {
810                 _cleanup_free_ char *e = NULL;
811                 const char *on, *off;
812                 const char *id;
813
814                 if (!output_show_unit_file(u))
815                         continue;
816
817                 n_shown++;
818
819                 if (u->state == UNIT_FILE_MASKED ||
820                     u->state == UNIT_FILE_MASKED_RUNTIME ||
821                     u->state == UNIT_FILE_DISABLED ||
822                     u->state == UNIT_FILE_INVALID) {
823                         on  = ansi_highlight_red();
824                         off = ansi_highlight_off();
825                 } else if (u->state == UNIT_FILE_ENABLED) {
826                         on  = ansi_highlight_green();
827                         off = ansi_highlight_off();
828                 } else
829                         on = off = "";
830
831                 id = path_get_file_name(u->path);
832
833                 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
834
835                 printf("%-*s %s%-*s%s\n",
836                        id_cols, e ? e : id,
837                        on, state_cols, unit_file_state_to_string(u->state), off);
838         }
839
840         if (!arg_no_legend)
841                 printf("\n%u unit files listed.\n", n_shown);
842 }
843
844 static int list_unit_files(DBusConnection *bus, char **args) {
845         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
846         _cleanup_free_ UnitFileList *units = NULL;
847         DBusMessageIter iter, sub, sub2;
848         unsigned c = 0, n_units = 0;
849         int r;
850
851         pager_open_if_enabled();
852
853         if (avoid_bus()) {
854                 Hashmap *h;
855                 UnitFileList *u;
856                 Iterator i;
857
858                 h = hashmap_new(string_hash_func, string_compare_func);
859                 if (!h)
860                         return log_oom();
861
862                 r = unit_file_get_list(arg_scope, arg_root, h);
863                 if (r < 0) {
864                         unit_file_list_free(h);
865                         log_error("Failed to get unit file list: %s", strerror(-r));
866                         return r;
867                 }
868
869                 n_units = hashmap_size(h);
870                 units = new(UnitFileList, n_units);
871                 if (!units) {
872                         unit_file_list_free(h);
873                         return log_oom();
874                 }
875
876                 HASHMAP_FOREACH(u, h, i) {
877                         memcpy(units + c++, u, sizeof(UnitFileList));
878                         free(u);
879                 }
880
881                 hashmap_free(h);
882         } else {
883                 r = bus_method_call_with_reply(
884                                 bus,
885                                 "org.freedesktop.systemd1",
886                                 "/org/freedesktop/systemd1",
887                                 "org.freedesktop.systemd1.Manager",
888                                 "ListUnitFiles",
889                                 &reply,
890                                 NULL,
891                                 DBUS_TYPE_INVALID);
892                 if (r < 0)
893                         return r;
894
895                 if (!dbus_message_iter_init(reply, &iter) ||
896                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
897                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
898                         log_error("Failed to parse reply.");
899                         return -EIO;
900                 }
901
902                 dbus_message_iter_recurse(&iter, &sub);
903
904                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
905                         UnitFileList *u;
906                         const char *state;
907
908                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
909
910                         if (c >= n_units) {
911                                 UnitFileList *w;
912
913                                 n_units = MAX(2*c, 16u);
914                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
915                                 if (!w)
916                                         return log_oom();
917
918                                 units = w;
919                         }
920
921                         u = units + c;
922
923                         dbus_message_iter_recurse(&sub, &sub2);
924
925                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
926                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
927                                 log_error("Failed to parse reply.");
928                                 return -EIO;
929                         }
930
931                         u->state = unit_file_state_from_string(state);
932
933                         dbus_message_iter_next(&sub);
934                         c++;
935                 }
936         }
937
938         if (c > 0) {
939                 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
940                 output_unit_file_list(units, c);
941         }
942
943         return 0;
944 }
945
946 static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
947         int i;
948         _cleanup_free_ char *n = NULL;
949         size_t len = 0;
950         size_t max_len = MAX(columns(),20u);
951
952         if (!arg_plain) {
953                 for (i = level - 1; i >= 0; i--) {
954                         len += 2;
955                         if(len > max_len - 3 && !arg_full) {
956                                 printf("%s...\n",max_len % 2 ? "" : " ");
957                                 return 0;
958                         }
959                         printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
960                 }
961                 len += 2;
962                 if(len > max_len - 3 && !arg_full) {
963                         printf("%s...\n",max_len % 2 ? "" : " ");
964                         return 0;
965                 }
966                 printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
967         }
968
969         if(arg_full){
970                 printf("%s\n", name);
971                 return 0;
972         }
973
974         n = ellipsize(name, max_len-len, 100);
975         if(!n)
976                 return log_oom();
977
978         printf("%s\n", n);
979         return 0;
980 }
981
982 static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
983         static const char *dependencies[] = {
984                 [DEPENDENCY_FORWARD] = "Requires\0"
985                                        "RequiresOverridable\0"
986                                        "Requisite\0"
987                                        "RequisiteOverridable\0"
988                                        "Wants\0",
989                 [DEPENDENCY_REVERSE] = "RequiredBy\0"
990                                        "RequiredByOverridable\0"
991                                        "WantedBy\0"
992                                        "PartOf\0",
993                 [DEPENDENCY_AFTER]   = "After\0",
994                 [DEPENDENCY_BEFORE]  = "Before\0",
995         };
996
997         _cleanup_free_ char *path;
998         const char *interface = "org.freedesktop.systemd1.Unit";
999
1000         _cleanup_dbus_message_unref_  DBusMessage *reply = NULL;
1001         DBusMessageIter iter, sub, sub2, sub3;
1002
1003         int r = 0;
1004         char **ret = NULL;
1005
1006         assert(bus);
1007         assert(name);
1008         assert(deps);
1009
1010         path = unit_dbus_path_from_name(name);
1011         if (path == NULL) {
1012                 r = -EINVAL;
1013                 goto finish;
1014         }
1015
1016         r = bus_method_call_with_reply(
1017                 bus,
1018                 "org.freedesktop.systemd1",
1019                 path,
1020                 "org.freedesktop.DBus.Properties",
1021                 "GetAll",
1022                 &reply,
1023                 NULL,
1024                 DBUS_TYPE_STRING, &interface,
1025                 DBUS_TYPE_INVALID);
1026         if (r < 0)
1027                 goto finish;
1028
1029         if (!dbus_message_iter_init(reply, &iter) ||
1030                 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1031                 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
1032                 log_error("Failed to parse reply.");
1033                 r = -EIO;
1034                 goto finish;
1035         }
1036
1037         dbus_message_iter_recurse(&iter, &sub);
1038
1039         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1040                 const char *prop;
1041
1042                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
1043                 dbus_message_iter_recurse(&sub, &sub2);
1044
1045                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
1046                         log_error("Failed to parse reply.");
1047                         r = -EIO;
1048                         goto finish;
1049                 }
1050
1051                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
1052                         log_error("Failed to parse reply.");
1053                         r = -EIO;
1054                         goto finish;
1055                 }
1056
1057                 dbus_message_iter_recurse(&sub2, &sub3);
1058                 dbus_message_iter_next(&sub);
1059
1060                 assert(arg_dependency < ELEMENTSOF(dependencies));
1061                 if (!nulstr_contains(dependencies[arg_dependency], prop))
1062                         continue;
1063
1064                 if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
1065                         if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
1066                                 DBusMessageIter sub4;
1067                                 dbus_message_iter_recurse(&sub3, &sub4);
1068
1069                                 while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
1070                                         const char *s;
1071
1072                                         assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
1073                                         dbus_message_iter_get_basic(&sub4, &s);
1074
1075                                         r = strv_extend(&ret, s);
1076                                         if (r < 0) {
1077                                                 log_oom();
1078                                                 goto finish;
1079                                         }
1080
1081                                         dbus_message_iter_next(&sub4);
1082                                 }
1083                         }
1084                 }
1085         }
1086 finish:
1087         if (r < 0)
1088                 strv_free(ret);
1089         else
1090                 *deps = ret;
1091         return r;
1092 }
1093
1094 static int list_dependencies_compare(const void *_a, const void *_b) {
1095         const char **a = (const char**) _a, **b = (const char**) _b;
1096         if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
1097                 return 1;
1098         if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
1099                 return -1;
1100         return strcasecmp(*a, *b);
1101 }
1102
1103 static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char ***units, unsigned int branches) {
1104         _cleanup_strv_free_ char **deps = NULL, **u;
1105         char **c;
1106         int r = 0;
1107
1108         u = strv_append(*units, name);
1109         if (!u)
1110                 return log_oom();
1111
1112         r = list_dependencies_get_dependencies(bus, name, &deps);
1113         if (r < 0)
1114                 return r;
1115
1116         qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
1117
1118         STRV_FOREACH(c, deps) {
1119                 if (strv_contains(u, *c)) {
1120                         if (!arg_plain) {
1121                                 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
1122                                 if (r < 0)
1123                                         return r;
1124                         }
1125                         continue;
1126                 }
1127
1128                 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
1129                 if (r < 0)
1130                         return r;
1131
1132                 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
1133                        r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
1134                        if(r < 0)
1135                                return r;
1136                 }
1137         }
1138         if (arg_plain) {
1139                 strv_free(*units);
1140                 *units = u;
1141                 u = NULL;
1142         }
1143         return 0;
1144 }
1145
1146 static int list_dependencies(DBusConnection *bus, char **args) {
1147         _cleanup_free_ char *unit = NULL;
1148         _cleanup_strv_free_ char **units = NULL;
1149         const char *u;
1150
1151         assert(bus);
1152
1153         if (args[1]) {
1154                 unit = unit_name_mangle(args[1]);
1155                 if (!unit)
1156                         return log_oom();
1157                 u = unit;
1158         } else
1159                 u = SPECIAL_DEFAULT_TARGET;
1160
1161         pager_open_if_enabled();
1162
1163         puts(u);
1164
1165         return list_dependencies_one(bus, u, 0, &units, 0);
1166 }
1167
1168 static int get_default(DBusConnection *bus, char **args) {
1169         char *path = NULL;
1170         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1171         int r;
1172         _cleanup_dbus_error_free_ DBusError error;
1173
1174         dbus_error_init(&error);
1175
1176         if (!bus || avoid_bus()) {
1177                 r = unit_file_get_default(arg_scope, arg_root, &path);
1178
1179                 if (r < 0) {
1180                         log_error("Operation failed: %s", strerror(-r));
1181                         goto finish;
1182                 }
1183
1184                 r = 0;
1185         } else {
1186                 r = bus_method_call_with_reply(
1187                         bus,
1188                         "org.freedesktop.systemd1",
1189                         "/org/freedesktop/systemd1",
1190                         "org.freedesktop.systemd1.Manager",
1191                         "GetDefaultTarget",
1192                         &reply,
1193                         NULL,
1194                         DBUS_TYPE_INVALID);
1195
1196                 if (r < 0) {
1197                         log_error("Operation failed: %s", strerror(-r));
1198                         goto finish;
1199                 }
1200
1201                 if (!dbus_message_get_args(reply, &error,
1202                                    DBUS_TYPE_STRING, &path,
1203                                    DBUS_TYPE_INVALID)) {
1204                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1205                         dbus_error_free(&error);
1206                         return  -EIO;
1207                 }
1208         }
1209
1210         if (path)
1211                 printf("%s\n", path);
1212
1213 finish:
1214         if ((!bus || avoid_bus()) && path)
1215                 free(path);
1216
1217         return r;
1218
1219 }
1220
1221 struct job_info {
1222         uint32_t id;
1223         char *name, *type, *state;
1224 };
1225
1226 static void list_jobs_print(struct job_info* jobs, size_t n) {
1227         size_t i;
1228         struct job_info *j;
1229         const char *on, *off;
1230         bool shorten = false;
1231
1232         assert(n == 0 || jobs);
1233
1234         if (n == 0) {
1235                 on = ansi_highlight_green();
1236                 off = ansi_highlight_off();
1237
1238                 printf("%sNo jobs running.%s\n", on, off);
1239                 return;
1240         }
1241
1242         pager_open_if_enabled();
1243
1244         {
1245                 /* JOB UNIT TYPE STATE */
1246                 unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5;
1247
1248                 for (i = 0, j = jobs; i < n; i++, j++) {
1249                         assert(j->name && j->type && j->state);
1250                         l0 = MAX(l0, DECIMAL_STR_WIDTH(j->id));
1251                         l1 = MAX(l1, strlen(j->name));
1252                         l2 = MAX(l2, strlen(j->type));
1253                         l3 = MAX(l3, strlen(j->state));
1254                 }
1255
1256                 if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) {
1257                         l1 = MAX(33u, columns() - l0 - l2 - l3 - 3);
1258                         shorten = true;
1259                 }
1260
1261                 if (on_tty())
1262                         printf("%*s %-*s %-*s %-*s\n",
1263                                l0, "JOB",
1264                                l1, "UNIT",
1265                                l2, "TYPE",
1266                                l3, "STATE");
1267
1268                 for (i = 0, j = jobs; i < n; i++, j++) {
1269                         _cleanup_free_ char *e = NULL;
1270
1271                         if (streq(j->state, "running")) {
1272                                 on = ansi_highlight();
1273                                 off = ansi_highlight_off();
1274                         } else
1275                                 on = off = "";
1276
1277                         e = shorten ? ellipsize(j->name, l1, 33) : NULL;
1278                         printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
1279                                l0, j->id,
1280                                on, l1, e ? e : j->name, off,
1281                                l2, j->type,
1282                                on, l3, j->state, off);
1283                 }
1284         }
1285
1286         on = ansi_highlight();
1287         off = ansi_highlight_off();
1288
1289         if (on_tty())
1290                 printf("\n%s%zu jobs listed%s.\n", on, n, off);
1291 }
1292
1293 static int list_jobs(DBusConnection *bus, char **args) {
1294         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1295         DBusMessageIter iter, sub, sub2;
1296         int r;
1297         struct job_info *jobs = NULL;
1298         size_t size = 0, used = 0;
1299
1300         r = bus_method_call_with_reply(
1301                         bus,
1302                         "org.freedesktop.systemd1",
1303                         "/org/freedesktop/systemd1",
1304                         "org.freedesktop.systemd1.Manager",
1305                         "ListJobs",
1306                         &reply,
1307                         NULL,
1308                         DBUS_TYPE_INVALID);
1309         if (r < 0)
1310                 return r;
1311
1312         if (!dbus_message_iter_init(reply, &iter) ||
1313             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1314             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
1315                 log_error("Failed to parse reply.");
1316                 return -EIO;
1317         }
1318
1319         dbus_message_iter_recurse(&iter, &sub);
1320
1321         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1322                 const char *name, *type, *state, *job_path, *unit_path;
1323                 uint32_t id;
1324
1325                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1326                         log_error("Failed to parse reply.");
1327                         return -EIO;
1328                 }
1329
1330                 dbus_message_iter_recurse(&sub, &sub2);
1331
1332                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1333                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1334                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1335                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1336                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1337                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1338                         log_error("Failed to parse reply.");
1339                         r = -EIO;
1340                         goto finish;
1341                 }
1342
1343                 if (!GREEDY_REALLOC(jobs, size, used + 1)) {
1344                         r = log_oom();
1345                         goto finish;
1346                 }
1347
1348                 jobs[used++] = (struct job_info) { id,
1349                                                    strdup(name),
1350                                                    strdup(type),
1351                                                    strdup(state) };
1352                 if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) {
1353                         r = log_oom();
1354                         goto finish;
1355                 }
1356
1357                 dbus_message_iter_next(&sub);
1358         }
1359
1360         list_jobs_print(jobs, used);
1361
1362  finish:
1363         while (used--) {
1364                 free(jobs[used].name);
1365                 free(jobs[used].type);
1366                 free(jobs[used].state);
1367         }
1368         free(jobs);
1369
1370         return 0;
1371 }
1372
1373 static int cancel_job(DBusConnection *bus, char **args) {
1374         char **name;
1375
1376         assert(args);
1377
1378         if (strv_length(args) <= 1)
1379                 return daemon_reload(bus, args);
1380
1381         STRV_FOREACH(name, args+1) {
1382                 uint32_t id;
1383                 int r;
1384
1385                 r = safe_atou32(*name, &id);
1386                 if (r < 0) {
1387                         log_error("Failed to parse job id: %s", strerror(-r));
1388                         return r;
1389                 }
1390
1391                 r = bus_method_call_with_reply(
1392                                 bus,
1393                                 "org.freedesktop.systemd1",
1394                                 "/org/freedesktop/systemd1",
1395                                 "org.freedesktop.systemd1.Manager",
1396                                 "CancelJob",
1397                                 NULL,
1398                                 NULL,
1399                                 DBUS_TYPE_UINT32, &id,
1400                                 DBUS_TYPE_INVALID);
1401                 if (r < 0)
1402                         return r;
1403         }
1404
1405         return 0;
1406 }
1407
1408 static int need_daemon_reload(DBusConnection *bus, const char *unit) {
1409         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1410         _cleanup_dbus_error_free_ DBusError error;
1411         dbus_bool_t b = FALSE;
1412         DBusMessageIter iter, sub;
1413         const char
1414                 *interface = "org.freedesktop.systemd1.Unit",
1415                 *property = "NeedDaemonReload",
1416                 *path;
1417         _cleanup_free_ char *n = NULL;
1418         int r;
1419
1420         dbus_error_init(&error);
1421
1422         /* We ignore all errors here, since this is used to show a warning only */
1423
1424         n = unit_name_mangle(unit);
1425         if (!n)
1426                 return log_oom();
1427
1428         r = bus_method_call_with_reply(
1429                         bus,
1430                         "org.freedesktop.systemd1",
1431                         "/org/freedesktop/systemd1",
1432                         "org.freedesktop.systemd1.Manager",
1433                         "GetUnit",
1434                         &reply,
1435                         &error,
1436                         DBUS_TYPE_STRING, &n,
1437                         DBUS_TYPE_INVALID);
1438         if (r < 0)
1439                 return r;
1440
1441         if (!dbus_message_get_args(reply, NULL,
1442                                    DBUS_TYPE_OBJECT_PATH, &path,
1443                                    DBUS_TYPE_INVALID))
1444                 return -EIO;
1445
1446         dbus_message_unref(reply);
1447         reply = NULL;
1448
1449         r = bus_method_call_with_reply(
1450                         bus,
1451                         "org.freedesktop.systemd1",
1452                         path,
1453                         "org.freedesktop.DBus.Properties",
1454                         "Get",
1455                         &reply,
1456                         &error,
1457                         DBUS_TYPE_STRING, &interface,
1458                         DBUS_TYPE_STRING, &property,
1459                         DBUS_TYPE_INVALID);
1460         if (r < 0)
1461                 return r;
1462
1463         if (!dbus_message_iter_init(reply, &iter) ||
1464             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1465                 return -EIO;
1466
1467         dbus_message_iter_recurse(&iter, &sub);
1468         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1469                 return -EIO;
1470
1471         dbus_message_iter_get_basic(&sub, &b);
1472         return b;
1473 }
1474
1475 typedef struct WaitData {
1476         Set *set;
1477
1478         char *name;
1479         char *result;
1480 } WaitData;
1481
1482 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1483         _cleanup_dbus_error_free_ DBusError error;
1484         WaitData *d = data;
1485
1486         dbus_error_init(&error);
1487
1488         assert(connection);
1489         assert(message);
1490         assert(d);
1491
1492         log_debug("Got D-Bus request: %s.%s() on %s",
1493                   dbus_message_get_interface(message),
1494                   dbus_message_get_member(message),
1495                   dbus_message_get_path(message));
1496
1497         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1498                 log_error("Warning! D-Bus connection terminated.");
1499                 dbus_connection_close(connection);
1500
1501         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1502                 uint32_t id;
1503                 const char *path, *result, *unit;
1504                 char *r;
1505
1506                 if (dbus_message_get_args(message, &error,
1507                                           DBUS_TYPE_UINT32, &id,
1508                                           DBUS_TYPE_OBJECT_PATH, &path,
1509                                           DBUS_TYPE_STRING, &unit,
1510                                           DBUS_TYPE_STRING, &result,
1511                                           DBUS_TYPE_INVALID)) {
1512
1513                         r = set_remove(d->set, (char*) path);
1514                         if (!r)
1515                                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1516
1517                         free(r);
1518
1519                         if (!isempty(result))
1520                                 d->result = strdup(result);
1521
1522                         if (!isempty(unit))
1523                                 d->name = strdup(unit);
1524
1525                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1526                 }
1527 #ifndef NOLEGACY
1528                 dbus_error_free(&error);
1529                 if (dbus_message_get_args(message, &error,
1530                                           DBUS_TYPE_UINT32, &id,
1531                                           DBUS_TYPE_OBJECT_PATH, &path,
1532                                           DBUS_TYPE_STRING, &result,
1533                                           DBUS_TYPE_INVALID)) {
1534                         /* Compatibility with older systemd versions <
1535                          * 183 during upgrades. This should be dropped
1536                          * one day. */
1537                         r = set_remove(d->set, (char*) path);
1538                         if (!r)
1539                                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1540
1541                         free(r);
1542
1543                         if (*result)
1544                                 d->result = strdup(result);
1545
1546                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1547                 }
1548 #endif
1549
1550                 log_error("Failed to parse message: %s", bus_error_message(&error));
1551         }
1552
1553         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1554 }
1555
1556 static int enable_wait_for_jobs(DBusConnection *bus) {
1557         DBusError error;
1558
1559         assert(bus);
1560
1561         if (private_bus)
1562                 return 0;
1563
1564         dbus_error_init(&error);
1565         dbus_bus_add_match(bus,
1566                            "type='signal',"
1567                            "sender='org.freedesktop.systemd1',"
1568                            "interface='org.freedesktop.systemd1.Manager',"
1569                            "member='JobRemoved',"
1570                            "path='/org/freedesktop/systemd1'",
1571                            &error);
1572
1573         if (dbus_error_is_set(&error)) {
1574                 log_error("Failed to add match: %s", bus_error_message(&error));
1575                 dbus_error_free(&error);
1576                 return -EIO;
1577         }
1578
1579         /* This is slightly dirty, since we don't undo the match registrations. */
1580         return 0;
1581 }
1582
1583 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1584         int r = 0;
1585         WaitData d = { .set = s };
1586
1587         assert(bus);
1588         assert(s);
1589
1590         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1591                 return log_oom();
1592
1593         while (!set_isempty(s)) {
1594
1595                 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1596                         log_error("Disconnected from bus.");
1597                         return -ECONNREFUSED;
1598                 }
1599
1600                 if (!d.result)
1601                         goto free_name;
1602
1603                 if (!arg_quiet) {
1604                         if (streq(d.result, "timeout"))
1605                                 log_error("Job for %s timed out.", strna(d.name));
1606                         else if (streq(d.result, "canceled"))
1607                                 log_error("Job for %s canceled.", strna(d.name));
1608                         else if (streq(d.result, "dependency"))
1609                                 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1610                         else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1611                                 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1612                 }
1613
1614                 if (streq_ptr(d.result, "timeout"))
1615                         r = -ETIME;
1616                 else if (streq_ptr(d.result, "canceled"))
1617                         r = -ECANCELED;
1618                 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1619                         r = -EIO;
1620
1621                 free(d.result);
1622                 d.result = NULL;
1623
1624         free_name:
1625                 free(d.name);
1626                 d.name = NULL;
1627         }
1628
1629         dbus_connection_remove_filter(bus, wait_filter, &d);
1630         return r;
1631 }
1632
1633 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1634         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1635         _cleanup_free_ char *n = NULL;
1636         DBusMessageIter iter, sub;
1637         const char
1638                 *interface = "org.freedesktop.systemd1.Unit",
1639                 *property = "ActiveState";
1640         const char *state, *path;
1641         DBusError error;
1642         int r;
1643
1644         assert(name);
1645
1646         dbus_error_init(&error);
1647
1648         n = unit_name_mangle(name);
1649         if (!n)
1650                 return log_oom();
1651
1652         r = bus_method_call_with_reply (
1653                         bus,
1654                         "org.freedesktop.systemd1",
1655                         "/org/freedesktop/systemd1",
1656                         "org.freedesktop.systemd1.Manager",
1657                         "GetUnit",
1658                         &reply,
1659                         &error,
1660                         DBUS_TYPE_STRING, &n,
1661                         DBUS_TYPE_INVALID);
1662         if (r < 0) {
1663                 dbus_error_free(&error);
1664
1665                 if (!quiet)
1666                         puts("unknown");
1667                 return 0;
1668         }
1669
1670         if (!dbus_message_get_args(reply, NULL,
1671                                    DBUS_TYPE_OBJECT_PATH, &path,
1672                                    DBUS_TYPE_INVALID)) {
1673                 log_error("Failed to parse reply.");
1674                 return -EIO;
1675         }
1676
1677         dbus_message_unref(reply);
1678         reply = NULL;
1679
1680         r = bus_method_call_with_reply(
1681                         bus,
1682                         "org.freedesktop.systemd1",
1683                         path,
1684                         "org.freedesktop.DBus.Properties",
1685                         "Get",
1686                         &reply,
1687                         NULL,
1688                         DBUS_TYPE_STRING, &interface,
1689                         DBUS_TYPE_STRING, &property,
1690                         DBUS_TYPE_INVALID);
1691         if (r < 0) {
1692                 if (!quiet)
1693                         puts("unknown");
1694                 return 0;
1695         }
1696
1697         if (!dbus_message_iter_init(reply, &iter) ||
1698             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1699                 log_error("Failed to parse reply.");
1700                 return r;
1701         }
1702
1703         dbus_message_iter_recurse(&iter, &sub);
1704
1705         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1706                 log_error("Failed to parse reply.");
1707                 return r;
1708         }
1709
1710         dbus_message_iter_get_basic(&sub, &state);
1711
1712         if (!quiet)
1713                 puts(state);
1714
1715         return strv_find(check_states, state) ? 1 : 0;
1716 }
1717
1718 static void check_triggering_units(
1719                 DBusConnection *bus,
1720                 const char *unit_name) {
1721
1722         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1723         DBusMessageIter iter, sub;
1724         const char *interface = "org.freedesktop.systemd1.Unit",
1725                    *load_state_property = "LoadState",
1726                    *triggered_by_property = "TriggeredBy",
1727                    *state;
1728         _cleanup_free_ char *unit_path = NULL, *n = NULL;
1729         bool print_warning_label = true;
1730         int r;
1731
1732         n = unit_name_mangle(unit_name);
1733         if (!n) {
1734                 log_oom();
1735                 return;
1736         }
1737
1738         unit_path = unit_dbus_path_from_name(n);
1739         if (!unit_path) {
1740                 log_oom();
1741                 return;
1742         }
1743
1744         r = bus_method_call_with_reply(
1745                         bus,
1746                         "org.freedesktop.systemd1",
1747                         unit_path,
1748                         "org.freedesktop.DBus.Properties",
1749                         "Get",
1750                         &reply,
1751                         NULL,
1752                         DBUS_TYPE_STRING, &interface,
1753                         DBUS_TYPE_STRING, &load_state_property,
1754                         DBUS_TYPE_INVALID);
1755         if (r < 0)
1756                 return;
1757
1758         if (!dbus_message_iter_init(reply, &iter) ||
1759             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1760                 log_error("Failed to parse reply.");
1761                 return;
1762         }
1763
1764         dbus_message_iter_recurse(&iter, &sub);
1765
1766         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1767             log_error("Failed to parse reply.");
1768             return;
1769         }
1770
1771         dbus_message_iter_get_basic(&sub, &state);
1772
1773         if (streq(state, "masked"))
1774             return;
1775
1776         dbus_message_unref(reply);
1777         reply = NULL;
1778
1779         r = bus_method_call_with_reply(
1780                         bus,
1781                         "org.freedesktop.systemd1",
1782                         unit_path,
1783                         "org.freedesktop.DBus.Properties",
1784                         "Get",
1785                         &reply,
1786                         NULL,
1787                         DBUS_TYPE_STRING, &interface,
1788                         DBUS_TYPE_STRING, &triggered_by_property,
1789                         DBUS_TYPE_INVALID);
1790         if (r < 0)
1791                 return;
1792
1793         if (!dbus_message_iter_init(reply, &iter) ||
1794             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1795                 log_error("Failed to parse reply.");
1796                 return;
1797         }
1798
1799         dbus_message_iter_recurse(&iter, &sub);
1800         dbus_message_iter_recurse(&sub, &iter);
1801         sub = iter;
1802
1803         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1804                 const char * const check_states[] = {
1805                         "active",
1806                         "reloading",
1807                         NULL
1808                 };
1809                 const char *service_trigger;
1810
1811                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1812                         log_error("Failed to parse reply.");
1813                         return;
1814                 }
1815
1816                 dbus_message_iter_get_basic(&sub, &service_trigger);
1817
1818                 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1819                 if (r < 0)
1820                         return;
1821                 if (r > 0) {
1822                         if (print_warning_label) {
1823                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1824                                 print_warning_label = false;
1825                         }
1826
1827                         log_warning("  %s", service_trigger);
1828                 }
1829
1830                 dbus_message_iter_next(&sub);
1831         }
1832 }
1833
1834 static int start_unit_one(
1835                 DBusConnection *bus,
1836                 const char *method,
1837                 const char *name,
1838                 const char *mode,
1839                 DBusError *error,
1840                 Set *s) {
1841
1842         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1843         _cleanup_free_ char *n;
1844         const char *path;
1845         int r;
1846
1847         assert(method);
1848         assert(name);
1849         assert(mode);
1850         assert(error);
1851
1852         n = unit_name_mangle(name);
1853         if (!n)
1854                 return log_oom();
1855
1856         r = bus_method_call_with_reply(
1857                         bus,
1858                         "org.freedesktop.systemd1",
1859                         "/org/freedesktop/systemd1",
1860                         "org.freedesktop.systemd1.Manager",
1861                         method,
1862                         &reply,
1863                         error,
1864                         DBUS_TYPE_STRING, &n,
1865                         DBUS_TYPE_STRING, &mode,
1866                         DBUS_TYPE_INVALID);
1867         if (r) {
1868                 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1869                         /* There's always a fallback possible for
1870                          * legacy actions. */
1871                         r = -EADDRNOTAVAIL;
1872                 else
1873                         log_error("Failed to issue method call: %s", bus_error_message(error));
1874
1875                 return r;
1876         }
1877
1878         if (!dbus_message_get_args(reply, error,
1879                                    DBUS_TYPE_OBJECT_PATH, &path,
1880                                    DBUS_TYPE_INVALID)) {
1881                 log_error("Failed to parse reply: %s", bus_error_message(error));
1882                 return -EIO;
1883         }
1884
1885         if (need_daemon_reload(bus, n) > 0)
1886                 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %sdaemon-reload' recommended.",
1887                             n, arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
1888
1889         if (s) {
1890                 char *p;
1891
1892                 p = strdup(path);
1893                 if (!p)
1894                         return log_oom();
1895
1896                 r = set_consume(s, p);
1897                 if (r < 0) {
1898                         log_error("Failed to add path to set.");
1899                         return r;
1900                 }
1901         }
1902
1903         return 0;
1904 }
1905
1906 static const struct {
1907         const char *target;
1908         const char *verb;
1909         const char *mode;
1910 } action_table[_ACTION_MAX] = {
1911         [ACTION_HALT]         = { SPECIAL_HALT_TARGET,         "halt",         "replace-irreversibly" },
1912         [ACTION_POWEROFF]     = { SPECIAL_POWEROFF_TARGET,     "poweroff",     "replace-irreversibly" },
1913         [ACTION_REBOOT]       = { SPECIAL_REBOOT_TARGET,       "reboot",       "replace-irreversibly" },
1914         [ACTION_KEXEC]        = { SPECIAL_KEXEC_TARGET,        "kexec",        "replace-irreversibly" },
1915         [ACTION_RUNLEVEL2]    = { SPECIAL_RUNLEVEL2_TARGET,    NULL,           "isolate" },
1916         [ACTION_RUNLEVEL3]    = { SPECIAL_RUNLEVEL3_TARGET,    NULL,           "isolate" },
1917         [ACTION_RUNLEVEL4]    = { SPECIAL_RUNLEVEL4_TARGET,    NULL,           "isolate" },
1918         [ACTION_RUNLEVEL5]    = { SPECIAL_RUNLEVEL5_TARGET,    NULL,           "isolate" },
1919         [ACTION_RESCUE]       = { SPECIAL_RESCUE_TARGET,       "rescue",       "isolate" },
1920         [ACTION_EMERGENCY]    = { SPECIAL_EMERGENCY_TARGET,    "emergency",    "isolate" },
1921         [ACTION_DEFAULT]      = { SPECIAL_DEFAULT_TARGET,      "default",      "isolate" },
1922         [ACTION_EXIT]         = { SPECIAL_EXIT_TARGET,         "exit",         "replace-irreversibly" },
1923         [ACTION_SUSPEND]      = { SPECIAL_SUSPEND_TARGET,      "suspend",      "replace-irreversibly" },
1924         [ACTION_HIBERNATE]    = { SPECIAL_HIBERNATE_TARGET,    "hibernate",    "replace-irreversibly" },
1925         [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1926 };
1927
1928 static enum action verb_to_action(const char *verb) {
1929         enum action i;
1930
1931         for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1932                 if (action_table[i].verb && streq(verb, action_table[i].verb))
1933                         return i;
1934         return ACTION_INVALID;
1935 }
1936
1937 static int start_unit(DBusConnection *bus, char **args) {
1938
1939         int r, ret = 0;
1940         const char *method, *mode, *one_name;
1941         _cleanup_set_free_free_ Set *s = NULL;
1942         _cleanup_dbus_error_free_ DBusError error;
1943         char **name;
1944
1945         dbus_error_init(&error);
1946
1947         assert(bus);
1948
1949         ask_password_agent_open_if_enabled();
1950
1951         if (arg_action == ACTION_SYSTEMCTL) {
1952                 enum action action;
1953                 method =
1954                         streq(args[0], "stop") ||
1955                         streq(args[0], "condstop")              ? "StopUnit" :
1956                         streq(args[0], "reload")                ? "ReloadUnit" :
1957                         streq(args[0], "restart")               ? "RestartUnit" :
1958
1959                         streq(args[0], "try-restart")           ||
1960                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1961
1962                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1963
1964                         streq(args[0], "reload-or-try-restart") ||
1965                         streq(args[0], "condreload") ||
1966
1967                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1968                                                                   "StartUnit";
1969                 action = verb_to_action(args[0]);
1970
1971                 mode = streq(args[0], "isolate") ? "isolate" :
1972                        action_table[action].mode ?: arg_job_mode;
1973
1974                 one_name = action_table[action].target;
1975
1976         } else {
1977                 assert(arg_action < ELEMENTSOF(action_table));
1978                 assert(action_table[arg_action].target);
1979
1980                 method = "StartUnit";
1981
1982                 mode = action_table[arg_action].mode;
1983                 one_name = action_table[arg_action].target;
1984         }
1985
1986         if (!arg_no_block) {
1987                 ret = enable_wait_for_jobs(bus);
1988                 if (ret < 0) {
1989                         log_error("Could not watch jobs: %s", strerror(-ret));
1990                         return ret;
1991                 }
1992
1993                 s = set_new(string_hash_func, string_compare_func);
1994                 if (!s)
1995                         return log_oom();
1996         }
1997
1998         if (one_name) {
1999                 ret = start_unit_one(bus, method, one_name, mode, &error, s);
2000                 if (ret < 0)
2001                         ret = translate_bus_error_to_exit_status(ret, &error);
2002         } else {
2003                 STRV_FOREACH(name, args+1) {
2004                         r = start_unit_one(bus, method, *name, mode, &error, s);
2005                         if (r < 0) {
2006                                 ret = translate_bus_error_to_exit_status(r, &error);
2007                                 dbus_error_free(&error);
2008                         }
2009                 }
2010         }
2011
2012         if (!arg_no_block) {
2013                 r = wait_for_jobs(bus, s);
2014                 if (r < 0)
2015                         return r;
2016
2017                 /* When stopping units, warn if they can still be triggered by
2018                  * another active unit (socket, path, timer) */
2019                 if (!arg_quiet && streq(method, "StopUnit")) {
2020                         if (one_name)
2021                                 check_triggering_units(bus, one_name);
2022                         else
2023                                 STRV_FOREACH(name, args+1)
2024                                         check_triggering_units(bus, *name);
2025                 }
2026         }
2027
2028         return ret;
2029 }
2030
2031 /* Ask systemd-logind, which might grant access to unprivileged users
2032  * through PolicyKit */
2033 static int reboot_with_logind(DBusConnection *bus, enum action a) {
2034 #ifdef HAVE_LOGIND
2035         const char *method;
2036         dbus_bool_t interactive = true;
2037
2038         if (!bus)
2039                 return -EIO;
2040
2041         polkit_agent_open_if_enabled();
2042
2043         switch (a) {
2044
2045         case ACTION_REBOOT:
2046                 method = "Reboot";
2047                 break;
2048
2049         case ACTION_POWEROFF:
2050                 method = "PowerOff";
2051                 break;
2052
2053         case ACTION_SUSPEND:
2054                 method = "Suspend";
2055                 break;
2056
2057         case ACTION_HIBERNATE:
2058                 method = "Hibernate";
2059                 break;
2060
2061         case ACTION_HYBRID_SLEEP:
2062                 method = "HybridSleep";
2063                 break;
2064
2065         default:
2066                 return -EINVAL;
2067         }
2068
2069         return bus_method_call_with_reply(
2070                         bus,
2071                         "org.freedesktop.login1",
2072                         "/org/freedesktop/login1",
2073                         "org.freedesktop.login1.Manager",
2074                         method,
2075                         NULL,
2076                         NULL,
2077                         DBUS_TYPE_BOOLEAN, &interactive,
2078                         DBUS_TYPE_INVALID);
2079 #else
2080         return -ENOSYS;
2081 #endif
2082 }
2083
2084 static int check_inhibitors(DBusConnection *bus, enum action a) {
2085 #ifdef HAVE_LOGIND
2086         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2087         DBusMessageIter iter, sub, sub2;
2088         int r;
2089         unsigned c = 0;
2090         _cleanup_strv_free_ char **sessions = NULL;
2091         char **s;
2092
2093         if (!bus)
2094                 return 0;
2095
2096         if (arg_ignore_inhibitors || arg_force > 0)
2097                 return 0;
2098
2099         if (arg_when > 0)
2100                 return 0;
2101
2102         if (geteuid() == 0)
2103                 return 0;
2104
2105         if (!on_tty())
2106                 return 0;
2107
2108         r = bus_method_call_with_reply(
2109                         bus,
2110                         "org.freedesktop.login1",
2111                         "/org/freedesktop/login1",
2112                         "org.freedesktop.login1.Manager",
2113                         "ListInhibitors",
2114                         &reply,
2115                         NULL,
2116                         DBUS_TYPE_INVALID);
2117         if (r < 0)
2118                 /* If logind is not around, then there are no inhibitors... */
2119                 return 0;
2120
2121         if (!dbus_message_iter_init(reply, &iter) ||
2122             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2123             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
2124                 log_error("Failed to parse reply.");
2125                 return -EIO;
2126         }
2127
2128         dbus_message_iter_recurse(&iter, &sub);
2129         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2130                 const char *what, *who, *why, *mode;
2131                 uint32_t uid, pid;
2132                 _cleanup_strv_free_ char **sv = NULL;
2133                 _cleanup_free_ char *comm = NULL, *user = NULL;
2134
2135                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
2136                         log_error("Failed to parse reply.");
2137                         return -EIO;
2138                 }
2139
2140                 dbus_message_iter_recurse(&sub, &sub2);
2141
2142                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
2143                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
2144                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
2145                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
2146                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
2147                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
2148                         log_error("Failed to parse reply.");
2149                         return -EIO;
2150                 }
2151
2152                 if (!streq(mode, "block"))
2153                         goto next;
2154
2155                 sv = strv_split(what, ":");
2156                 if (!sv)
2157                         return log_oom();
2158
2159                 if (!strv_contains(sv,
2160                                   a == ACTION_HALT ||
2161                                   a == ACTION_POWEROFF ||
2162                                   a == ACTION_REBOOT ||
2163                                   a == ACTION_KEXEC ? "shutdown" : "sleep"))
2164                         goto next;
2165
2166                 get_process_comm(pid, &comm);
2167                 user = uid_to_name(uid);
2168                 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
2169                             who, (unsigned long) pid, strna(comm), strna(user), why);
2170                 c++;
2171
2172         next:
2173                 dbus_message_iter_next(&sub);
2174         }
2175
2176         dbus_message_iter_recurse(&iter, &sub);
2177
2178         /* Check for current sessions */
2179         sd_get_sessions(&sessions);
2180         STRV_FOREACH(s, sessions) {
2181                 uid_t uid;
2182                 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2183
2184                 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2185                         continue;
2186
2187                 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2188                         continue;
2189
2190                 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2191                         continue;
2192
2193                 sd_session_get_tty(*s, &tty);
2194                 sd_session_get_seat(*s, &seat);
2195                 sd_session_get_service(*s, &service);
2196                 user = uid_to_name(uid);
2197
2198                 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2199                 c++;
2200         }
2201
2202         if (c <= 0)
2203                 return 0;
2204
2205         log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
2206                   action_table[a].verb);
2207
2208         return -EPERM;
2209 #else
2210         return 0;
2211 #endif
2212 }
2213
2214 static int start_special(DBusConnection *bus, char **args) {
2215         enum action a;
2216         int r;
2217
2218         assert(args);
2219
2220         a = verb_to_action(args[0]);
2221
2222         r = check_inhibitors(bus, a);
2223         if (r < 0)
2224                 return r;
2225
2226         if (arg_force >= 2 && geteuid() != 0) {
2227                 log_error("Must be root.");
2228                 return -EPERM;
2229         }
2230
2231         if (arg_force >= 2 &&
2232             (a == ACTION_HALT ||
2233              a == ACTION_POWEROFF ||
2234              a == ACTION_REBOOT))
2235                 halt_now(a);
2236
2237         if (arg_force >= 1 &&
2238             (a == ACTION_HALT ||
2239              a == ACTION_POWEROFF ||
2240              a == ACTION_REBOOT ||
2241              a == ACTION_KEXEC ||
2242              a == ACTION_EXIT))
2243                 return daemon_reload(bus, args);
2244
2245         /* first try logind, to allow authentication with polkit */
2246         if (geteuid() != 0 &&
2247             (a == ACTION_POWEROFF ||
2248              a == ACTION_REBOOT ||
2249              a == ACTION_SUSPEND ||
2250              a == ACTION_HIBERNATE ||
2251              a == ACTION_HYBRID_SLEEP)) {
2252                 r = reboot_with_logind(bus, a);
2253                 if (r >= 0)
2254                         return r;
2255         }
2256
2257         r = start_unit(bus, args);
2258         if (r == EXIT_SUCCESS)
2259                 warn_wall(a);
2260
2261         return r;
2262 }
2263
2264 static int check_unit_active(DBusConnection *bus, char **args) {
2265         const char * const check_states[] = {
2266                 "active",
2267                 "reloading",
2268                 NULL
2269         };
2270
2271         char **name;
2272         int r = 3; /* According to LSB: "program is not running" */
2273
2274         assert(bus);
2275         assert(args);
2276
2277         STRV_FOREACH(name, args+1) {
2278                 int state;
2279
2280                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2281                 if (state < 0)
2282                         return state;
2283                 if (state > 0)
2284                         r = 0;
2285         }
2286
2287         return r;
2288 }
2289
2290 static int check_unit_failed(DBusConnection *bus, char **args) {
2291         const char * const check_states[] = {
2292                 "failed",
2293                 NULL
2294         };
2295
2296         char **name;
2297         int r = 1;
2298
2299         assert(bus);
2300         assert(args);
2301
2302         STRV_FOREACH(name, args+1) {
2303                 int state;
2304
2305                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2306                 if (state < 0)
2307                         return state;
2308                 if (state > 0)
2309                         r = 0;
2310         }
2311
2312         return r;
2313 }
2314
2315 static int kill_unit(DBusConnection *bus, char **args) {
2316         char **name;
2317         int r = 0;
2318
2319         assert(bus);
2320         assert(args);
2321
2322         if (!arg_kill_who)
2323                 arg_kill_who = "all";
2324
2325         STRV_FOREACH(name, args+1) {
2326                 _cleanup_free_ char *n = NULL;
2327
2328                 n = unit_name_mangle(*name);
2329                 if (!n)
2330                         return log_oom();
2331
2332                 r = bus_method_call_with_reply(
2333                                 bus,
2334                                 "org.freedesktop.systemd1",
2335                                 "/org/freedesktop/systemd1",
2336                                 "org.freedesktop.systemd1.Manager",
2337                                 "KillUnit",
2338                                 NULL,
2339                                 NULL,
2340                                 DBUS_TYPE_STRING, &n,
2341                                 DBUS_TYPE_STRING, &arg_kill_who,
2342                                 DBUS_TYPE_INT32, &arg_signal,
2343                                 DBUS_TYPE_INVALID);
2344                 if (r < 0)
2345                         return r;
2346         }
2347         return 0;
2348 }
2349
2350 typedef struct ExecStatusInfo {
2351         char *name;
2352
2353         char *path;
2354         char **argv;
2355
2356         bool ignore;
2357
2358         usec_t start_timestamp;
2359         usec_t exit_timestamp;
2360         pid_t pid;
2361         int code;
2362         int status;
2363
2364         LIST_FIELDS(struct ExecStatusInfo, exec);
2365 } ExecStatusInfo;
2366
2367 static void exec_status_info_free(ExecStatusInfo *i) {
2368         assert(i);
2369
2370         free(i->name);
2371         free(i->path);
2372         strv_free(i->argv);
2373         free(i);
2374 }
2375
2376 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2377         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2378         DBusMessageIter sub2, sub3;
2379         const char*path;
2380         unsigned n;
2381         uint32_t pid;
2382         int32_t code, status;
2383         dbus_bool_t ignore;
2384
2385         assert(i);
2386         assert(i);
2387
2388         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2389                 return -EIO;
2390
2391         dbus_message_iter_recurse(sub, &sub2);
2392
2393         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2394                 return -EIO;
2395
2396         i->path = strdup(path);
2397         if (!i->path)
2398                 return -ENOMEM;
2399
2400         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2401             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2402                 return -EIO;
2403
2404         n = 0;
2405         dbus_message_iter_recurse(&sub2, &sub3);
2406         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2407                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2408                 dbus_message_iter_next(&sub3);
2409                 n++;
2410         }
2411
2412         i->argv = new0(char*, n+1);
2413         if (!i->argv)
2414                 return -ENOMEM;
2415
2416         n = 0;
2417         dbus_message_iter_recurse(&sub2, &sub3);
2418         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2419                 const char *s;
2420
2421                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2422                 dbus_message_iter_get_basic(&sub3, &s);
2423                 dbus_message_iter_next(&sub3);
2424
2425                 i->argv[n] = strdup(s);
2426                 if (!i->argv[n])
2427                         return -ENOMEM;
2428
2429                 n++;
2430         }
2431
2432         if (!dbus_message_iter_next(&sub2) ||
2433             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2434             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2435             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2436             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2437             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2438             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2439             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2440             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2441                 return -EIO;
2442
2443         i->ignore = ignore;
2444         i->start_timestamp = (usec_t) start_timestamp;
2445         i->exit_timestamp = (usec_t) exit_timestamp;
2446         i->pid = (pid_t) pid;
2447         i->code = code;
2448         i->status = status;
2449
2450         return 0;
2451 }
2452
2453 typedef struct UnitStatusInfo {
2454         const char *id;
2455         const char *load_state;
2456         const char *active_state;
2457         const char *sub_state;
2458         const char *unit_file_state;
2459
2460         const char *description;
2461         const char *following;
2462
2463         char **documentation;
2464
2465         const char *fragment_path;
2466         const char *source_path;
2467         const char *control_group;
2468
2469         char **dropin_paths;
2470
2471         const char *load_error;
2472         const char *result;
2473
2474         usec_t inactive_exit_timestamp;
2475         usec_t inactive_exit_timestamp_monotonic;
2476         usec_t active_enter_timestamp;
2477         usec_t active_exit_timestamp;
2478         usec_t inactive_enter_timestamp;
2479
2480         bool need_daemon_reload;
2481
2482         /* Service */
2483         pid_t main_pid;
2484         pid_t control_pid;
2485         const char *status_text;
2486         const char *pid_file;
2487         bool running:1;
2488
2489         usec_t start_timestamp;
2490         usec_t exit_timestamp;
2491
2492         int exit_code, exit_status;
2493
2494         usec_t condition_timestamp;
2495         bool condition_result;
2496         bool failed_condition_trigger;
2497         bool failed_condition_negate;
2498         const char *failed_condition;
2499         const char *failed_condition_param;
2500
2501         /* Socket */
2502         unsigned n_accepted;
2503         unsigned n_connections;
2504         bool accept;
2505
2506         /* Pairs of type, path */
2507         char **listen;
2508
2509         /* Device */
2510         const char *sysfs_path;
2511
2512         /* Mount, Automount */
2513         const char *where;
2514
2515         /* Swap */
2516         const char *what;
2517
2518         LIST_HEAD(ExecStatusInfo, exec);
2519 } UnitStatusInfo;
2520
2521 static void print_status_info(UnitStatusInfo *i,
2522                               bool *ellipsized) {
2523         ExecStatusInfo *p;
2524         const char *on, *off, *ss;
2525         usec_t timestamp;
2526         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2527         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2528         const char *path;
2529         int flags =
2530                 arg_all * OUTPUT_SHOW_ALL |
2531                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2532                 on_tty() * OUTPUT_COLOR |
2533                 !arg_quiet * OUTPUT_WARN_CUTOFF |
2534                 arg_full * OUTPUT_FULL_WIDTH;
2535         char **t, **t2;
2536
2537         assert(i);
2538
2539         /* This shows pretty information about a unit. See
2540          * print_property() for a low-level property printer */
2541
2542         printf("%s", strna(i->id));
2543
2544         if (i->description && !streq_ptr(i->id, i->description))
2545                 printf(" - %s", i->description);
2546
2547         printf("\n");
2548
2549         if (i->following)
2550                 printf("   Follow: unit currently follows state of %s\n", i->following);
2551
2552         if (streq_ptr(i->load_state, "error")) {
2553                 on = ansi_highlight_red();
2554                 off = ansi_highlight_off();
2555         } else
2556                 on = off = "";
2557
2558         path = i->source_path ? i->source_path : i->fragment_path;
2559
2560         if (i->load_error)
2561                 printf("   Loaded: %s%s%s (Reason: %s)\n",
2562                        on, strna(i->load_state), off, i->load_error);
2563         else if (path && i->unit_file_state)
2564                 printf("   Loaded: %s%s%s (%s; %s)\n",
2565                        on, strna(i->load_state), off, path, i->unit_file_state);
2566         else if (path)
2567                 printf("   Loaded: %s%s%s (%s)\n",
2568                        on, strna(i->load_state), off, path);
2569         else
2570                 printf("   Loaded: %s%s%s\n",
2571                        on, strna(i->load_state), off);
2572
2573         if (!strv_isempty(i->dropin_paths)) {
2574                 char ** dropin;
2575                 char * dir = NULL;
2576                 bool last = false;
2577
2578                 STRV_FOREACH(dropin, i->dropin_paths) {
2579                         if (! dir || last) {
2580                                 printf(dir ? "        " : "  Drop-In: ");
2581
2582                                 free(dir);
2583
2584                                 if (path_get_parent(*dropin, &dir) < 0) {
2585                                         log_oom();
2586                                         return;
2587                                 }
2588
2589                                 printf("%s\n           %s", dir,
2590                                        draw_special_char(DRAW_TREE_RIGHT));
2591                         }
2592
2593                         last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2594
2595                         printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2596                 }
2597
2598                 free(dir);
2599         }
2600
2601         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2602
2603         if (streq_ptr(i->active_state, "failed")) {
2604                 on = ansi_highlight_red();
2605                 off = ansi_highlight_off();
2606         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2607                 on = ansi_highlight_green();
2608                 off = ansi_highlight_off();
2609         } else
2610                 on = off = "";
2611
2612         if (ss)
2613                 printf("   Active: %s%s (%s)%s",
2614                        on, strna(i->active_state), ss, off);
2615         else
2616                 printf("   Active: %s%s%s",
2617                        on, strna(i->active_state), off);
2618
2619         if (!isempty(i->result) && !streq(i->result, "success"))
2620                 printf(" (Result: %s)", i->result);
2621
2622         timestamp = (streq_ptr(i->active_state, "active")      ||
2623                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2624                     (streq_ptr(i->active_state, "inactive")    ||
2625                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2626                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2627                                                                   i->active_exit_timestamp;
2628
2629         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2630         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2631
2632         if (s1)
2633                 printf(" since %s; %s\n", s2, s1);
2634         else if (s2)
2635                 printf(" since %s\n", s2);
2636         else
2637                 printf("\n");
2638
2639         if (!i->condition_result && i->condition_timestamp > 0) {
2640                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2641                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2642
2643                 printf("           start condition failed at %s%s%s\n",
2644                        s2, s1 ? "; " : "", s1 ? s1 : "");
2645                 if (i->failed_condition_trigger)
2646                         printf("           none of the trigger conditions were met\n");
2647                 else if (i->failed_condition)
2648                         printf("           %s=%s%s was not met\n",
2649                                i->failed_condition,
2650                                i->failed_condition_negate ? "!" : "",
2651                                i->failed_condition_param);
2652         }
2653
2654         if (i->sysfs_path)
2655                 printf("   Device: %s\n", i->sysfs_path);
2656         if (i->where)
2657                 printf("    Where: %s\n", i->where);
2658         if (i->what)
2659                 printf("     What: %s\n", i->what);
2660
2661         STRV_FOREACH(t, i->documentation)
2662                 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
2663
2664         STRV_FOREACH_PAIR(t, t2, i->listen)
2665                 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
2666
2667         if (i->accept)
2668                 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2669
2670         LIST_FOREACH(exec, p, i->exec) {
2671                 _cleanup_free_ char *argv = NULL;
2672                 bool good;
2673
2674                 /* Only show exited processes here */
2675                 if (p->code == 0)
2676                         continue;
2677
2678                 argv = strv_join(p->argv, " ");
2679                 printf("  Process: %u %s=%s ", p->pid, p->name, strna(argv));
2680
2681                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2682                 if (!good) {
2683                         on = ansi_highlight_red();
2684                         off = ansi_highlight_off();
2685                 } else
2686                         on = off = "";
2687
2688                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2689
2690                 if (p->code == CLD_EXITED) {
2691                         const char *c;
2692
2693                         printf("status=%i", p->status);
2694
2695                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2696                         if (c)
2697                                 printf("/%s", c);
2698
2699                 } else
2700                         printf("signal=%s", signal_to_string(p->status));
2701
2702                 printf(")%s\n", off);
2703
2704                 if (i->main_pid == p->pid &&
2705                     i->start_timestamp == p->start_timestamp &&
2706                     i->exit_timestamp == p->start_timestamp)
2707                         /* Let's not show this twice */
2708                         i->main_pid = 0;
2709
2710                 if (p->pid == i->control_pid)
2711                         i->control_pid = 0;
2712         }
2713
2714         if (i->main_pid > 0 || i->control_pid > 0) {
2715                 if (i->main_pid > 0) {
2716                         printf(" Main PID: %u", (unsigned) i->main_pid);
2717
2718                         if (i->running) {
2719                                 _cleanup_free_ char *comm = NULL;
2720                                 get_process_comm(i->main_pid, &comm);
2721                                 if (comm)
2722                                         printf(" (%s)", comm);
2723                         } else if (i->exit_code > 0) {
2724                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2725
2726                                 if (i->exit_code == CLD_EXITED) {
2727                                         const char *c;
2728
2729                                         printf("status=%i", i->exit_status);
2730
2731                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2732                                         if (c)
2733                                                 printf("/%s", c);
2734
2735                                 } else
2736                                         printf("signal=%s", signal_to_string(i->exit_status));
2737                                 printf(")");
2738                         }
2739
2740                         if (i->control_pid > 0)
2741                                 printf(";");
2742                 }
2743
2744                 if (i->control_pid > 0) {
2745                         _cleanup_free_ char *c = NULL;
2746
2747                         printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
2748
2749                         get_process_comm(i->control_pid, &c);
2750                         if (c)
2751                                 printf(" (%s)", c);
2752                 }
2753
2754                 printf("\n");
2755         }
2756
2757         if (i->status_text)
2758                 printf("   Status: \"%s\"\n", i->status_text);
2759
2760         if (i->control_group &&
2761             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
2762                 unsigned c;
2763
2764                 printf("   CGroup: %s\n", i->control_group);
2765
2766                 if (arg_transport != TRANSPORT_SSH) {
2767                         unsigned k = 0;
2768                         pid_t extra[2];
2769                         char prefix[] = "           ";
2770
2771                         c = columns();
2772                         if (c > sizeof(prefix) - 1)
2773                                 c -= sizeof(prefix) - 1;
2774                         else
2775                                 c = 0;
2776
2777                         if (i->main_pid > 0)
2778                                 extra[k++] = i->main_pid;
2779
2780                         if (i->control_pid > 0)
2781                                 extra[k++] = i->control_pid;
2782
2783                         show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix,
2784                                                       c, false, extra, k, flags);
2785                 }
2786         }
2787
2788         if (i->id && arg_transport != TRANSPORT_SSH) {
2789                 printf("\n");
2790                 show_journal_by_unit(stdout,
2791                                      i->id,
2792                                      arg_output,
2793                                      0,
2794                                      i->inactive_exit_timestamp_monotonic,
2795                                      arg_lines,
2796                                      getuid(),
2797                                      flags,
2798                                      arg_scope == UNIT_FILE_SYSTEM,
2799                                      ellipsized);
2800         }
2801
2802         if (i->need_daemon_reload)
2803                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
2804                        ansi_highlight_red(),
2805                        ansi_highlight_off(),
2806                        arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
2807 }
2808
2809 static void show_unit_help(UnitStatusInfo *i) {
2810         char **p;
2811
2812         assert(i);
2813
2814         if (!i->documentation) {
2815                 log_info("Documentation for %s not known.", i->id);
2816                 return;
2817         }
2818
2819         STRV_FOREACH(p, i->documentation) {
2820
2821                 if (startswith(*p, "man:")) {
2822                         size_t k;
2823                         char *e = NULL;
2824                         _cleanup_free_ char *page = NULL, *section = NULL;
2825                         const char *args[4] = { "man", NULL, NULL, NULL };
2826                         pid_t pid;
2827
2828                         k = strlen(*p);
2829
2830                         if ((*p)[k-1] == ')')
2831                                 e = strrchr(*p, '(');
2832
2833                         if (e) {
2834                                 page = strndup((*p) + 4, e - *p - 4);
2835                                 section = strndup(e + 1, *p + k - e - 2);
2836                                 if (!page || !section) {
2837                                         log_oom();
2838                                         return;
2839                                 }
2840
2841                                 args[1] = section;
2842                                 args[2] = page;
2843                         } else
2844                                 args[1] = *p + 4;
2845
2846                         pid = fork();
2847                         if (pid < 0) {
2848                                 log_error("Failed to fork: %m");
2849                                 continue;
2850                         }
2851
2852                         if (pid == 0) {
2853                                 /* Child */
2854                                 execvp(args[0], (char**) args);
2855                                 log_error("Failed to execute man: %m");
2856                                 _exit(EXIT_FAILURE);
2857                         }
2858
2859                         wait_for_terminate(pid, NULL);
2860                 } else
2861                         log_info("Can't show: %s", *p);
2862         }
2863 }
2864
2865 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2866
2867         assert(name);
2868         assert(iter);
2869         assert(i);
2870
2871         switch (dbus_message_iter_get_arg_type(iter)) {
2872
2873         case DBUS_TYPE_STRING: {
2874                 const char *s;
2875
2876                 dbus_message_iter_get_basic(iter, &s);
2877
2878                 if (!isempty(s)) {
2879                         if (streq(name, "Id"))
2880                                 i->id = s;
2881                         else if (streq(name, "LoadState"))
2882                                 i->load_state = s;
2883                         else if (streq(name, "ActiveState"))
2884                                 i->active_state = s;
2885                         else if (streq(name, "SubState"))
2886                                 i->sub_state = s;
2887                         else if (streq(name, "Description"))
2888                                 i->description = s;
2889                         else if (streq(name, "FragmentPath"))
2890                                 i->fragment_path = s;
2891                         else if (streq(name, "SourcePath"))
2892                                 i->source_path = s;
2893 #ifndef NOLEGACY
2894                         else if (streq(name, "DefaultControlGroup")) {
2895                                 const char *e;
2896                                 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
2897                                 if (e)
2898                                         i->control_group = e;
2899                         }
2900 #endif
2901                         else if (streq(name, "ControlGroup"))
2902                                 i->control_group = s;
2903                         else if (streq(name, "StatusText"))
2904                                 i->status_text = s;
2905                         else if (streq(name, "PIDFile"))
2906                                 i->pid_file = s;
2907                         else if (streq(name, "SysFSPath"))
2908                                 i->sysfs_path = s;
2909                         else if (streq(name, "Where"))
2910                                 i->where = s;
2911                         else if (streq(name, "What"))
2912                                 i->what = s;
2913                         else if (streq(name, "Following"))
2914                                 i->following = s;
2915                         else if (streq(name, "UnitFileState"))
2916                                 i->unit_file_state = s;
2917                         else if (streq(name, "Result"))
2918                                 i->result = s;
2919                 }
2920
2921                 break;
2922         }
2923
2924         case DBUS_TYPE_BOOLEAN: {
2925                 dbus_bool_t b;
2926
2927                 dbus_message_iter_get_basic(iter, &b);
2928
2929                 if (streq(name, "Accept"))
2930                         i->accept = b;
2931                 else if (streq(name, "NeedDaemonReload"))
2932                         i->need_daemon_reload = b;
2933                 else if (streq(name, "ConditionResult"))
2934                         i->condition_result = b;
2935
2936                 break;
2937         }
2938
2939         case DBUS_TYPE_UINT32: {
2940                 uint32_t u;
2941
2942                 dbus_message_iter_get_basic(iter, &u);
2943
2944                 if (streq(name, "MainPID")) {
2945                         if (u > 0) {
2946                                 i->main_pid = (pid_t) u;
2947                                 i->running = true;
2948                         }
2949                 } else if (streq(name, "ControlPID"))
2950                         i->control_pid = (pid_t) u;
2951                 else if (streq(name, "ExecMainPID")) {
2952                         if (u > 0)
2953                                 i->main_pid = (pid_t) u;
2954                 } else if (streq(name, "NAccepted"))
2955                         i->n_accepted = u;
2956                 else if (streq(name, "NConnections"))
2957                         i->n_connections = u;
2958
2959                 break;
2960         }
2961
2962         case DBUS_TYPE_INT32: {
2963                 int32_t j;
2964
2965                 dbus_message_iter_get_basic(iter, &j);
2966
2967                 if (streq(name, "ExecMainCode"))
2968                         i->exit_code = (int) j;
2969                 else if (streq(name, "ExecMainStatus"))
2970                         i->exit_status = (int) j;
2971
2972                 break;
2973         }
2974
2975         case DBUS_TYPE_UINT64: {
2976                 uint64_t u;
2977
2978                 dbus_message_iter_get_basic(iter, &u);
2979
2980                 if (streq(name, "ExecMainStartTimestamp"))
2981                         i->start_timestamp = (usec_t) u;
2982                 else if (streq(name, "ExecMainExitTimestamp"))
2983                         i->exit_timestamp = (usec_t) u;
2984                 else if (streq(name, "ActiveEnterTimestamp"))
2985                         i->active_enter_timestamp = (usec_t) u;
2986                 else if (streq(name, "InactiveEnterTimestamp"))
2987                         i->inactive_enter_timestamp = (usec_t) u;
2988                 else if (streq(name, "InactiveExitTimestamp"))
2989                         i->inactive_exit_timestamp = (usec_t) u;
2990                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2991                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2992                 else if (streq(name, "ActiveExitTimestamp"))
2993                         i->active_exit_timestamp = (usec_t) u;
2994                 else if (streq(name, "ConditionTimestamp"))
2995                         i->condition_timestamp = (usec_t) u;
2996
2997                 break;
2998         }
2999
3000         case DBUS_TYPE_ARRAY: {
3001
3002                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3003                     startswith(name, "Exec")) {
3004                         DBusMessageIter sub;
3005
3006                         dbus_message_iter_recurse(iter, &sub);
3007                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3008                                 ExecStatusInfo *info;
3009                                 int r;
3010
3011                                 info = new0(ExecStatusInfo, 1);
3012                                 if (!info)
3013                                         return -ENOMEM;
3014
3015                                 info->name = strdup(name);
3016                                 if (!info->name) {
3017                                         free(info);
3018                                         return -ENOMEM;
3019                                 }
3020
3021                                 r = exec_status_info_deserialize(&sub, info);
3022                                 if (r < 0) {
3023                                         free(info);
3024                                         return r;
3025                                 }
3026
3027                                 LIST_PREPEND(exec, i->exec, info);
3028
3029                                 dbus_message_iter_next(&sub);
3030                         }
3031
3032                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3033                            streq(name, "Listen")) {
3034                         DBusMessageIter sub, sub2;
3035
3036                         dbus_message_iter_recurse(iter, &sub);
3037                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3038                                 const char *type, *path;
3039
3040                                 dbus_message_iter_recurse(&sub, &sub2);
3041
3042                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3043                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
3044                                         int r;
3045
3046                                         r = strv_extend(&i->listen, type);
3047                                         if (r < 0)
3048                                                 return r;
3049                                         r = strv_extend(&i->listen, path);
3050                                         if (r < 0)
3051                                                 return r;
3052                                 }
3053
3054                                 dbus_message_iter_next(&sub);
3055                         }
3056
3057                         return 0;
3058
3059                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
3060                            streq(name, "DropInPaths")) {
3061                         int r = bus_parse_strv_iter(iter, &i->dropin_paths);
3062                         if (r < 0)
3063                                 return r;
3064
3065                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
3066                            streq(name, "Documentation")) {
3067
3068                         DBusMessageIter sub;
3069
3070                         dbus_message_iter_recurse(iter, &sub);
3071                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
3072                                 const char *s;
3073                                 int r;
3074
3075                                 dbus_message_iter_get_basic(&sub, &s);
3076
3077                                 r = strv_extend(&i->documentation, s);
3078                                 if (r < 0)
3079                                         return r;
3080
3081                                 dbus_message_iter_next(&sub);
3082                         }
3083
3084                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3085                            streq(name, "Conditions")) {
3086                         DBusMessageIter sub, sub2;
3087
3088                         dbus_message_iter_recurse(iter, &sub);
3089                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3090                                 const char *cond, *param;
3091                                 dbus_bool_t trigger, negate;
3092                                 dbus_int32_t state;
3093
3094                                 dbus_message_iter_recurse(&sub, &sub2);
3095                                 log_debug("here");
3096
3097                                 if(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &cond, true) >= 0 &&
3098                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &trigger, true) >= 0 &&
3099                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &negate, true) >= 0 &&
3100                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &param, true) >= 0 &&
3101                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &state, false) >= 0) {
3102                                         log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3103                                         if (state < 0 && (!trigger || !i->failed_condition)) {
3104                                                 i->failed_condition = cond;
3105                                                 i->failed_condition_trigger = trigger;
3106                                                 i->failed_condition_negate = negate;
3107                                                 i->failed_condition_param = param;
3108                                         }
3109                                 }
3110
3111                                 dbus_message_iter_next(&sub);
3112                         }
3113                 }
3114
3115                 break;
3116         }
3117
3118         case DBUS_TYPE_STRUCT: {
3119
3120                 if (streq(name, "LoadError")) {
3121                         DBusMessageIter sub;
3122                         const char *n, *message;
3123                         int r;
3124
3125                         dbus_message_iter_recurse(iter, &sub);
3126
3127                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
3128                         if (r < 0)
3129                                 return r;
3130
3131                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
3132                         if (r < 0)
3133                                 return r;
3134
3135                         if (!isempty(message))
3136                                 i->load_error = message;
3137                 }
3138
3139                 break;
3140         }
3141         }
3142
3143         return 0;
3144 }
3145
3146 static int print_property(const char *name, DBusMessageIter *iter) {
3147         assert(name);
3148         assert(iter);
3149
3150         /* This is a low-level property printer, see
3151          * print_status_info() for the nicer output */
3152
3153         if (arg_properties && !strv_find(arg_properties, name))
3154                 return 0;
3155
3156         switch (dbus_message_iter_get_arg_type(iter)) {
3157
3158         case DBUS_TYPE_STRUCT: {
3159                 DBusMessageIter sub;
3160                 dbus_message_iter_recurse(iter, &sub);
3161
3162                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
3163                         uint32_t u;
3164
3165                         dbus_message_iter_get_basic(&sub, &u);
3166
3167                         if (u)
3168                                 printf("%s=%u\n", name, (unsigned) u);
3169                         else if (arg_all)
3170                                 printf("%s=\n", name);
3171
3172                         return 0;
3173                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
3174                         const char *s;
3175
3176                         dbus_message_iter_get_basic(&sub, &s);
3177
3178                         if (arg_all || s[0])
3179                                 printf("%s=%s\n", name, s);
3180
3181                         return 0;
3182                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
3183                         const char *a = NULL, *b = NULL;
3184
3185                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
3186                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
3187
3188                         if (arg_all || !isempty(a) || !isempty(b))
3189                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
3190
3191                         return 0;
3192                 }
3193
3194                 break;
3195         }
3196
3197         case DBUS_TYPE_ARRAY:
3198
3199                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
3200                         DBusMessageIter sub, sub2;
3201
3202                         dbus_message_iter_recurse(iter, &sub);
3203                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3204                                 const char *path;
3205                                 dbus_bool_t ignore;
3206
3207                                 dbus_message_iter_recurse(&sub, &sub2);
3208
3209                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3210                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
3211                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
3212
3213                                 dbus_message_iter_next(&sub);
3214                         }
3215
3216                         return 0;
3217
3218                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
3219                         DBusMessageIter sub, sub2;
3220
3221                         dbus_message_iter_recurse(iter, &sub);
3222
3223                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3224                                 const char *type, *path;
3225
3226                                 dbus_message_iter_recurse(&sub, &sub2);
3227
3228                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3229                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3230                                         printf("%s=%s\n", type, path);
3231
3232                                 dbus_message_iter_next(&sub);
3233                         }
3234
3235                         return 0;
3236
3237                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3238                         DBusMessageIter sub, sub2;
3239
3240                         dbus_message_iter_recurse(iter, &sub);
3241                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3242                                 const char *type, *path;
3243
3244                                 dbus_message_iter_recurse(&sub, &sub2);
3245
3246                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3247                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3248                                         printf("Listen%s=%s\n", type, path);
3249
3250                                 dbus_message_iter_next(&sub);
3251                         }
3252
3253                         return 0;
3254
3255                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
3256                         DBusMessageIter sub, sub2;
3257
3258                         dbus_message_iter_recurse(iter, &sub);
3259                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3260                                 const char *base;
3261                                 uint64_t value, next_elapse;
3262
3263                                 dbus_message_iter_recurse(&sub, &sub2);
3264
3265                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
3266                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
3267                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
3268                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
3269
3270                                         printf("%s={ value=%s ; next_elapse=%s }\n",
3271                                                base,
3272                                                format_timespan(timespan1, sizeof(timespan1), value, 0),
3273                                                format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
3274                                 }
3275
3276                                 dbus_message_iter_next(&sub);
3277                         }
3278
3279                         return 0;
3280
3281                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3282                         DBusMessageIter sub;
3283
3284                         dbus_message_iter_recurse(iter, &sub);
3285                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3286                                 ExecStatusInfo info = {};
3287
3288                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3289                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3290                                         _cleanup_free_ char *t;
3291
3292                                         t = strv_join(info.argv, " ");
3293
3294                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3295                                                name,
3296                                                strna(info.path),
3297                                                strna(t),
3298                                                yes_no(info.ignore),
3299                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3300                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3301                                                (unsigned) info. pid,
3302                                                sigchld_code_to_string(info.code),
3303                                                info.status,
3304                                                info.code == CLD_EXITED ? "" : "/",
3305                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3306                                 }
3307
3308                                 free(info.path);
3309                                 strv_free(info.argv);
3310
3311                                 dbus_message_iter_next(&sub);
3312                         }
3313
3314                         return 0;
3315
3316                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "DeviceAllow")) {
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, *rwm;
3322
3323                                 dbus_message_iter_recurse(&sub, &sub2);
3324
3325                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3326                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) >= 0)
3327                                         printf("%s=%s %s\n", name, strna(path), strna(rwm));
3328
3329                                 dbus_message_iter_next(&sub);
3330                         }
3331                         return 0;
3332
3333                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "BlockIODeviceWeight")) {
3334                         DBusMessageIter sub, sub2;
3335
3336                         dbus_message_iter_recurse(iter, &sub);
3337                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3338                                 const char *path;
3339                                 uint64_t weight;
3340
3341                                 dbus_message_iter_recurse(&sub, &sub2);
3342
3343                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3344                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &weight, false) >= 0)
3345                                         printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
3346
3347                                 dbus_message_iter_next(&sub);
3348                         }
3349                         return 0;
3350
3351                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
3352                         DBusMessageIter sub, sub2;
3353
3354                         dbus_message_iter_recurse(iter, &sub);
3355                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3356                                 const char *path;
3357                                 uint64_t bandwidth;
3358
3359                                 dbus_message_iter_recurse(&sub, &sub2);
3360
3361                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3362                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &bandwidth, false) >= 0)
3363                                         printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
3364
3365                                 dbus_message_iter_next(&sub);
3366                         }
3367                         return 0;
3368                 }
3369
3370
3371                 break;
3372         }
3373
3374         if (generic_print_property(name, iter, arg_all) > 0)
3375                 return 0;
3376
3377         if (arg_all)
3378                 printf("%s=[unprintable]\n", name);
3379
3380         return 0;
3381 }
3382
3383 static int show_one(const char *verb,
3384                     DBusConnection *bus,
3385                     const char *path,
3386                     bool show_properties,
3387                     bool *new_line,
3388                     bool *ellipsized) {
3389         _cleanup_free_ DBusMessage *reply = NULL;
3390         const char *interface = "";
3391         int r;
3392         DBusMessageIter iter, sub, sub2, sub3;
3393         UnitStatusInfo info = {};
3394         ExecStatusInfo *p;
3395
3396         assert(path);
3397         assert(new_line);
3398
3399         r = bus_method_call_with_reply(
3400                         bus,
3401                         "org.freedesktop.systemd1",
3402                         path,
3403                         "org.freedesktop.DBus.Properties",
3404                         "GetAll",
3405                         &reply,
3406                         NULL,
3407                         DBUS_TYPE_STRING, &interface,
3408                         DBUS_TYPE_INVALID);
3409         if (r < 0)
3410                 return r;
3411
3412         if (!dbus_message_iter_init(reply, &iter) ||
3413             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3414             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3415                 log_error("Failed to parse reply.");
3416                 return -EIO;
3417         }
3418
3419         dbus_message_iter_recurse(&iter, &sub);
3420
3421         if (*new_line)
3422                 printf("\n");
3423
3424         *new_line = true;
3425
3426         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3427                 const char *name;
3428
3429                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
3430                 dbus_message_iter_recurse(&sub, &sub2);
3431
3432                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
3433                     dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
3434                         log_error("Failed to parse reply.");
3435                         return -EIO;
3436                 }
3437
3438                 dbus_message_iter_recurse(&sub2, &sub3);
3439
3440                 if (show_properties)
3441                         r = print_property(name, &sub3);
3442                 else
3443                         r = status_property(name, &sub3, &info);
3444                 if (r < 0) {
3445                         log_error("Failed to parse reply.");
3446                         return -EIO;
3447                 }
3448
3449                 dbus_message_iter_next(&sub);
3450         }
3451
3452         r = 0;
3453
3454         if (!show_properties) {
3455                 if (streq(verb, "help"))
3456                         show_unit_help(&info);
3457                 else
3458                         print_status_info(&info, ellipsized);
3459         }
3460
3461         strv_free(info.documentation);
3462         strv_free(info.dropin_paths);
3463         strv_free(info.listen);
3464
3465         if (!streq_ptr(info.active_state, "active") &&
3466             !streq_ptr(info.active_state, "reloading") &&
3467             streq(verb, "status")) {
3468                 /* According to LSB: "program not running" */
3469                 /* 0: program is running or service is OK
3470                  * 1: program is dead and /var/run pid file exists
3471                  * 2: program is dead and /var/lock lock file exists
3472                  * 3: program is not running
3473                  * 4: program or service status is unknown
3474                  */
3475                 if (info.pid_file && access(info.pid_file, F_OK) == 0)
3476                         r = 1;
3477                 else
3478                         r = 3;
3479         }
3480
3481         while ((p = info.exec)) {
3482                 LIST_REMOVE(exec, info.exec, p);
3483                 exec_status_info_free(p);
3484         }
3485
3486         return r;
3487 }
3488
3489 static int show_one_by_pid(const char *verb,
3490                            DBusConnection *bus,
3491                            uint32_t pid,
3492                            bool *new_line,
3493                            bool *ellipsized) {
3494         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3495         const char *path = NULL;
3496         _cleanup_dbus_error_free_ DBusError error;
3497         int r;
3498
3499         dbus_error_init(&error);
3500
3501         r = bus_method_call_with_reply(
3502                         bus,
3503                         "org.freedesktop.systemd1",
3504                         "/org/freedesktop/systemd1",
3505                         "org.freedesktop.systemd1.Manager",
3506                         "GetUnitByPID",
3507                         &reply,
3508                         NULL,
3509                         DBUS_TYPE_UINT32, &pid,
3510                         DBUS_TYPE_INVALID);
3511         if (r < 0)
3512                 return r;
3513
3514         if (!dbus_message_get_args(reply, &error,
3515                                    DBUS_TYPE_OBJECT_PATH, &path,
3516                                    DBUS_TYPE_INVALID)) {
3517                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3518                 return -EIO;
3519         }
3520
3521         r = show_one(verb, bus, path, false, new_line, ellipsized);
3522         return r;
3523 }
3524
3525 static int show_all(const char* verb,
3526                     DBusConnection *bus,
3527                     bool show_properties,
3528                     bool *new_line,
3529                     bool *ellipsized) {
3530         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3531         _cleanup_free_ struct unit_info *unit_infos = NULL;
3532         unsigned c = 0;
3533         const struct unit_info *u;
3534         int r;
3535
3536         r = get_unit_list(bus, &reply, &unit_infos, &c);
3537         if (r < 0)
3538                 return r;
3539
3540         qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
3541
3542         for (u = unit_infos; u < unit_infos + c; u++) {
3543                 _cleanup_free_ char *p = NULL;
3544
3545                 if (!output_show_unit(u))
3546                         continue;
3547
3548                 p = unit_dbus_path_from_name(u->id);
3549                 if (!p)
3550                         return log_oom();
3551
3552                 printf("%s -> '%s'\n", u->id, p);
3553
3554                 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
3555                 if (r != 0)
3556                         return r;
3557         }
3558
3559         return 0;
3560 }
3561
3562 static int show(DBusConnection *bus, char **args) {
3563         int r, ret = 0;
3564         bool show_properties, show_status, new_line = false;
3565         char **name;
3566         bool ellipsized = false;
3567
3568         assert(bus);
3569         assert(args);
3570
3571         show_properties = streq(args[0], "show");
3572         show_status = streq(args[0], "status");
3573
3574         if (show_properties)
3575                 pager_open_if_enabled();
3576
3577         /* If no argument is specified inspect the manager itself */
3578
3579         if (show_properties && strv_length(args) <= 1)
3580                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
3581
3582         if (show_status && strv_length(args) <= 1)
3583                 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
3584         else
3585                 STRV_FOREACH(name, args+1) {
3586                         uint32_t id;
3587
3588                         if (safe_atou32(*name, &id) < 0) {
3589                                 _cleanup_free_ char *p = NULL, *n = NULL;
3590                                 /* Interpret as unit name */
3591
3592                                 n = unit_name_mangle(*name);
3593                                 if (!n)
3594                                         return log_oom();
3595
3596                                 p = unit_dbus_path_from_name(n);
3597                                 if (!p)
3598                                         return log_oom();
3599
3600                                 r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
3601                                 if (r != 0)
3602                                         ret = r;
3603
3604                         } else if (show_properties) {
3605                                 _cleanup_free_ char *p = NULL;
3606
3607                                 /* Interpret as job id */
3608                                 if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3609                                         return log_oom();
3610
3611                                 r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
3612                                 if (r != 0)
3613                                         ret = r;
3614
3615                         } else {
3616                                 /* Interpret as PID */
3617                                 r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized);
3618                                 if (r != 0)
3619                                         ret = r;
3620                         }
3621                 }
3622
3623         if (ellipsized && !arg_quiet)
3624                 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
3625
3626         return ret;
3627 }
3628
3629 static int append_assignment(DBusMessageIter *iter, const char *assignment) {
3630         const char *eq;
3631         char *field;
3632         DBusMessageIter sub;
3633         int r;
3634
3635         assert(iter);
3636         assert(assignment);
3637
3638         eq = strchr(assignment, '=');
3639         if (!eq) {
3640                 log_error("Not an assignment: %s", assignment);
3641                 return -EINVAL;
3642         }
3643
3644         field = strndupa(assignment, eq - assignment);
3645         eq ++;
3646
3647         if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field))
3648                 return log_oom();
3649
3650         if (streq(field, "CPUAccounting") ||
3651             streq(field, "MemoryAccounting") ||
3652             streq(field, "BlockIOAccounting")) {
3653                 dbus_bool_t b;
3654
3655                 r = parse_boolean(eq);
3656                 if (r < 0) {
3657                         log_error("Failed to parse boolean assignment %s.", assignment);
3658                         return -EINVAL;
3659                 }
3660
3661                 b = r;
3662                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "b", &sub) ||
3663                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
3664                         return log_oom();
3665
3666         } else if (streq(field, "MemoryLimit")) {
3667                 off_t bytes;
3668                 uint64_t u;
3669
3670                 r = parse_bytes(eq, &bytes);
3671                 if (r < 0) {
3672                         log_error("Failed to parse bytes specification %s", assignment);
3673                         return -EINVAL;
3674                 }
3675
3676                 u = bytes;
3677                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
3678                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
3679                         return log_oom();
3680
3681         } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
3682                 uint64_t u;
3683
3684                 r = safe_atou64(eq, &u);
3685                 if (r < 0) {
3686                         log_error("Failed to parse %s value %s.", field, eq);
3687                         return -EINVAL;
3688                 }
3689
3690                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
3691                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
3692                         return log_oom();
3693
3694         } else if (streq(field, "DevicePolicy")) {
3695
3696                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &sub) ||
3697                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &eq))
3698                         return log_oom();
3699
3700         } else if (streq(field, "DeviceAllow")) {
3701                 DBusMessageIter sub2;
3702
3703                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(ss)", &sub) ||
3704                     !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(ss)", &sub2))
3705                         return log_oom();
3706
3707                 if (!isempty(eq)) {
3708                         const char *path, *rwm;
3709                         DBusMessageIter sub3;
3710                         char *e;
3711
3712                         e = strchr(eq, ' ');
3713                         if (e) {
3714                                 path = strndupa(eq, e - eq);
3715                                 rwm = e+1;
3716                         } else {
3717                                 path = eq;
3718                                 rwm = "";
3719                         }
3720
3721                         if (!path_startswith(path, "/dev")) {
3722                                 log_error("%s is not a device file in /dev.", path);
3723                                 return -EINVAL;
3724                         }
3725
3726                         if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3727                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3728                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &rwm) ||
3729                             !dbus_message_iter_close_container(&sub2, &sub3))
3730                                 return log_oom();
3731                 }
3732
3733                 if (!dbus_message_iter_close_container(&sub, &sub2))
3734                         return log_oom();
3735
3736         } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
3737                 DBusMessageIter sub2;
3738
3739                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) ||
3740                     !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2))
3741                         return log_oom();
3742
3743                 if (!isempty(eq)) {
3744                         const char *path, *bandwidth;
3745                         DBusMessageIter sub3;
3746                         uint64_t u;
3747                         off_t bytes;
3748                         char *e;
3749
3750                         e = strchr(eq, ' ');
3751                         if (e) {
3752                                 path = strndupa(eq, e - eq);
3753                                 bandwidth = e+1;
3754                         } else {
3755                                 log_error("Failed to parse %s value %s.", field, eq);
3756                                 return -EINVAL;
3757                         }
3758
3759                         if (!path_startswith(path, "/dev")) {
3760                                 log_error("%s is not a device file in /dev.", path);
3761                                 return -EINVAL;
3762                         }
3763
3764                         r = parse_bytes(bandwidth, &bytes);
3765                         if (r < 0) {
3766                                 log_error("Failed to parse byte value %s.", bandwidth);
3767                                 return -EINVAL;
3768                         }
3769
3770                         u = (uint64_t) bytes;
3771
3772                         if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3773                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3774                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) ||
3775                             !dbus_message_iter_close_container(&sub2, &sub3))
3776                                 return log_oom();
3777                 }
3778
3779                 if (!dbus_message_iter_close_container(&sub, &sub2))
3780                         return log_oom();
3781
3782         } else if (streq(field, "BlockIODeviceWeight")) {
3783                 DBusMessageIter sub2;
3784
3785                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) ||
3786                     !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2))
3787                         return log_oom();
3788
3789                 if (!isempty(eq)) {
3790                         const char *path, *weight;
3791                         DBusMessageIter sub3;
3792                         uint64_t u;
3793                         char *e;
3794
3795                         e = strchr(eq, ' ');
3796                         if (e) {
3797                                 path = strndupa(eq, e - eq);
3798                                 weight = e+1;
3799                         } else {
3800                                 log_error("Failed to parse %s value %s.", field, eq);
3801                                 return -EINVAL;
3802                         }
3803
3804                         if (!path_startswith(path, "/dev")) {
3805                                 log_error("%s is not a device file in /dev.", path);
3806                                 return -EINVAL;
3807                         }
3808
3809                         r = safe_atou64(weight, &u);
3810                         if (r < 0) {
3811                                 log_error("Failed to parse %s value %s.", field, weight);
3812                                 return -EINVAL;
3813                         }
3814                         if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3815                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3816                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) ||
3817                             !dbus_message_iter_close_container(&sub2, &sub3))
3818                                 return log_oom();
3819                 }
3820
3821                 if (!dbus_message_iter_close_container(&sub, &sub2))
3822                         return log_oom();
3823
3824         } else {
3825                 log_error("Unknown assignment %s.", assignment);
3826                 return -EINVAL;
3827         }
3828
3829         if (!dbus_message_iter_close_container(iter, &sub))
3830                 return log_oom();
3831
3832         return 0;
3833 }
3834
3835 static int set_property(DBusConnection *bus, char **args) {
3836
3837         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
3838         _cleanup_free_ char *n = NULL;
3839         DBusMessageIter iter, sub;
3840         dbus_bool_t runtime;
3841         DBusError error;
3842         char **i;
3843         int r;
3844
3845         dbus_error_init(&error);
3846
3847         m = dbus_message_new_method_call(
3848                         "org.freedesktop.systemd1",
3849                         "/org/freedesktop/systemd1",
3850                         "org.freedesktop.systemd1.Manager",
3851                         "SetUnitProperties");
3852         if (!m)
3853                 return log_oom();
3854
3855         dbus_message_iter_init_append(m, &iter);
3856
3857         runtime = arg_runtime;
3858
3859         n = unit_name_mangle(args[1]);
3860         if (!n)
3861                 return log_oom();
3862
3863         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
3864             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &runtime) ||
3865             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
3866                 return log_oom();
3867
3868         STRV_FOREACH(i, args + 2) {
3869                 DBusMessageIter sub2;
3870
3871                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
3872                         return log_oom();
3873
3874                 r = append_assignment(&sub2, *i);
3875                 if (r < 0)
3876                         return r;
3877
3878                 if (!dbus_message_iter_close_container(&sub, &sub2))
3879                         return log_oom();
3880
3881         }
3882
3883         if (!dbus_message_iter_close_container(&iter, &sub))
3884                 return log_oom();
3885
3886         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3887         if (!reply) {
3888                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3889                 dbus_error_free(&error);
3890                 return -EIO;
3891         }
3892
3893         return 0;
3894 }
3895
3896 static int snapshot(DBusConnection *bus, char **args) {
3897         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3898         DBusError error;
3899         int r;
3900         dbus_bool_t cleanup = FALSE;
3901         DBusMessageIter iter, sub;
3902         const char
3903                 *path, *id,
3904                 *interface = "org.freedesktop.systemd1.Unit",
3905                 *property = "Id";
3906         _cleanup_free_ char *n = NULL;
3907
3908         dbus_error_init(&error);
3909
3910         if (strv_length(args) > 1)
3911                 n = unit_name_mangle_with_suffix(args[1], ".snapshot");
3912         else
3913                 n = strdup("");
3914         if (!n)
3915                 return log_oom();
3916
3917         r = bus_method_call_with_reply(
3918                         bus,
3919                         "org.freedesktop.systemd1",
3920                         "/org/freedesktop/systemd1",
3921                         "org.freedesktop.systemd1.Manager",
3922                         "CreateSnapshot",
3923                         &reply,
3924                         NULL,
3925                         DBUS_TYPE_STRING, &n,
3926                         DBUS_TYPE_BOOLEAN, &cleanup,
3927                         DBUS_TYPE_INVALID);
3928         if (r < 0)
3929                 return r;
3930
3931         if (!dbus_message_get_args(reply, &error,
3932                                    DBUS_TYPE_OBJECT_PATH, &path,
3933                                    DBUS_TYPE_INVALID)) {
3934                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3935                 dbus_error_free(&error);
3936                 return -EIO;
3937         }
3938
3939         dbus_message_unref(reply);
3940         reply = NULL;
3941
3942         r = bus_method_call_with_reply (
3943                         bus,
3944                         "org.freedesktop.systemd1",
3945                         path,
3946                         "org.freedesktop.DBus.Properties",
3947                         "Get",
3948                         &reply,
3949                         NULL,
3950                         DBUS_TYPE_STRING, &interface,
3951                         DBUS_TYPE_STRING, &property,
3952                         DBUS_TYPE_INVALID);
3953         if (r < 0)
3954                 return r;
3955
3956         if (!dbus_message_iter_init(reply, &iter) ||
3957             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3958                 log_error("Failed to parse reply.");
3959                 return -EIO;
3960         }
3961
3962         dbus_message_iter_recurse(&iter, &sub);
3963
3964         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3965                 log_error("Failed to parse reply.");
3966                 return -EIO;
3967         }
3968
3969         dbus_message_iter_get_basic(&sub, &id);
3970
3971         if (!arg_quiet)
3972                 puts(id);
3973
3974         return 0;
3975 }
3976
3977 static int delete_snapshot(DBusConnection *bus, char **args) {
3978         char **name;
3979
3980         assert(args);
3981
3982         STRV_FOREACH(name, args+1) {
3983                 _cleanup_free_ char *n = NULL;
3984                 int r;
3985
3986                 n = unit_name_mangle_with_suffix(*name, ".snapshot");
3987                 if (!n)
3988                         return log_oom();
3989
3990                 r = bus_method_call_with_reply(
3991                                 bus,
3992                                 "org.freedesktop.systemd1",
3993                                 "/org/freedesktop/systemd1",
3994                                 "org.freedesktop.systemd1.Manager",
3995                                 "RemoveSnapshot",
3996                                 NULL,
3997                                 NULL,
3998                                 DBUS_TYPE_STRING, &n,
3999                                 DBUS_TYPE_INVALID);
4000                 if (r < 0)
4001                         return r;
4002         }
4003
4004         return 0;
4005 }
4006
4007 static int daemon_reload(DBusConnection *bus, char **args) {
4008         int r;
4009         const char *method;
4010         DBusError error;
4011
4012         if (arg_action == ACTION_RELOAD)
4013                 method = "Reload";
4014         else if (arg_action == ACTION_REEXEC)
4015                 method = "Reexecute";
4016         else {
4017                 assert(arg_action == ACTION_SYSTEMCTL);
4018
4019                 method =
4020                         streq(args[0], "clear-jobs")    ||
4021                         streq(args[0], "cancel")        ? "ClearJobs" :
4022                         streq(args[0], "daemon-reexec") ? "Reexecute" :
4023                         streq(args[0], "reset-failed")  ? "ResetFailed" :
4024                         streq(args[0], "halt")          ? "Halt" :
4025                         streq(args[0], "poweroff")      ? "PowerOff" :
4026                         streq(args[0], "reboot")        ? "Reboot" :
4027                         streq(args[0], "kexec")         ? "KExec" :
4028                         streq(args[0], "exit")          ? "Exit" :
4029                                     /* "daemon-reload" */ "Reload";
4030         }
4031
4032         r = bus_method_call_with_reply(
4033                         bus,
4034                         "org.freedesktop.systemd1",
4035                         "/org/freedesktop/systemd1",
4036                         "org.freedesktop.systemd1.Manager",
4037                         method,
4038                         NULL,
4039                         &error,
4040                         DBUS_TYPE_INVALID);
4041
4042         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4043                 /* There's always a fallback possible for
4044                  * legacy actions. */
4045                 r = -EADDRNOTAVAIL;
4046         else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4047                 /* On reexecution, we expect a disconnect, not a
4048                  * reply */
4049                 r = 0;
4050         else if (r < 0)
4051                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4052
4053         dbus_error_free(&error);
4054         return r;
4055 }
4056
4057 static int reset_failed(DBusConnection *bus, char **args) {
4058         int r = 0;
4059         char **name;
4060
4061         if (strv_length(args) <= 1)
4062                 return daemon_reload(bus, args);
4063
4064         STRV_FOREACH(name, args+1) {
4065                 _cleanup_free_ char *n;
4066
4067                 n = unit_name_mangle(*name);
4068                 if (!n)
4069                         return log_oom();
4070
4071                 r = bus_method_call_with_reply(
4072                                 bus,
4073                                 "org.freedesktop.systemd1",
4074                                 "/org/freedesktop/systemd1",
4075                                 "org.freedesktop.systemd1.Manager",
4076                                 "ResetFailedUnit",
4077                                 NULL,
4078                                 NULL,
4079                                 DBUS_TYPE_STRING, &n,
4080                                 DBUS_TYPE_INVALID);
4081                 if (r < 0)
4082                         return r;
4083         }
4084
4085         return 0;
4086 }
4087
4088 static int show_enviroment(DBusConnection *bus, char **args) {
4089         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
4090         DBusMessageIter iter, sub, sub2;
4091         int r;
4092         const char
4093                 *interface = "org.freedesktop.systemd1.Manager",
4094                 *property = "Environment";
4095
4096         pager_open_if_enabled();
4097
4098         r = bus_method_call_with_reply(
4099                         bus,
4100                         "org.freedesktop.systemd1",
4101                         "/org/freedesktop/systemd1",
4102                         "org.freedesktop.DBus.Properties",
4103                         "Get",
4104                         &reply,
4105                         NULL,
4106                         DBUS_TYPE_STRING, &interface,
4107                         DBUS_TYPE_STRING, &property,
4108                         DBUS_TYPE_INVALID);
4109         if (r < 0)
4110                 return r;
4111
4112         if (!dbus_message_iter_init(reply, &iter) ||
4113             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
4114                 log_error("Failed to parse reply.");
4115                 return -EIO;
4116         }
4117
4118         dbus_message_iter_recurse(&iter, &sub);
4119
4120         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
4121             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
4122                 log_error("Failed to parse reply.");
4123                 return -EIO;
4124         }
4125
4126         dbus_message_iter_recurse(&sub, &sub2);
4127
4128         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
4129                 const char *text;
4130
4131                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
4132                         log_error("Failed to parse reply.");
4133                         return -EIO;
4134                 }
4135
4136                 dbus_message_iter_get_basic(&sub2, &text);
4137                 puts(text);
4138
4139                 dbus_message_iter_next(&sub2);
4140         }
4141
4142         return 0;
4143 }
4144
4145 static int switch_root(DBusConnection *bus, char **args) {
4146         unsigned l;
4147         const char *root;
4148         _cleanup_free_ char *init = NULL;
4149
4150         l = strv_length(args);
4151         if (l < 2 || l > 3) {
4152                 log_error("Wrong number of arguments.");
4153                 return -EINVAL;
4154         }
4155
4156         root = args[1];
4157
4158         if (l >= 3)
4159                 init = strdup(args[2]);
4160         else {
4161                 parse_env_file("/proc/cmdline", WHITESPACE,
4162                                "init", &init,
4163                                NULL);
4164
4165                 if (!init)
4166                         init = strdup("");
4167         }
4168         if (!init)
4169                 return log_oom();
4170
4171         log_debug("switching root - root: %s; init: %s", root, init);
4172
4173         return bus_method_call_with_reply(
4174                         bus,
4175                         "org.freedesktop.systemd1",
4176                         "/org/freedesktop/systemd1",
4177                         "org.freedesktop.systemd1.Manager",
4178                         "SwitchRoot",
4179                         NULL,
4180                         NULL,
4181                         DBUS_TYPE_STRING, &root,
4182                         DBUS_TYPE_STRING, &init,
4183                         DBUS_TYPE_INVALID);
4184 }
4185
4186 static int set_environment(DBusConnection *bus, char **args) {
4187         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4188         DBusError error;
4189         const char *method;
4190         DBusMessageIter iter;
4191         int r;
4192
4193         assert(bus);
4194         assert(args);
4195
4196         dbus_error_init(&error);
4197
4198         method = streq(args[0], "set-environment")
4199                 ? "SetEnvironment"
4200                 : "UnsetEnvironment";
4201
4202         m = dbus_message_new_method_call(
4203                         "org.freedesktop.systemd1",
4204                         "/org/freedesktop/systemd1",
4205                         "org.freedesktop.systemd1.Manager",
4206                         method);
4207         if (!m)
4208                 return log_oom();
4209
4210         dbus_message_iter_init_append(m, &iter);
4211
4212         r = bus_append_strv_iter(&iter, args + 1);
4213         if (r < 0)
4214                 return log_oom();
4215
4216         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4217         if (!reply) {
4218                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4219                 dbus_error_free(&error);
4220                 return -EIO;
4221         }
4222
4223         return 0;
4224 }
4225
4226 static int enable_sysv_units(const char *verb, char **args) {
4227         int r = 0;
4228
4229 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
4230         unsigned f = 1, t = 1;
4231         _cleanup_lookup_paths_free_ LookupPaths paths = {};
4232
4233         if (arg_scope != UNIT_FILE_SYSTEM)
4234                 return 0;
4235
4236         if (!streq(verb, "enable") &&
4237             !streq(verb, "disable") &&
4238             !streq(verb, "is-enabled"))
4239                 return 0;
4240
4241         /* Processes all SysV units, and reshuffles the array so that
4242          * afterwards only the native units remain */
4243
4244         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
4245         if (r < 0)
4246                 return r;
4247
4248         r = 0;
4249         for (f = 0; args[f]; f++) {
4250                 const char *name;
4251                 _cleanup_free_ char *p = NULL, *q = NULL;
4252                 bool found_native = false, found_sysv;
4253                 unsigned c = 1;
4254                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4255                 char **k, *l;
4256                 int j;
4257                 pid_t pid;
4258                 siginfo_t status;
4259
4260                 name = args[f];
4261
4262                 if (!endswith(name, ".service"))
4263                         continue;
4264
4265                 if (path_is_absolute(name))
4266                         continue;
4267
4268                 STRV_FOREACH(k, paths.unit_path) {
4269                         if (!isempty(arg_root))
4270                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4271                         else
4272                                 asprintf(&p, "%s/%s", *k, name);
4273
4274                         if (!p) {
4275                                 r = log_oom();
4276                                 goto finish;
4277                         }
4278
4279                         found_native = access(p, F_OK) >= 0;
4280                         free(p);
4281                         p = NULL;
4282
4283                         if (found_native)
4284                                 break;
4285                 }
4286
4287                 if (found_native)
4288                         continue;
4289
4290                 if (!isempty(arg_root))
4291                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4292                 else
4293                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4294                 if (!p) {
4295                         r = log_oom();
4296                         goto finish;
4297                 }
4298
4299                 p[strlen(p) - sizeof(".service") + 1] = 0;
4300                 found_sysv = access(p, F_OK) >= 0;
4301
4302                 if (!found_sysv)
4303                         continue;
4304
4305                 /* Mark this entry, so that we don't try enabling it as native unit */
4306                 args[f] = (char*) "";
4307
4308                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
4309
4310                 if (!isempty(arg_root))
4311                         argv[c++] = q = strappend("--root=", arg_root);
4312
4313                 argv[c++] = path_get_file_name(p);
4314                 argv[c++] =
4315                         streq(verb, "enable") ? "on" :
4316                         streq(verb, "disable") ? "off" : "--level=5";
4317                 argv[c] = NULL;
4318
4319                 l = strv_join((char**)argv, " ");
4320                 if (!l) {
4321                         r = log_oom();
4322                         goto finish;
4323                 }
4324
4325                 log_info("Executing %s", l);
4326                 free(l);
4327
4328                 pid = fork();
4329                 if (pid < 0) {
4330                         log_error("Failed to fork: %m");
4331                         r = -errno;
4332                         goto finish;
4333                 } else if (pid == 0) {
4334                         /* Child */
4335
4336                         execv(argv[0], (char**) argv);
4337                         _exit(EXIT_FAILURE);
4338                 }
4339
4340                 j = wait_for_terminate(pid, &status);
4341                 if (j < 0) {
4342                         log_error("Failed to wait for child: %s", strerror(-r));
4343                         r = j;
4344                         goto finish;
4345                 }
4346
4347                 if (status.si_code == CLD_EXITED) {
4348                         if (streq(verb, "is-enabled")) {
4349                                 if (status.si_status == 0) {
4350                                         if (!arg_quiet)
4351                                                 puts("enabled");
4352                                         r = 1;
4353                                 } else {
4354                                         if (!arg_quiet)
4355                                                 puts("disabled");
4356                                 }
4357
4358                         } else if (status.si_status != 0) {
4359                                 r = -EINVAL;
4360                                 goto finish;
4361                         }
4362                 } else {
4363                         r = -EPROTO;
4364                         goto finish;
4365                 }
4366         }
4367
4368 finish:
4369         /* Drop all SysV units */
4370         for (f = 0, t = 0; args[f]; f++) {
4371
4372                 if (isempty(args[f]))
4373                         continue;
4374
4375                 args[t++] = args[f];
4376         }
4377
4378         args[t] = NULL;
4379
4380 #endif
4381         return r;
4382 }
4383
4384 static int mangle_names(char **original_names, char ***mangled_names) {
4385         char **i, **l, **name;
4386
4387         l = new(char*, strv_length(original_names) + 1);
4388         if (!l)
4389                 return log_oom();
4390
4391         i = l;
4392         STRV_FOREACH(name, original_names) {
4393
4394                 /* When enabling units qualified path names are OK,
4395                  * too, hence allow them explicitly. */
4396
4397                 if (is_path(*name))
4398                         *i = strdup(*name);
4399                 else
4400                         *i = unit_name_mangle(*name);
4401
4402                 if (!*i) {
4403                         strv_free(l);
4404                         return log_oom();
4405                 }
4406
4407                 i++;
4408         }
4409
4410         *i = NULL;
4411         *mangled_names = l;
4412
4413         return 0;
4414 }
4415
4416 static int enable_unit(DBusConnection *bus, char **args) {
4417         const char *verb = args[0];
4418         UnitFileChange *changes = NULL;
4419         unsigned n_changes = 0, i;
4420         int carries_install_info = -1;
4421         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4422         int r;
4423         _cleanup_dbus_error_free_ DBusError error;
4424         _cleanup_strv_free_ char **mangled_names = NULL;
4425
4426         dbus_error_init(&error);
4427
4428         if (!args[1])
4429                 return 0;
4430
4431         r = mangle_names(args+1, &mangled_names);
4432         if (r < 0)
4433                 return r;
4434
4435         r = enable_sysv_units(verb, mangled_names);
4436         if (r < 0)
4437                 return r;
4438
4439         if (!bus || avoid_bus()) {
4440                 if (streq(verb, "enable")) {
4441                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4442                         carries_install_info = r;
4443                 } else if (streq(verb, "disable"))
4444                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
4445                 else if (streq(verb, "reenable")) {
4446                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4447                         carries_install_info = r;
4448                 } else if (streq(verb, "link"))
4449                         r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4450                 else if (streq(verb, "preset")) {
4451                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4452                         carries_install_info = r;
4453                 } else if (streq(verb, "mask"))
4454                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4455                 else if (streq(verb, "unmask"))
4456                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
4457                 else if (streq(verb, "set-default"))
4458                         r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
4459                 else
4460                         assert_not_reached("Unknown verb");
4461
4462                 if (r < 0) {
4463                         log_error("Operation failed: %s", strerror(-r));
4464                         goto finish;
4465                 }
4466
4467                 if (!arg_quiet) {
4468                         for (i = 0; i < n_changes; i++) {
4469                                 if (changes[i].type == UNIT_FILE_SYMLINK)
4470                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4471                                 else
4472                                         log_info("rm '%s'", changes[i].path);
4473                         }
4474                 }
4475
4476                 r = 0;
4477         } else {
4478                 const char *method;
4479                 bool send_force = true, expect_carries_install_info = false;
4480                 dbus_bool_t a, b;
4481                 DBusMessageIter iter, sub, sub2;
4482
4483                 if (streq(verb, "enable")) {
4484                         method = "EnableUnitFiles";
4485                         expect_carries_install_info = true;
4486                 } else if (streq(verb, "disable")) {
4487                         method = "DisableUnitFiles";
4488                         send_force = false;
4489                 } else if (streq(verb, "reenable")) {
4490                         method = "ReenableUnitFiles";
4491                         expect_carries_install_info = true;
4492                 } else if (streq(verb, "link"))
4493                         method = "LinkUnitFiles";
4494                 else if (streq(verb, "preset")) {
4495                         method = "PresetUnitFiles";
4496                         expect_carries_install_info = true;
4497                 } else if (streq(verb, "mask"))
4498                         method = "MaskUnitFiles";
4499                 else if (streq(verb, "unmask")) {
4500                         method = "UnmaskUnitFiles";
4501                         send_force = false;
4502                 } else if (streq(verb, "set-default")) {
4503                         method = "SetDefaultTarget";
4504                 } else
4505                         assert_not_reached("Unknown verb");
4506
4507                 m = dbus_message_new_method_call(
4508                                 "org.freedesktop.systemd1",
4509                                 "/org/freedesktop/systemd1",
4510                                 "org.freedesktop.systemd1.Manager",
4511                                 method);
4512                 if (!m) {
4513                         r = log_oom();
4514                         goto finish;
4515                 }
4516
4517                 dbus_message_iter_init_append(m, &iter);
4518
4519                 r = bus_append_strv_iter(&iter, mangled_names);
4520                 if (r < 0) {
4521                         log_error("Failed to append unit files.");
4522                         goto finish;
4523                 }
4524
4525                 a = arg_runtime;
4526                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4527                         log_error("Failed to append runtime boolean.");
4528                         r = -ENOMEM;
4529                         goto finish;
4530                 }
4531
4532                 if (send_force) {
4533                         b = arg_force;
4534
4535                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4536                                 log_error("Failed to append force boolean.");
4537                                 r = -ENOMEM;
4538                                 goto finish;
4539                         }
4540                 }
4541
4542                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4543                 if (!reply) {
4544                         log_error("Failed to issue method call: %s", bus_error_message(&error));
4545                         r = -EIO;
4546                         goto finish;
4547                 }
4548
4549                 if (!dbus_message_iter_init(reply, &iter)) {
4550                         log_error("Failed to initialize iterator.");
4551                         goto finish;
4552                 }
4553
4554                 if (expect_carries_install_info) {
4555                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4556                         if (r < 0) {
4557                                 log_error("Failed to parse reply.");
4558                                 goto finish;
4559                         }
4560
4561                         carries_install_info = b;
4562                 }
4563
4564                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4565                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4566                         log_error("Failed to parse reply.");
4567                         r = -EIO;
4568                         goto finish;
4569                 }
4570
4571                 dbus_message_iter_recurse(&iter, &sub);
4572                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4573                         const char *type, *path, *source;
4574
4575                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4576                                 log_error("Failed to parse reply.");
4577                                 r = -EIO;
4578                                 goto finish;
4579                         }
4580
4581                         dbus_message_iter_recurse(&sub, &sub2);
4582
4583                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4584                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4585                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4586                                 log_error("Failed to parse reply.");
4587                                 r = -EIO;
4588                                 goto finish;
4589                         }
4590
4591                         if (!arg_quiet) {
4592                                 if (streq(type, "symlink"))
4593                                         log_info("ln -s '%s' '%s'", source, path);
4594                                 else
4595                                         log_info("rm '%s'", path);
4596                         }
4597
4598                         dbus_message_iter_next(&sub);
4599                 }
4600
4601                 /* Try to reload if enabeld */
4602                 if (!arg_no_reload)
4603                         r = daemon_reload(bus, args);
4604         }
4605
4606         if (carries_install_info == 0)
4607                 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4608                             "using systemctl.\n"
4609                             "Possible reasons for having this kind of units are:\n"
4610                             "1) A unit may be statically enabled by being symlinked from another unit's\n"
4611                             "   .wants/ or .requires/ directory.\n"
4612                             "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4613                             "   a requirement dependency on it.\n"
4614                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
4615                             "   D-Bus, udev, scripted systemctl call, ...).\n");
4616
4617 finish:
4618         unit_file_changes_free(changes, n_changes);
4619
4620         return r;
4621 }
4622
4623 static int unit_is_enabled(DBusConnection *bus, char **args) {
4624         _cleanup_dbus_error_free_ DBusError error;
4625         int r;
4626         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
4627         bool enabled;
4628         char **name;
4629         _cleanup_strv_free_ char **mangled_names = NULL;
4630
4631         dbus_error_init(&error);
4632
4633         r = mangle_names(args+1, &mangled_names);
4634         if (r < 0)
4635                 return r;
4636
4637         r = enable_sysv_units(args[0], mangled_names);
4638         if (r < 0)
4639                 return r;
4640
4641         enabled = r > 0;
4642
4643         if (!bus || avoid_bus()) {
4644
4645                 STRV_FOREACH(name, mangled_names) {
4646                         UnitFileState state;
4647
4648                         state = unit_file_get_state(arg_scope, arg_root, *name);
4649
4650                         if (state < 0)
4651                                 return state;
4652
4653                         if (state == UNIT_FILE_ENABLED ||
4654                             state == UNIT_FILE_ENABLED_RUNTIME ||
4655                             state == UNIT_FILE_STATIC)
4656                                 enabled = true;
4657
4658                         if (!arg_quiet)
4659                                 puts(unit_file_state_to_string(state));
4660                 }
4661
4662         } else {
4663                 STRV_FOREACH(name, mangled_names) {
4664                         const char *s;
4665
4666                         r = bus_method_call_with_reply (
4667                                         bus,
4668                                         "org.freedesktop.systemd1",
4669                                         "/org/freedesktop/systemd1",
4670                                         "org.freedesktop.systemd1.Manager",
4671                                         "GetUnitFileState",
4672                                         &reply,
4673                                         NULL,
4674                                         DBUS_TYPE_STRING, name,
4675                                         DBUS_TYPE_INVALID);
4676
4677                         if (r)
4678                                 return r;
4679
4680                         if (!dbus_message_get_args(reply, &error,
4681                                                    DBUS_TYPE_STRING, &s,
4682                                                    DBUS_TYPE_INVALID)) {
4683                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4684                                 return -EIO;
4685                         }
4686
4687                         dbus_message_unref(reply);
4688                         reply = NULL;
4689
4690                         if (streq(s, "enabled") ||
4691                             streq(s, "enabled-runtime") ||
4692                             streq(s, "static"))
4693                                 enabled = true;
4694
4695                         if (!arg_quiet)
4696                                 puts(s);
4697                 }
4698         }
4699
4700         return enabled ? 0 : 1;
4701 }
4702
4703 static int systemctl_help(void) {
4704
4705         pager_open_if_enabled();
4706
4707         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4708                "Query or send control commands to the systemd manager.\n\n"
4709                "  -h --help           Show this help\n"
4710                "     --version        Show package version\n"
4711                "  -t --type=TYPE      List only units of a particular type\n"
4712                "     --state=STATE    List only units with particular LOAD or SUB or ACTIVE state\n"
4713                "  -p --property=NAME  Show only properties by this name\n"
4714                "  -a --all            Show all loaded units/properties, including dead/empty\n"
4715                "                      ones. To list all units installed on the system, use\n"
4716                "                      the 'list-unit-files' command instead.\n"
4717                "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
4718                "  -l --full           Don't ellipsize unit names on output\n"
4719                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4720                "                      pending\n"
4721                "     --irreversible   When queueing a new job, make sure it cannot be implicitly\n"
4722                "                      cancelled\n"
4723                "     --ignore-dependencies\n"
4724                "                      When queueing a new job, ignore all its dependencies\n"
4725                "     --show-types     When showing sockets, explicitly show their type\n"
4726                "  -i --ignore-inhibitors\n"
4727                "                      When shutting down or sleeping, ignore inhibitors\n"
4728                "     --kill-who=WHO   Who to send signal to\n"
4729                "  -s --signal=SIGNAL  Which signal to send\n"
4730                "  -H --host=[USER@]HOST\n"
4731                "                      Show information for remote host\n"
4732                "  -P --privileged     Acquire privileges before execution\n"
4733                "  -q --quiet          Suppress output\n"
4734                "     --no-block       Do not wait until operation finished\n"
4735                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4736                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4737                "                      configuration\n"
4738                "     --no-legend      Do not print a legend (column headers and hints)\n"
4739                "     --no-pager       Do not pipe output into a pager\n"
4740                "     --no-ask-password\n"
4741                "                      Do not ask for system passwords\n"
4742                "     --system         Connect to system manager\n"
4743                "     --user           Connect to user service manager\n"
4744                "     --global         Enable/disable unit files globally\n"
4745                "     --runtime        Enable unit files only temporarily until next reboot\n"
4746                "  -f --force          When enabling unit files, override existing symlinks\n"
4747                "                      When shutting down, execute action immediately\n"
4748                "     --root=PATH      Enable unit files in the specified root directory\n"
4749                "  -n --lines=INTEGER  Number of journal entries to show\n"
4750                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4751                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
4752                "Unit Commands:\n"
4753                "  list-units                      List loaded units\n"
4754                "  list-sockets                    List loaded sockets ordered by address\n"
4755                "  start [NAME...]                 Start (activate) one or more units\n"
4756                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4757                "  reload [NAME...]                Reload one or more units\n"
4758                "  restart [NAME...]               Start or restart one or more units\n"
4759                "  try-restart [NAME...]           Restart one or more units if active\n"
4760                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
4761                "                                  otherwise start or restart\n"
4762                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
4763                "                                  otherwise restart if active\n"
4764                "  isolate [NAME]                  Start one unit and stop all others\n"
4765                "  kill [NAME...]                  Send signal to processes of a unit\n"
4766                "  is-active [NAME...]             Check whether units are active\n"
4767                "  is-failed [NAME...]             Check whether units are failed\n"
4768                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4769                "  show [NAME...|JOB...]           Show properties of one or more\n"
4770                "                                  units/jobs or the manager\n"
4771                "  set-property [NAME] [ASSIGNMENT...]\n"
4772                "                                  Sets one or more properties of a unit\n"
4773                "  help [NAME...|PID...]           Show manual for one or more units\n"
4774                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4775                "                                  units\n"
4776                "  list-dependencies [NAME]        Recursively show units which are required\n"
4777                "                                  or wanted by this unit or by which this\n"
4778                "                                  unit is required or wanted\n\n"
4779                "Unit File Commands:\n"
4780                "  list-unit-files                 List installed unit files\n"
4781                "  enable [NAME...]                Enable one or more unit files\n"
4782                "  disable [NAME...]               Disable one or more unit files\n"
4783                "  reenable [NAME...]              Reenable one or more unit files\n"
4784                "  preset [NAME...]                Enable/disable one or more unit files\n"
4785                "                                  based on preset configuration\n"
4786                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4787                "  mask [NAME...]                  Mask one or more units\n"
4788                "  unmask [NAME...]                Unmask one or more units\n"
4789                "  link [PATH...]                  Link one or more units files into\n"
4790                "                                  the search path\n"
4791                "  get-default                     Get the name of the default target\n"
4792                "  set-default NAME                Set the default target\n\n"
4793                "Job Commands:\n"
4794                "  list-jobs                       List jobs\n"
4795                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4796                "Snapshot Commands:\n"
4797                "  snapshot [NAME]                 Create a snapshot\n"
4798                "  delete [NAME...]                Remove one or more snapshots\n\n"
4799                "Environment Commands:\n"
4800                "  show-environment                Dump environment\n"
4801                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4802                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4803                "Manager Lifecycle Commands:\n"
4804                "  daemon-reload                   Reload systemd manager configuration\n"
4805                "  daemon-reexec                   Reexecute systemd manager\n\n"
4806                "System Commands:\n"
4807                "  default                         Enter system default mode\n"
4808                "  rescue                          Enter system rescue mode\n"
4809                "  emergency                       Enter system emergency mode\n"
4810                "  halt                            Shut down and halt the system\n"
4811                "  poweroff                        Shut down and power-off the system\n"
4812                "  reboot [ARG]                    Shut down and reboot the system\n"
4813                "  kexec                           Shut down and reboot the system with kexec\n"
4814                "  exit                            Request user instance exit\n"
4815                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4816                "  suspend                         Suspend the system\n"
4817                "  hibernate                       Hibernate the system\n"
4818                "  hybrid-sleep                    Hibernate and suspend the system\n",
4819                program_invocation_short_name);
4820
4821         return 0;
4822 }
4823
4824 static int halt_help(void) {
4825
4826         printf("%s [OPTIONS...]%s\n\n"
4827                "%s the system.\n\n"
4828                "     --help      Show this help\n"
4829                "     --halt      Halt the machine\n"
4830                "  -p --poweroff  Switch off the machine\n"
4831                "     --reboot    Reboot the machine\n"
4832                "  -f --force     Force immediate halt/power-off/reboot\n"
4833                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4834                "  -d --no-wtmp   Don't write wtmp record\n"
4835                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4836                program_invocation_short_name,
4837                arg_action == ACTION_REBOOT   ? " [ARG]" : "",
4838                arg_action == ACTION_REBOOT   ? "Reboot" :
4839                arg_action == ACTION_POWEROFF ? "Power off" :
4840                                                "Halt");
4841
4842         return 0;
4843 }
4844
4845 static int shutdown_help(void) {
4846
4847         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4848                "Shut down the system.\n\n"
4849                "     --help      Show this help\n"
4850                "  -H --halt      Halt the machine\n"
4851                "  -P --poweroff  Power-off the machine\n"
4852                "  -r --reboot    Reboot the machine\n"
4853                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4854                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4855                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4856                "  -c             Cancel a pending shutdown\n",
4857                program_invocation_short_name);
4858
4859         return 0;
4860 }
4861
4862 static int telinit_help(void) {
4863
4864         printf("%s [OPTIONS...] {COMMAND}\n\n"
4865                "Send control commands to the init daemon.\n\n"
4866                "     --help      Show this help\n"
4867                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4868                "Commands:\n"
4869                "  0              Power-off the machine\n"
4870                "  6              Reboot the machine\n"
4871                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4872                "  1, s, S        Enter rescue mode\n"
4873                "  q, Q           Reload init daemon configuration\n"
4874                "  u, U           Reexecute init daemon\n",
4875                program_invocation_short_name);
4876
4877         return 0;
4878 }
4879
4880 static int runlevel_help(void) {
4881
4882         printf("%s [OPTIONS...]\n\n"
4883                "Prints the previous and current runlevel of the init system.\n\n"
4884                "     --help      Show this help\n",
4885                program_invocation_short_name);
4886
4887         return 0;
4888 }
4889
4890 static int help_types(void) {
4891         int i;
4892         const char *t;
4893
4894         puts("Available unit types:");
4895         for(i = 0; i < _UNIT_TYPE_MAX; i++) {
4896                 t = unit_type_to_string(i);
4897                 if (t)
4898                         puts(t);
4899         }
4900
4901         return 0;
4902 }
4903
4904 static int systemctl_parse_argv(int argc, char *argv[]) {
4905
4906         enum {
4907                 ARG_FAIL = 0x100,
4908                 ARG_REVERSE,
4909                 ARG_AFTER,
4910                 ARG_BEFORE,
4911                 ARG_SHOW_TYPES,
4912                 ARG_IRREVERSIBLE,
4913                 ARG_IGNORE_DEPENDENCIES,
4914                 ARG_VERSION,
4915                 ARG_USER,
4916                 ARG_SYSTEM,
4917                 ARG_GLOBAL,
4918                 ARG_NO_BLOCK,
4919                 ARG_NO_LEGEND,
4920                 ARG_NO_PAGER,
4921                 ARG_NO_WALL,
4922                 ARG_ROOT,
4923                 ARG_NO_RELOAD,
4924                 ARG_KILL_WHO,
4925                 ARG_NO_ASK_PASSWORD,
4926                 ARG_FAILED,
4927                 ARG_RUNTIME,
4928                 ARG_FORCE,
4929                 ARG_PLAIN,
4930                 ARG_STATE
4931         };
4932
4933         static const struct option options[] = {
4934                 { "help",                no_argument,       NULL, 'h'                     },
4935                 { "version",             no_argument,       NULL, ARG_VERSION             },
4936                 { "type",                required_argument, NULL, 't'                     },
4937                 { "property",            required_argument, NULL, 'p'                     },
4938                 { "all",                 no_argument,       NULL, 'a'                     },
4939                 { "reverse",             no_argument,       NULL, ARG_REVERSE             },
4940                 { "after",               no_argument,       NULL, ARG_AFTER               },
4941                 { "before",              no_argument,       NULL, ARG_BEFORE              },
4942                 { "show-types",          no_argument,       NULL, ARG_SHOW_TYPES          },
4943                 { "failed",              no_argument,       NULL, ARG_FAILED              }, /* compatibility only */
4944                 { "full",                no_argument,       NULL, 'l'                     },
4945                 { "fail",                no_argument,       NULL, ARG_FAIL                },
4946                 { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        },
4947                 { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES },
4948                 { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
4949                 { "user",                no_argument,       NULL, ARG_USER                },
4950                 { "system",              no_argument,       NULL, ARG_SYSTEM              },
4951                 { "global",              no_argument,       NULL, ARG_GLOBAL              },
4952                 { "no-block",            no_argument,       NULL, ARG_NO_BLOCK            },
4953                 { "no-legend",           no_argument,       NULL, ARG_NO_LEGEND           },
4954                 { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
4955                 { "no-wall",             no_argument,       NULL, ARG_NO_WALL             },
4956                 { "quiet",               no_argument,       NULL, 'q'                     },
4957                 { "root",                required_argument, NULL, ARG_ROOT                },
4958                 { "force",               no_argument,       NULL, ARG_FORCE               },
4959                 { "no-reload",           no_argument,       NULL, ARG_NO_RELOAD           },
4960                 { "kill-who",            required_argument, NULL, ARG_KILL_WHO            },
4961                 { "signal",              required_argument, NULL, 's'                     },
4962                 { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
4963                 { "host",                required_argument, NULL, 'H'                     },
4964                 { "privileged",          no_argument,       NULL, 'P'                     },
4965                 { "runtime",             no_argument,       NULL, ARG_RUNTIME             },
4966                 { "lines",               required_argument, NULL, 'n'                     },
4967                 { "output",              required_argument, NULL, 'o'                     },
4968                 { "plain",               no_argument,       NULL, ARG_PLAIN               },
4969                 { "state",               required_argument, NULL, ARG_STATE               },
4970                 {}
4971         };
4972
4973         int c;
4974
4975         assert(argc >= 0);
4976         assert(argv);
4977
4978         while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:Pn:o:i", options, NULL)) >= 0) {
4979
4980                 switch (c) {
4981
4982                 case 'h':
4983                         return systemctl_help();
4984
4985                 case ARG_VERSION:
4986                         puts(PACKAGE_STRING);
4987                         puts(SYSTEMD_FEATURES);
4988                         return 0;
4989
4990                 case 't': {
4991                         char *word, *state;
4992                         size_t size;
4993
4994                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
4995                                 _cleanup_free_ char *type;
4996
4997                                 type = strndup(word, size);
4998                                 if (!type)
4999                                         return -ENOMEM;
5000
5001                                 if (streq(type, "help")) {
5002                                         help_types();
5003                                         return 0;
5004                                 }
5005
5006                                 if (unit_type_from_string(type) >= 0) {
5007                                         if (strv_push(&arg_types, type))
5008                                                 return log_oom();
5009                                         type = NULL;
5010                                         continue;
5011                                 }
5012
5013                                 /* It's much nicer to use --state= for
5014                                  * load states, but let's support this
5015                                  * in --types= too for compatibility
5016                                  * with old versions */
5017                                 if (unit_load_state_from_string(optarg) >= 0) {
5018                                         if (strv_push(&arg_states, type) < 0)
5019                                                 return log_oom();
5020                                         type = NULL;
5021                                         continue;
5022                                 }
5023
5024                                 log_error("Unknown unit type or load state '%s'.", type);
5025                                 log_info("Use -t help to see a list of allowed values.");
5026                                 return -EINVAL;
5027                         }
5028
5029                         break;
5030                 }
5031
5032                 case 'p': {
5033                         /* Make sure that if the empty property list
5034                            was specified, we won't show any properties. */
5035                         if (isempty(optarg) && !arg_properties) {
5036                                 arg_properties = strv_new(NULL, NULL);
5037                                 if (!arg_properties)
5038                                         return log_oom();
5039                         } else {
5040                                 char *word, *state;
5041                                 size_t size;
5042
5043                                 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5044                                         char *prop;
5045
5046                                         prop = strndup(word, size);
5047                                         if (!prop)
5048                                                 return log_oom();
5049
5050                                         if (strv_push(&arg_properties, prop) < 0) {
5051                                                 free(prop);
5052                                                 return log_oom();
5053                                         }
5054                                 }
5055                         }
5056
5057                         /* If the user asked for a particular
5058                          * property, show it to him, even if it is
5059                          * empty. */
5060                         arg_all = true;
5061
5062                         break;
5063                 }
5064
5065                 case 'a':
5066                         arg_all = true;
5067                         break;
5068
5069                 case ARG_REVERSE:
5070                         arg_dependency = DEPENDENCY_REVERSE;
5071                         break;
5072
5073                 case ARG_AFTER:
5074                         arg_dependency = DEPENDENCY_AFTER;
5075                         break;
5076
5077                 case ARG_BEFORE:
5078                         arg_dependency = DEPENDENCY_BEFORE;
5079                         break;
5080
5081                 case ARG_SHOW_TYPES:
5082                         arg_show_types = true;
5083                         break;
5084
5085                 case ARG_FAIL:
5086                         arg_job_mode = "fail";
5087                         break;
5088
5089                 case ARG_IRREVERSIBLE:
5090                         arg_job_mode = "replace-irreversibly";
5091                         break;
5092
5093                 case ARG_IGNORE_DEPENDENCIES:
5094                         arg_job_mode = "ignore-dependencies";
5095                         break;
5096
5097                 case ARG_USER:
5098                         arg_scope = UNIT_FILE_USER;
5099                         break;
5100
5101                 case ARG_SYSTEM:
5102                         arg_scope = UNIT_FILE_SYSTEM;
5103                         break;
5104
5105                 case ARG_GLOBAL:
5106                         arg_scope = UNIT_FILE_GLOBAL;
5107                         break;
5108
5109                 case ARG_NO_BLOCK:
5110                         arg_no_block = true;
5111                         break;
5112
5113                 case ARG_NO_LEGEND:
5114                         arg_no_legend = true;
5115                         break;
5116
5117                 case ARG_NO_PAGER:
5118                         arg_no_pager = true;
5119                         break;
5120
5121                 case ARG_NO_WALL:
5122                         arg_no_wall = true;
5123                         break;
5124
5125                 case ARG_ROOT:
5126                         arg_root = optarg;
5127                         break;
5128
5129                 case 'l':
5130                         arg_full = true;
5131                         break;
5132
5133                 case ARG_FAILED:
5134                         if (strv_extend(&arg_states, "failed") < 0)
5135                                 return log_oom();
5136
5137                         break;
5138
5139                 case 'q':
5140                         arg_quiet = true;
5141                         break;
5142
5143                 case ARG_FORCE:
5144                         arg_force ++;
5145                         break;
5146
5147                 case 'f':
5148                         arg_force ++;
5149                         break;
5150
5151                 case ARG_NO_RELOAD:
5152                         arg_no_reload = true;
5153                         break;
5154
5155                 case ARG_KILL_WHO:
5156                         arg_kill_who = optarg;
5157                         break;
5158
5159                 case 's':
5160                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5161                                 log_error("Failed to parse signal string %s.", optarg);
5162                                 return -EINVAL;
5163                         }
5164                         break;
5165
5166                 case ARG_NO_ASK_PASSWORD:
5167                         arg_ask_password = false;
5168                         break;
5169
5170                 case 'P':
5171                         arg_transport = TRANSPORT_POLKIT;
5172                         break;
5173
5174                 case 'H':
5175                         arg_transport = TRANSPORT_SSH;
5176                         parse_user_at_host(optarg, &arg_user, &arg_host);
5177                         break;
5178
5179                 case ARG_RUNTIME:
5180                         arg_runtime = true;
5181                         break;
5182
5183                 case 'n':
5184                         if (safe_atou(optarg, &arg_lines) < 0) {
5185                                 log_error("Failed to parse lines '%s'", optarg);
5186                                 return -EINVAL;
5187                         }
5188                         break;
5189
5190                 case 'o':
5191                         arg_output = output_mode_from_string(optarg);
5192                         if (arg_output < 0) {
5193                                 log_error("Unknown output '%s'.", optarg);
5194                                 return -EINVAL;
5195                         }
5196                         break;
5197
5198                 case 'i':
5199                         arg_ignore_inhibitors = true;
5200                         break;
5201
5202                 case ARG_PLAIN:
5203                         arg_plain = true;
5204                         break;
5205
5206                 case ARG_STATE: {
5207                         char *word, *state;
5208                         size_t size;
5209
5210                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5211                                 char *s;
5212
5213                                 s = strndup(word, size);
5214                                 if (!s)
5215                                         return log_oom();
5216
5217                                 if (strv_push(&arg_states, s) < 0) {
5218                                         free(s);
5219                                         return log_oom();
5220                                 }
5221                         }
5222                         break;
5223                 }
5224
5225                 case '?':
5226                         return -EINVAL;
5227
5228                 default:
5229                         assert_not_reached("Unhandled option");
5230                 }
5231         }
5232
5233         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
5234                 log_error("Cannot access user instance remotely.");
5235                 return -EINVAL;
5236         }
5237
5238         return 1;
5239 }
5240
5241 static int halt_parse_argv(int argc, char *argv[]) {
5242
5243         enum {
5244                 ARG_HELP = 0x100,
5245                 ARG_HALT,
5246                 ARG_REBOOT,
5247                 ARG_NO_WALL
5248         };
5249
5250         static const struct option options[] = {
5251                 { "help",      no_argument,       NULL, ARG_HELP    },
5252                 { "halt",      no_argument,       NULL, ARG_HALT    },
5253                 { "poweroff",  no_argument,       NULL, 'p'         },
5254                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
5255                 { "force",     no_argument,       NULL, 'f'         },
5256                 { "wtmp-only", no_argument,       NULL, 'w'         },
5257                 { "no-wtmp",   no_argument,       NULL, 'd'         },
5258                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5259                 {}
5260         };
5261
5262         int c, r, runlevel;
5263
5264         assert(argc >= 0);
5265         assert(argv);
5266
5267         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5268                 if (runlevel == '0' || runlevel == '6')
5269                         arg_force = 2;
5270
5271         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5272                 switch (c) {
5273
5274                 case ARG_HELP:
5275                         return halt_help();
5276
5277                 case ARG_HALT:
5278                         arg_action = ACTION_HALT;
5279                         break;
5280
5281                 case 'p':
5282                         if (arg_action != ACTION_REBOOT)
5283                                 arg_action = ACTION_POWEROFF;
5284                         break;
5285
5286                 case ARG_REBOOT:
5287                         arg_action = ACTION_REBOOT;
5288                         break;
5289
5290                 case 'f':
5291                         arg_force = 2;
5292                         break;
5293
5294                 case 'w':
5295                         arg_dry = true;
5296                         break;
5297
5298                 case 'd':
5299                         arg_no_wtmp = true;
5300                         break;
5301
5302                 case ARG_NO_WALL:
5303                         arg_no_wall = true;
5304                         break;
5305
5306                 case 'i':
5307                 case 'h':
5308                 case 'n':
5309                         /* Compatibility nops */
5310                         break;
5311
5312                 case '?':
5313                         return -EINVAL;
5314
5315                 default:
5316                         assert_not_reached("Unhandled option");
5317                 }
5318         }
5319
5320         if (arg_action == ACTION_REBOOT && argc == optind + 1) {
5321                 r = write_string_file(REBOOT_PARAM_FILE, argv[optind]);
5322                 if (r < 0) {
5323                         log_error("Failed to write reboot param to "
5324                                   REBOOT_PARAM_FILE": %s", strerror(-r));
5325                         return r;
5326                 }
5327         } else if (optind < argc) {
5328                 log_error("Too many arguments.");
5329                 return -EINVAL;
5330         }
5331
5332         return 1;
5333 }
5334
5335 static int parse_time_spec(const char *t, usec_t *_u) {
5336         assert(t);
5337         assert(_u);
5338
5339         if (streq(t, "now"))
5340                 *_u = 0;
5341         else if (!strchr(t, ':')) {
5342                 uint64_t u;
5343
5344                 if (safe_atou64(t, &u) < 0)
5345                         return -EINVAL;
5346
5347                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5348         } else {
5349                 char *e = NULL;
5350                 long hour, minute;
5351                 struct tm tm = {};
5352                 time_t s;
5353                 usec_t n;
5354
5355                 errno = 0;
5356                 hour = strtol(t, &e, 10);
5357                 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
5358                         return -EINVAL;
5359
5360                 minute = strtol(e+1, &e, 10);
5361                 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
5362                         return -EINVAL;
5363
5364                 n = now(CLOCK_REALTIME);
5365                 s = (time_t) (n / USEC_PER_SEC);
5366
5367                 assert_se(localtime_r(&s, &tm));
5368
5369                 tm.tm_hour = (int) hour;
5370                 tm.tm_min = (int) minute;
5371                 tm.tm_sec = 0;
5372
5373                 assert_se(s = mktime(&tm));
5374
5375                 *_u = (usec_t) s * USEC_PER_SEC;
5376
5377                 while (*_u <= n)
5378                         *_u += USEC_PER_DAY;
5379         }
5380
5381         return 0;
5382 }
5383
5384 static int shutdown_parse_argv(int argc, char *argv[]) {
5385
5386         enum {
5387                 ARG_HELP = 0x100,
5388                 ARG_NO_WALL
5389         };
5390
5391         static const struct option options[] = {
5392                 { "help",      no_argument,       NULL, ARG_HELP    },
5393                 { "halt",      no_argument,       NULL, 'H'         },
5394                 { "poweroff",  no_argument,       NULL, 'P'         },
5395                 { "reboot",    no_argument,       NULL, 'r'         },
5396                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
5397                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5398                 {}
5399         };
5400
5401         int c, r;
5402
5403         assert(argc >= 0);
5404         assert(argv);
5405
5406         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
5407                 switch (c) {
5408
5409                 case ARG_HELP:
5410                         return shutdown_help();
5411
5412                 case 'H':
5413                         arg_action = ACTION_HALT;
5414                         break;
5415
5416                 case 'P':
5417                         arg_action = ACTION_POWEROFF;
5418                         break;
5419
5420                 case 'r':
5421                         if (kexec_loaded())
5422                                 arg_action = ACTION_KEXEC;
5423                         else
5424                                 arg_action = ACTION_REBOOT;
5425                         break;
5426
5427                 case 'K':
5428                         arg_action = ACTION_KEXEC;
5429                         break;
5430
5431                 case 'h':
5432                         if (arg_action != ACTION_HALT)
5433                                 arg_action = ACTION_POWEROFF;
5434                         break;
5435
5436                 case 'k':
5437                         arg_dry = true;
5438                         break;
5439
5440                 case ARG_NO_WALL:
5441                         arg_no_wall = true;
5442                         break;
5443
5444                 case 't':
5445                 case 'a':
5446                         /* Compatibility nops */
5447                         break;
5448
5449                 case 'c':
5450                         arg_action = ACTION_CANCEL_SHUTDOWN;
5451                         break;
5452
5453                 case '?':
5454                         return -EINVAL;
5455
5456                 default:
5457                         assert_not_reached("Unhandled option");
5458                 }
5459         }
5460
5461         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
5462                 r = parse_time_spec(argv[optind], &arg_when);
5463                 if (r < 0) {
5464                         log_error("Failed to parse time specification: %s", argv[optind]);
5465                         return r;
5466                 }
5467         } else
5468                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
5469
5470         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5471                 /* No time argument for shutdown cancel */
5472                 arg_wall = argv + optind;
5473         else if (argc > optind + 1)
5474                 /* We skip the time argument */
5475                 arg_wall = argv + optind + 1;
5476
5477         optind = argc;
5478
5479         return 1;
5480 }
5481
5482 static int telinit_parse_argv(int argc, char *argv[]) {
5483
5484         enum {
5485                 ARG_HELP = 0x100,
5486                 ARG_NO_WALL
5487         };
5488
5489         static const struct option options[] = {
5490                 { "help",      no_argument,       NULL, ARG_HELP    },
5491                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5492                 {}
5493         };
5494
5495         static const struct {
5496                 char from;
5497                 enum action to;
5498         } table[] = {
5499                 { '0', ACTION_POWEROFF },
5500                 { '6', ACTION_REBOOT },
5501                 { '1', ACTION_RESCUE },
5502                 { '2', ACTION_RUNLEVEL2 },
5503                 { '3', ACTION_RUNLEVEL3 },
5504                 { '4', ACTION_RUNLEVEL4 },
5505                 { '5', ACTION_RUNLEVEL5 },
5506                 { 's', ACTION_RESCUE },
5507                 { 'S', ACTION_RESCUE },
5508                 { 'q', ACTION_RELOAD },
5509                 { 'Q', ACTION_RELOAD },
5510                 { 'u', ACTION_REEXEC },
5511                 { 'U', ACTION_REEXEC }
5512         };
5513
5514         unsigned i;
5515         int c;
5516
5517         assert(argc >= 0);
5518         assert(argv);
5519
5520         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5521                 switch (c) {
5522
5523                 case ARG_HELP:
5524                         return telinit_help();
5525
5526                 case ARG_NO_WALL:
5527                         arg_no_wall = true;
5528                         break;
5529
5530                 case '?':
5531                         return -EINVAL;
5532
5533                 default:
5534                         assert_not_reached("Unhandled option");
5535                 }
5536         }
5537
5538         if (optind >= argc) {
5539                 telinit_help();
5540                 return -EINVAL;
5541         }
5542
5543         if (optind + 1 < argc) {
5544                 log_error("Too many arguments.");
5545                 return -EINVAL;
5546         }
5547
5548         if (strlen(argv[optind]) != 1) {
5549                 log_error("Expected single character argument.");
5550                 return -EINVAL;
5551         }
5552
5553         for (i = 0; i < ELEMENTSOF(table); i++)
5554                 if (table[i].from == argv[optind][0])
5555                         break;
5556
5557         if (i >= ELEMENTSOF(table)) {
5558                 log_error("Unknown command '%s'.", argv[optind]);
5559                 return -EINVAL;
5560         }
5561
5562         arg_action = table[i].to;
5563
5564         optind ++;
5565
5566         return 1;
5567 }
5568
5569 static int runlevel_parse_argv(int argc, char *argv[]) {
5570
5571         enum {
5572                 ARG_HELP = 0x100,
5573         };
5574
5575         static const struct option options[] = {
5576                 { "help",      no_argument,       NULL, ARG_HELP    },
5577                 {}
5578         };
5579
5580         int c;
5581
5582         assert(argc >= 0);
5583         assert(argv);
5584
5585         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5586                 switch (c) {
5587
5588                 case ARG_HELP:
5589                         return runlevel_help();
5590                         return 0;
5591
5592                 case '?':
5593                         return -EINVAL;
5594
5595                 default:
5596                         assert_not_reached("Unhandled option");
5597                 }
5598         }
5599
5600         if (optind < argc) {
5601                 log_error("Too many arguments.");
5602                 return -EINVAL;
5603         }
5604
5605         return 1;
5606 }
5607
5608 static int parse_argv(int argc, char *argv[]) {
5609         assert(argc >= 0);
5610         assert(argv);
5611
5612         if (program_invocation_short_name) {
5613
5614                 if (strstr(program_invocation_short_name, "halt")) {
5615                         arg_action = ACTION_HALT;
5616                         return halt_parse_argv(argc, argv);
5617                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5618                         arg_action = ACTION_POWEROFF;
5619                         return halt_parse_argv(argc, argv);
5620                 } else if (strstr(program_invocation_short_name, "reboot")) {
5621                         if (kexec_loaded())
5622                                 arg_action = ACTION_KEXEC;
5623                         else
5624                                 arg_action = ACTION_REBOOT;
5625                         return halt_parse_argv(argc, argv);
5626                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5627                         arg_action = ACTION_POWEROFF;
5628                         return shutdown_parse_argv(argc, argv);
5629                 } else if (strstr(program_invocation_short_name, "init")) {
5630
5631                         if (sd_booted() > 0) {
5632                                 arg_action = ACTION_INVALID;
5633                                 return telinit_parse_argv(argc, argv);
5634                         } else {
5635                                 /* Hmm, so some other init system is
5636                                  * running, we need to forward this
5637                                  * request to it. For now we simply
5638                                  * guess that it is Upstart. */
5639
5640                                 execv(TELINIT, argv);
5641
5642                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5643                                 return -EIO;
5644                         }
5645
5646                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5647                         arg_action = ACTION_RUNLEVEL;
5648                         return runlevel_parse_argv(argc, argv);
5649                 }
5650         }
5651
5652         arg_action = ACTION_SYSTEMCTL;
5653         return systemctl_parse_argv(argc, argv);
5654 }
5655
5656 _pure_ static int action_to_runlevel(void) {
5657
5658         static const char table[_ACTION_MAX] = {
5659                 [ACTION_HALT] =      '0',
5660                 [ACTION_POWEROFF] =  '0',
5661                 [ACTION_REBOOT] =    '6',
5662                 [ACTION_RUNLEVEL2] = '2',
5663                 [ACTION_RUNLEVEL3] = '3',
5664                 [ACTION_RUNLEVEL4] = '4',
5665                 [ACTION_RUNLEVEL5] = '5',
5666                 [ACTION_RESCUE] =    '1'
5667         };
5668
5669         assert(arg_action < _ACTION_MAX);
5670
5671         return table[arg_action];
5672 }
5673
5674 static int talk_initctl(void) {
5675         struct init_request request = {};
5676         int r;
5677         _cleanup_close_ int fd = -1;
5678         char rl;
5679
5680         rl = action_to_runlevel();
5681         if (!rl)
5682                 return 0;
5683
5684         request.magic = INIT_MAGIC;
5685         request.sleeptime = 0;
5686         request.cmd = INIT_CMD_RUNLVL;
5687         request.runlevel = rl;
5688
5689         fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5690         if (fd < 0) {
5691                 if (errno == ENOENT)
5692                         return 0;
5693
5694                 log_error("Failed to open "INIT_FIFO": %m");
5695                 return -errno;
5696         }
5697
5698         errno = 0;
5699         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5700         if (r) {
5701                 log_error("Failed to write to "INIT_FIFO": %m");
5702                 return errno > 0 ? -errno : -EIO;
5703         }
5704
5705         return 1;
5706 }
5707
5708 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5709
5710         static const struct {
5711                 const char* verb;
5712                 const enum {
5713                         MORE,
5714                         LESS,
5715                         EQUAL
5716                 } argc_cmp;
5717                 const int argc;
5718                 int (* const dispatch)(DBusConnection *bus, char **args);
5719         } verbs[] = {
5720                 { "list-units",            LESS,  1, list_units        },
5721                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5722                 { "list-sockets",          LESS,  1, list_sockets      },
5723                 { "list-jobs",             EQUAL, 1, list_jobs         },
5724                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5725                 { "cancel",                MORE,  2, cancel_job        },
5726                 { "start",                 MORE,  2, start_unit        },
5727                 { "stop",                  MORE,  2, start_unit        },
5728                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5729                 { "reload",                MORE,  2, start_unit        },
5730                 { "restart",               MORE,  2, start_unit        },
5731                 { "try-restart",           MORE,  2, start_unit        },
5732                 { "reload-or-restart",     MORE,  2, start_unit        },
5733                 { "reload-or-try-restart", MORE,  2, start_unit        },
5734                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5735                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5736                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5737                 { "isolate",               EQUAL, 2, start_unit        },
5738                 { "kill",                  MORE,  2, kill_unit         },
5739                 { "is-active",             MORE,  2, check_unit_active },
5740                 { "check",                 MORE,  2, check_unit_active },
5741                 { "is-failed",             MORE,  2, check_unit_failed },
5742                 { "show",                  MORE,  1, show              },
5743                 { "status",                MORE,  1, show              },
5744                 { "help",                  MORE,  2, show              },
5745                 { "snapshot",              LESS,  2, snapshot          },
5746                 { "delete",                MORE,  2, delete_snapshot   },
5747                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5748                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5749                 { "show-environment",      EQUAL, 1, show_enviroment   },
5750                 { "set-environment",       MORE,  2, set_environment   },
5751                 { "unset-environment",     MORE,  2, set_environment   },
5752                 { "halt",                  EQUAL, 1, start_special     },
5753                 { "poweroff",              EQUAL, 1, start_special     },
5754                 { "reboot",                EQUAL, 1, start_special     },
5755                 { "kexec",                 EQUAL, 1, start_special     },
5756                 { "suspend",               EQUAL, 1, start_special     },
5757                 { "hibernate",             EQUAL, 1, start_special     },
5758                 { "hybrid-sleep",          EQUAL, 1, start_special     },
5759                 { "default",               EQUAL, 1, start_special     },
5760                 { "rescue",                EQUAL, 1, start_special     },
5761                 { "emergency",             EQUAL, 1, start_special     },
5762                 { "exit",                  EQUAL, 1, start_special     },
5763                 { "reset-failed",          MORE,  1, reset_failed      },
5764                 { "enable",                MORE,  2, enable_unit       },
5765                 { "disable",               MORE,  2, enable_unit       },
5766                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5767                 { "reenable",              MORE,  2, enable_unit       },
5768                 { "preset",                MORE,  2, enable_unit       },
5769                 { "mask",                  MORE,  2, enable_unit       },
5770                 { "unmask",                MORE,  2, enable_unit       },
5771                 { "link",                  MORE,  2, enable_unit       },
5772                 { "switch-root",           MORE,  2, switch_root       },
5773                 { "list-dependencies",     LESS,  2, list_dependencies },
5774                 { "set-default",           EQUAL, 2, enable_unit       },
5775                 { "get-default",           LESS,  1, get_default       },
5776                 { "set-property",          MORE,  3, set_property      },
5777         };
5778
5779         int left;
5780         unsigned i;
5781
5782         assert(argc >= 0);
5783         assert(argv);
5784         assert(error);
5785
5786         left = argc - optind;
5787
5788         if (left <= 0)
5789                 /* Special rule: no arguments means "list-units" */
5790                 i = 0;
5791         else {
5792                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5793                         log_error("This command expects one or more "
5794                                   "unit names. Did you mean --help?");
5795                         return -EINVAL;
5796                 }
5797
5798                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5799                         if (streq(argv[optind], verbs[i].verb))
5800                                 break;
5801
5802                 if (i >= ELEMENTSOF(verbs)) {
5803                         log_error("Unknown operation '%s'.", argv[optind]);
5804                         return -EINVAL;
5805                 }
5806         }
5807
5808         switch (verbs[i].argc_cmp) {
5809
5810         case EQUAL:
5811                 if (left != verbs[i].argc) {
5812                         log_error("Invalid number of arguments.");
5813                         return -EINVAL;
5814                 }
5815
5816                 break;
5817
5818         case MORE:
5819                 if (left < verbs[i].argc) {
5820                         log_error("Too few arguments.");
5821                         return -EINVAL;
5822                 }
5823
5824                 break;
5825
5826         case LESS:
5827                 if (left > verbs[i].argc) {
5828                         log_error("Too many arguments.");
5829                         return -EINVAL;
5830                 }
5831
5832                 break;
5833
5834         default:
5835                 assert_not_reached("Unknown comparison operator.");
5836         }
5837
5838         /* Require a bus connection for all operations but
5839          * enable/disable */
5840         if (!streq(verbs[i].verb, "enable") &&
5841             !streq(verbs[i].verb, "disable") &&
5842             !streq(verbs[i].verb, "is-enabled") &&
5843             !streq(verbs[i].verb, "list-unit-files") &&
5844             !streq(verbs[i].verb, "reenable") &&
5845             !streq(verbs[i].verb, "preset") &&
5846             !streq(verbs[i].verb, "mask") &&
5847             !streq(verbs[i].verb, "unmask") &&
5848             !streq(verbs[i].verb, "link") &&
5849             !streq(verbs[i].verb, "set-default") &&
5850             !streq(verbs[i].verb, "get-default")) {
5851
5852                 if (running_in_chroot() > 0) {
5853                         log_info("Running in chroot, ignoring request.");
5854                         return 0;
5855                 }
5856
5857                 if (((!streq(verbs[i].verb, "reboot") &&
5858                       !streq(verbs[i].verb, "halt") &&
5859                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5860                         log_error("Failed to get D-Bus connection: %s",
5861                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5862                         return -EIO;
5863                 }
5864
5865         } else {
5866
5867                 if (!bus && !avoid_bus()) {
5868                         log_error("Failed to get D-Bus connection: %s",
5869                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5870                         return -EIO;
5871                 }
5872         }
5873
5874         return verbs[i].dispatch(bus, argv + optind);
5875 }
5876
5877 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5878         _cleanup_close_ int fd;
5879         struct sd_shutdown_command c = {
5880                 .usec = t,
5881                 .mode = mode,
5882                 .dry_run = dry_run,
5883                 .warn_wall = warn,
5884         };
5885         union sockaddr_union sockaddr = {
5886                 .un.sun_family = AF_UNIX,
5887                 .un.sun_path = "/run/systemd/shutdownd",
5888         };
5889         struct iovec iovec[2] = {
5890                 {.iov_base = (char*) &c,
5891                  .iov_len = offsetof(struct sd_shutdown_command, wall_message),
5892                 }
5893         };
5894         struct msghdr msghdr = {
5895                 .msg_name = &sockaddr,
5896                 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
5897                                + sizeof("/run/systemd/shutdownd") - 1,
5898                 .msg_iov = iovec,
5899                 .msg_iovlen = 1,
5900         };
5901
5902         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5903         if (fd < 0)
5904                 return -errno;
5905
5906         if (!isempty(message)) {
5907                 iovec[1].iov_base = (char*) message;
5908                 iovec[1].iov_len = strlen(message);
5909                 msghdr.msg_iovlen++;
5910         }
5911
5912         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
5913                 return -errno;
5914
5915         return 0;
5916 }
5917
5918 static int reload_with_fallback(DBusConnection *bus) {
5919
5920         if (bus) {
5921                 /* First, try systemd via D-Bus. */
5922                 if (daemon_reload(bus, NULL) >= 0)
5923                         return 0;
5924         }
5925
5926         /* Nothing else worked, so let's try signals */
5927         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5928
5929         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5930                 log_error("kill() failed: %m");
5931                 return -errno;
5932         }
5933
5934         return 0;
5935 }
5936
5937 static int start_with_fallback(DBusConnection *bus) {
5938
5939         if (bus) {
5940                 /* First, try systemd via D-Bus. */
5941                 if (start_unit(bus, NULL) >= 0)
5942                         goto done;
5943         }
5944
5945         /* Nothing else worked, so let's try
5946          * /dev/initctl */
5947         if (talk_initctl() > 0)
5948                 goto done;
5949
5950         log_error("Failed to talk to init daemon.");
5951         return -EIO;
5952
5953 done:
5954         warn_wall(arg_action);
5955         return 0;
5956 }
5957
5958 static _noreturn_ void halt_now(enum action a) {
5959
5960         _cleanup_free_ char *param = NULL;
5961
5962        /* Make sure C-A-D is handled by the kernel from this
5963          * point on... */
5964         reboot(RB_ENABLE_CAD);
5965
5966         switch (a) {
5967
5968         case ACTION_HALT:
5969                 log_info("Halting.");
5970                 reboot(RB_HALT_SYSTEM);
5971                 break;
5972
5973         case ACTION_POWEROFF:
5974                 log_info("Powering off.");
5975                 reboot(RB_POWER_OFF);
5976                 break;
5977
5978         case ACTION_REBOOT:
5979                 if (read_one_line_file(REBOOT_PARAM_FILE, &param) == 0) {
5980                         log_info("Rebooting with arg '%s'.", param);
5981                         syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
5982                                 LINUX_REBOOT_CMD_RESTART2, param);
5983                 } else {
5984                         log_info("Rebooting.");
5985                         reboot(RB_AUTOBOOT);
5986                 }
5987                 break;
5988
5989         default:
5990                 assert_not_reached("Unknown halt action.");
5991         }
5992
5993         assert_not_reached("Uh? This shouldn't happen.");
5994 }
5995
5996 static int halt_main(DBusConnection *bus) {
5997         int r;
5998
5999         r = check_inhibitors(bus, arg_action);
6000         if (r < 0)
6001                 return r;
6002
6003         if (geteuid() != 0) {
6004                 /* Try logind if we are a normal user and no special
6005                  * mode applies. Maybe PolicyKit allows us to shutdown
6006                  * the machine. */
6007
6008                 if (arg_when <= 0 &&
6009                     !arg_dry &&
6010                     arg_force <= 0 &&
6011                     (arg_action == ACTION_POWEROFF ||
6012                      arg_action == ACTION_REBOOT)) {
6013                         r = reboot_with_logind(bus, arg_action);
6014                         if (r >= 0)
6015                                 return r;
6016                 }
6017
6018                 log_error("Must be root.");
6019                 return -EPERM;
6020         }
6021
6022         if (arg_when > 0) {
6023                 _cleanup_free_ char *m;
6024
6025                 m = strv_join(arg_wall, " ");
6026                 r = send_shutdownd(arg_when,
6027                                    arg_action == ACTION_HALT     ? 'H' :
6028                                    arg_action == ACTION_POWEROFF ? 'P' :
6029                                    arg_action == ACTION_KEXEC    ? 'K' :
6030                                                                    'r',
6031                                    arg_dry,
6032                                    !arg_no_wall,
6033                                    m);
6034
6035                 if (r < 0)
6036                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
6037                 else {
6038                         char date[FORMAT_TIMESTAMP_MAX];
6039
6040                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6041                                  format_timestamp(date, sizeof(date), arg_when));
6042                         return 0;
6043                 }
6044         }
6045
6046         if (!arg_dry && !arg_force)
6047                 return start_with_fallback(bus);
6048
6049         if (!arg_no_wtmp) {
6050                 if (sd_booted() > 0)
6051                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
6052                 else {
6053                         r = utmp_put_shutdown();
6054                         if (r < 0)
6055                                 log_warning("Failed to write utmp record: %s", strerror(-r));
6056                 }
6057         }
6058
6059         if (arg_dry)
6060                 return 0;
6061
6062         halt_now(arg_action);
6063         /* We should never reach this. */
6064         return -ENOSYS;
6065 }
6066
6067 static int runlevel_main(void) {
6068         int r, runlevel, previous;
6069
6070         r = utmp_get_runlevel(&runlevel, &previous);
6071         if (r < 0) {
6072                 puts("unknown");
6073                 return r;
6074         }
6075
6076         printf("%c %c\n",
6077                previous <= 0 ? 'N' : previous,
6078                runlevel <= 0 ? 'N' : runlevel);
6079
6080         return 0;
6081 }
6082
6083 int main(int argc, char*argv[]) {
6084         int r, retval = EXIT_FAILURE;
6085         DBusConnection *bus = NULL;
6086         _cleanup_dbus_error_free_ DBusError error;
6087
6088         dbus_error_init(&error);
6089
6090         setlocale(LC_ALL, "");
6091         log_parse_environment();
6092         log_open();
6093
6094         /* Explicitly not on_tty() to avoid setting cached value.
6095          * This becomes relevant for piping output which might be
6096          * ellipsized. */
6097         original_stdout_is_tty = isatty(STDOUT_FILENO);
6098
6099         r = parse_argv(argc, argv);
6100         if (r < 0)
6101                 goto finish;
6102         else if (r == 0) {
6103                 retval = EXIT_SUCCESS;
6104                 goto finish;
6105         }
6106
6107         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6108          * let's shortcut this */
6109         if (arg_action == ACTION_RUNLEVEL) {
6110                 r = runlevel_main();
6111                 retval = r < 0 ? EXIT_FAILURE : r;
6112                 goto finish;
6113         }
6114
6115         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6116                 log_info("Running in chroot, ignoring request.");
6117                 retval = 0;
6118                 goto finish;
6119         }
6120
6121         if (!avoid_bus()) {
6122                 if (arg_transport == TRANSPORT_NORMAL)
6123                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
6124                 else if (arg_transport == TRANSPORT_POLKIT) {
6125                         bus_connect_system_polkit(&bus, &error);
6126                         private_bus = false;
6127                 } else if (arg_transport == TRANSPORT_SSH) {
6128                         bus_connect_system_ssh(arg_user, arg_host, &bus, &error);
6129                         private_bus = false;
6130                 } else
6131                         assert_not_reached("Uh, invalid transport...");
6132         }
6133
6134         switch (arg_action) {
6135
6136         case ACTION_SYSTEMCTL:
6137                 r = systemctl_main(bus, argc, argv, &error);
6138                 break;
6139
6140         case ACTION_HALT:
6141         case ACTION_POWEROFF:
6142         case ACTION_REBOOT:
6143         case ACTION_KEXEC:
6144                 r = halt_main(bus);
6145                 break;
6146
6147         case ACTION_RUNLEVEL2:
6148         case ACTION_RUNLEVEL3:
6149         case ACTION_RUNLEVEL4:
6150         case ACTION_RUNLEVEL5:
6151         case ACTION_RESCUE:
6152         case ACTION_EMERGENCY:
6153         case ACTION_DEFAULT:
6154                 r = start_with_fallback(bus);
6155                 break;
6156
6157         case ACTION_RELOAD:
6158         case ACTION_REEXEC:
6159                 r = reload_with_fallback(bus);
6160                 break;
6161
6162         case ACTION_CANCEL_SHUTDOWN: {
6163                 char *m = NULL;
6164
6165                 if (arg_wall) {
6166                         m = strv_join(arg_wall, " ");
6167                         if (!m) {
6168                                 retval = EXIT_FAILURE;
6169                                 goto finish;
6170                         }
6171                 }
6172                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6173                 if (r < 0)
6174                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
6175                 free(m);
6176                 break;
6177         }
6178
6179         case ACTION_INVALID:
6180         case ACTION_RUNLEVEL:
6181         default:
6182                 assert_not_reached("Unknown action");
6183         }
6184
6185         retval = r < 0 ? EXIT_FAILURE : r;
6186
6187 finish:
6188         if (bus) {
6189                 dbus_connection_flush(bus);
6190                 dbus_connection_close(bus);
6191                 dbus_connection_unref(bus);
6192         }
6193
6194         dbus_shutdown();
6195
6196         strv_free(arg_types);
6197         strv_free(arg_states);
6198         strv_free(arg_properties);
6199
6200         pager_close();
6201         ask_password_agent_close();
6202         polkit_agent_close();
6203
6204         return retval;
6205 }