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