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