chiark / gitweb /
replace tabs with spaces in various files
[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 *m = NULL, *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 bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1458         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1459         dbus_bool_t b = FALSE;
1460         DBusMessageIter iter, sub;
1461         const char
1462                 *interface = "org.freedesktop.systemd1.Unit",
1463                 *property = "NeedDaemonReload",
1464                 *path;
1465         _cleanup_free_ char *n = NULL;
1466         int r;
1467
1468         /* We ignore all errors here, since this is used to show a warning only */
1469
1470         n = unit_name_mangle(unit);
1471         if (!n)
1472                 return log_oom();
1473
1474         r = bus_method_call_with_reply(
1475                         bus,
1476                         "org.freedesktop.systemd1",
1477                         "/org/freedesktop/systemd1",
1478                         "org.freedesktop.systemd1.Manager",
1479                         "GetUnit",
1480                         &reply,
1481                         NULL,
1482                         DBUS_TYPE_STRING, &n,
1483                         DBUS_TYPE_INVALID);
1484         if (r < 0)
1485                 return r;
1486
1487         if (!dbus_message_get_args(reply, NULL,
1488                                    DBUS_TYPE_OBJECT_PATH, &path,
1489                                    DBUS_TYPE_INVALID))
1490                 return -EIO;
1491
1492         dbus_message_unref(reply);
1493         reply = NULL;
1494
1495         r = bus_method_call_with_reply(
1496                         bus,
1497                         "org.freedesktop.systemd1",
1498                         path,
1499                         "org.freedesktop.DBus.Properties",
1500                         "Get",
1501                         &reply,
1502                         NULL,
1503                         DBUS_TYPE_STRING, &interface,
1504                         DBUS_TYPE_STRING, &property,
1505                         DBUS_TYPE_INVALID);
1506         if (r < 0)
1507                 return r;
1508
1509         if (!dbus_message_iter_init(reply, &iter) ||
1510             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1511                 return -EIO;
1512
1513         dbus_message_iter_recurse(&iter, &sub);
1514         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1515                 return -EIO;
1516
1517         dbus_message_iter_get_basic(&sub, &b);
1518         return b;
1519 }
1520
1521 typedef struct WaitData {
1522         Set *set;
1523
1524         char *name;
1525         char *result;
1526 } WaitData;
1527
1528 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1529         _cleanup_dbus_error_free_ DBusError error;
1530         WaitData *d = data;
1531
1532         dbus_error_init(&error);
1533
1534         assert(connection);
1535         assert(message);
1536         assert(d);
1537
1538         log_debug("Got D-Bus request: %s.%s() on %s",
1539                   dbus_message_get_interface(message),
1540                   dbus_message_get_member(message),
1541                   dbus_message_get_path(message));
1542
1543         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1544                 log_error("Warning! D-Bus connection terminated.");
1545                 dbus_connection_close(connection);
1546
1547         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1548                 uint32_t id;
1549                 const char *path, *result, *unit;
1550
1551                 if (dbus_message_get_args(message, &error,
1552                                           DBUS_TYPE_UINT32, &id,
1553                                           DBUS_TYPE_OBJECT_PATH, &path,
1554                                           DBUS_TYPE_STRING, &unit,
1555                                           DBUS_TYPE_STRING, &result,
1556                                           DBUS_TYPE_INVALID)) {
1557
1558                         free(set_remove(d->set, (char*) path));
1559
1560                         if (!isempty(result))
1561                                 d->result = strdup(result);
1562
1563                         if (!isempty(unit))
1564                                 d->name = strdup(unit);
1565
1566                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1567                 }
1568 #ifndef LEGACY
1569                 dbus_error_free(&error);
1570                 if (dbus_message_get_args(message, &error,
1571                                           DBUS_TYPE_UINT32, &id,
1572                                           DBUS_TYPE_OBJECT_PATH, &path,
1573                                           DBUS_TYPE_STRING, &result,
1574                                           DBUS_TYPE_INVALID)) {
1575                         /* Compatibility with older systemd versions <
1576                          * 183 during upgrades. This should be dropped
1577                          * one day. */
1578                         free(set_remove(d->set, (char*) path));
1579
1580                         if (*result)
1581                                 d->result = strdup(result);
1582
1583                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1584                 }
1585 #endif
1586
1587                 log_error("Failed to parse message: %s", bus_error_message(&error));
1588         }
1589
1590         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1591 }
1592
1593 static int enable_wait_for_jobs(DBusConnection *bus) {
1594         DBusError error;
1595
1596         assert(bus);
1597
1598         if (private_bus)
1599                 return 0;
1600
1601         dbus_error_init(&error);
1602         dbus_bus_add_match(bus,
1603                            "type='signal',"
1604                            "sender='org.freedesktop.systemd1',"
1605                            "interface='org.freedesktop.systemd1.Manager',"
1606                            "member='JobRemoved',"
1607                            "path='/org/freedesktop/systemd1'",
1608                            &error);
1609
1610         if (dbus_error_is_set(&error)) {
1611                 log_error("Failed to add match: %s", bus_error_message(&error));
1612                 dbus_error_free(&error);
1613                 return -EIO;
1614         }
1615
1616         /* This is slightly dirty, since we don't undo the match registrations. */
1617         return 0;
1618 }
1619
1620 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1621         int r = 0;
1622         WaitData d = { .set = s };
1623
1624         assert(bus);
1625         assert(s);
1626
1627         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1628                 return log_oom();
1629
1630         while (!set_isempty(s)) {
1631
1632                 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1633                         log_error("Disconnected from bus.");
1634                         return -ECONNREFUSED;
1635                 }
1636
1637                 if (!d.result)
1638                         goto free_name;
1639
1640                 if (!arg_quiet) {
1641                         if (streq(d.result, "timeout"))
1642                                 log_error("Job for %s timed out.", strna(d.name));
1643                         else if (streq(d.result, "canceled"))
1644                                 log_error("Job for %s canceled.", strna(d.name));
1645                         else if (streq(d.result, "dependency"))
1646                                 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1647                         else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1648                                 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1649                 }
1650
1651                 if (streq_ptr(d.result, "timeout"))
1652                         r = -ETIME;
1653                 else if (streq_ptr(d.result, "canceled"))
1654                         r = -ECANCELED;
1655                 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1656                         r = -EIO;
1657
1658                 free(d.result);
1659                 d.result = NULL;
1660
1661         free_name:
1662                 free(d.name);
1663                 d.name = NULL;
1664         }
1665
1666         dbus_connection_remove_filter(bus, wait_filter, &d);
1667         return r;
1668 }
1669
1670 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1671         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1672         _cleanup_free_ char *n = NULL;
1673         DBusMessageIter iter, sub;
1674         const char
1675                 *interface = "org.freedesktop.systemd1.Unit",
1676                 *property = "ActiveState";
1677         const char *state, *path;
1678         DBusError error;
1679         int r;
1680
1681         assert(name);
1682
1683         dbus_error_init(&error);
1684
1685         n = unit_name_mangle(name);
1686         if (!n)
1687                 return log_oom();
1688
1689         r = bus_method_call_with_reply (
1690                         bus,
1691                         "org.freedesktop.systemd1",
1692                         "/org/freedesktop/systemd1",
1693                         "org.freedesktop.systemd1.Manager",
1694                         "GetUnit",
1695                         &reply,
1696                         &error,
1697                         DBUS_TYPE_STRING, &n,
1698                         DBUS_TYPE_INVALID);
1699         if (r < 0) {
1700                 dbus_error_free(&error);
1701
1702                 if (!quiet)
1703                         puts("unknown");
1704                 return 0;
1705         }
1706
1707         if (!dbus_message_get_args(reply, NULL,
1708                                    DBUS_TYPE_OBJECT_PATH, &path,
1709                                    DBUS_TYPE_INVALID)) {
1710                 log_error("Failed to parse reply.");
1711                 return -EIO;
1712         }
1713
1714         dbus_message_unref(reply);
1715         reply = NULL;
1716
1717         r = bus_method_call_with_reply(
1718                         bus,
1719                         "org.freedesktop.systemd1",
1720                         path,
1721                         "org.freedesktop.DBus.Properties",
1722                         "Get",
1723                         &reply,
1724                         NULL,
1725                         DBUS_TYPE_STRING, &interface,
1726                         DBUS_TYPE_STRING, &property,
1727                         DBUS_TYPE_INVALID);
1728         if (r < 0) {
1729                 if (!quiet)
1730                         puts("unknown");
1731                 return 0;
1732         }
1733
1734         if (!dbus_message_iter_init(reply, &iter) ||
1735             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1736                 log_error("Failed to parse reply.");
1737                 return r;
1738         }
1739
1740         dbus_message_iter_recurse(&iter, &sub);
1741
1742         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1743                 log_error("Failed to parse reply.");
1744                 return r;
1745         }
1746
1747         dbus_message_iter_get_basic(&sub, &state);
1748
1749         if (!quiet)
1750                 puts(state);
1751
1752         return strv_find(check_states, state) ? 1 : 0;
1753 }
1754
1755 static void check_triggering_units(
1756                 DBusConnection *bus,
1757                 const char *unit_name) {
1758
1759         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1760         DBusMessageIter iter, sub;
1761         const char *interface = "org.freedesktop.systemd1.Unit",
1762                    *load_state_property = "LoadState",
1763                    *triggered_by_property = "TriggeredBy",
1764                    *state;
1765         _cleanup_free_ char *unit_path = NULL, *n = NULL;
1766         bool print_warning_label = true;
1767         int r;
1768
1769         n = unit_name_mangle(unit_name);
1770         if (!n) {
1771                 log_oom();
1772                 return;
1773         }
1774
1775         unit_path = unit_dbus_path_from_name(n);
1776         if (!unit_path) {
1777                 log_oom();
1778                 return;
1779         }
1780
1781         r = bus_method_call_with_reply(
1782                         bus,
1783                         "org.freedesktop.systemd1",
1784                         unit_path,
1785                         "org.freedesktop.DBus.Properties",
1786                         "Get",
1787                         &reply,
1788                         NULL,
1789                         DBUS_TYPE_STRING, &interface,
1790                         DBUS_TYPE_STRING, &load_state_property,
1791                         DBUS_TYPE_INVALID);
1792         if (r < 0)
1793                 return;
1794
1795         if (!dbus_message_iter_init(reply, &iter) ||
1796             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1797                 log_error("Failed to parse reply.");
1798                 return;
1799         }
1800
1801         dbus_message_iter_recurse(&iter, &sub);
1802
1803         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1804             log_error("Failed to parse reply.");
1805             return;
1806         }
1807
1808         dbus_message_iter_get_basic(&sub, &state);
1809
1810         if (streq(state, "masked"))
1811             return;
1812
1813         dbus_message_unref(reply);
1814         reply = NULL;
1815
1816         r = bus_method_call_with_reply(
1817                         bus,
1818                         "org.freedesktop.systemd1",
1819                         unit_path,
1820                         "org.freedesktop.DBus.Properties",
1821                         "Get",
1822                         &reply,
1823                         NULL,
1824                         DBUS_TYPE_STRING, &interface,
1825                         DBUS_TYPE_STRING, &triggered_by_property,
1826                         DBUS_TYPE_INVALID);
1827         if (r < 0)
1828                 return;
1829
1830         if (!dbus_message_iter_init(reply, &iter) ||
1831             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1832                 log_error("Failed to parse reply.");
1833                 return;
1834         }
1835
1836         dbus_message_iter_recurse(&iter, &sub);
1837         dbus_message_iter_recurse(&sub, &iter);
1838         sub = iter;
1839
1840         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1841                 const char * const check_states[] = {
1842                         "active",
1843                         "reloading",
1844                         NULL
1845                 };
1846                 const char *service_trigger;
1847
1848                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1849                         log_error("Failed to parse reply.");
1850                         return;
1851                 }
1852
1853                 dbus_message_iter_get_basic(&sub, &service_trigger);
1854
1855                 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1856                 if (r < 0)
1857                         return;
1858                 if (r > 0) {
1859                         if (print_warning_label) {
1860                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1861                                 print_warning_label = false;
1862                         }
1863
1864                         log_warning("  %s", service_trigger);
1865                 }
1866
1867                 dbus_message_iter_next(&sub);
1868         }
1869 }
1870
1871 static int start_unit_one(
1872                 DBusConnection *bus,
1873                 const char *method,
1874                 const char *name,
1875                 const char *mode,
1876                 DBusError *error,
1877                 Set *s) {
1878
1879         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1880         _cleanup_free_ char *n;
1881         const char *path;
1882         int r;
1883
1884         assert(method);
1885         assert(name);
1886         assert(mode);
1887         assert(error);
1888
1889         n = unit_name_mangle(name);
1890         if (!n)
1891                 return log_oom();
1892
1893         r = bus_method_call_with_reply(
1894                         bus,
1895                         "org.freedesktop.systemd1",
1896                         "/org/freedesktop/systemd1",
1897                         "org.freedesktop.systemd1.Manager",
1898                         method,
1899                         &reply,
1900                         error,
1901                         DBUS_TYPE_STRING, &n,
1902                         DBUS_TYPE_STRING, &mode,
1903                         DBUS_TYPE_INVALID);
1904         if (r) {
1905                 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1906                         /* There's always a fallback possible for
1907                          * legacy actions. */
1908                         r = -EADDRNOTAVAIL;
1909                 else
1910                         log_error("Failed to issue method call: %s", bus_error_message(error));
1911
1912                 return r;
1913         }
1914
1915         if (!dbus_message_get_args(reply, error,
1916                                    DBUS_TYPE_OBJECT_PATH, &path,
1917                                    DBUS_TYPE_INVALID)) {
1918                 log_error("Failed to parse reply: %s", bus_error_message(error));
1919                 return -EIO;
1920         }
1921
1922         if (need_daemon_reload(bus, n))
1923                 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %sdaemon-reload' recommended.",
1924                             n, arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
1925
1926         if (s) {
1927                 char *p;
1928
1929                 p = strdup(path);
1930                 if (!p)
1931                         return log_oom();
1932
1933                 r = set_consume(s, p);
1934                 if (r < 0) {
1935                         log_error("Failed to add path to set.");
1936                         return r;
1937                 }
1938         }
1939
1940         return 0;
1941 }
1942
1943 static const struct {
1944         const char *target;
1945         const char *verb;
1946         const char *mode;
1947 } action_table[_ACTION_MAX] = {
1948         [ACTION_HALT]         = { SPECIAL_HALT_TARGET,         "halt",         "replace-irreversibly" },
1949         [ACTION_POWEROFF]     = { SPECIAL_POWEROFF_TARGET,     "poweroff",     "replace-irreversibly" },
1950         [ACTION_REBOOT]       = { SPECIAL_REBOOT_TARGET,       "reboot",       "replace-irreversibly" },
1951         [ACTION_KEXEC]        = { SPECIAL_KEXEC_TARGET,        "kexec",        "replace-irreversibly" },
1952         [ACTION_RUNLEVEL2]    = { SPECIAL_RUNLEVEL2_TARGET,    NULL,           "isolate" },
1953         [ACTION_RUNLEVEL3]    = { SPECIAL_RUNLEVEL3_TARGET,    NULL,           "isolate" },
1954         [ACTION_RUNLEVEL4]    = { SPECIAL_RUNLEVEL4_TARGET,    NULL,           "isolate" },
1955         [ACTION_RUNLEVEL5]    = { SPECIAL_RUNLEVEL5_TARGET,    NULL,           "isolate" },
1956         [ACTION_RESCUE]       = { SPECIAL_RESCUE_TARGET,       "rescue",       "isolate" },
1957         [ACTION_EMERGENCY]    = { SPECIAL_EMERGENCY_TARGET,    "emergency",    "isolate" },
1958         [ACTION_DEFAULT]      = { SPECIAL_DEFAULT_TARGET,      "default",      "isolate" },
1959         [ACTION_EXIT]         = { SPECIAL_EXIT_TARGET,         "exit",         "replace-irreversibly" },
1960         [ACTION_SUSPEND]      = { SPECIAL_SUSPEND_TARGET,      "suspend",      "replace-irreversibly" },
1961         [ACTION_HIBERNATE]    = { SPECIAL_HIBERNATE_TARGET,    "hibernate",    "replace-irreversibly" },
1962         [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1963 };
1964
1965 static enum action verb_to_action(const char *verb) {
1966         enum action i;
1967
1968         for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1969                 if (action_table[i].verb && streq(verb, action_table[i].verb))
1970                         return i;
1971         return ACTION_INVALID;
1972 }
1973
1974 static int start_unit(DBusConnection *bus, char **args) {
1975
1976         int r, ret = 0;
1977         const char *method, *mode, *one_name;
1978         _cleanup_set_free_free_ Set *s = NULL;
1979         _cleanup_dbus_error_free_ DBusError error;
1980         char **name;
1981
1982         dbus_error_init(&error);
1983
1984         assert(bus);
1985
1986         ask_password_agent_open_if_enabled();
1987
1988         if (arg_action == ACTION_SYSTEMCTL) {
1989                 enum action action;
1990                 method =
1991                         streq(args[0], "stop") ||
1992                         streq(args[0], "condstop")              ? "StopUnit" :
1993                         streq(args[0], "reload")                ? "ReloadUnit" :
1994                         streq(args[0], "restart")               ? "RestartUnit" :
1995
1996                         streq(args[0], "try-restart")           ||
1997                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1998
1999                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
2000
2001                         streq(args[0], "reload-or-try-restart") ||
2002                         streq(args[0], "condreload") ||
2003
2004                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
2005                                                                   "StartUnit";
2006                 action = verb_to_action(args[0]);
2007
2008                 mode = streq(args[0], "isolate") ? "isolate" :
2009                        action_table[action].mode ?: arg_job_mode;
2010
2011                 one_name = action_table[action].target;
2012
2013         } else {
2014                 assert(arg_action < ELEMENTSOF(action_table));
2015                 assert(action_table[arg_action].target);
2016
2017                 method = "StartUnit";
2018
2019                 mode = action_table[arg_action].mode;
2020                 one_name = action_table[arg_action].target;
2021         }
2022
2023         if (!arg_no_block) {
2024                 ret = enable_wait_for_jobs(bus);
2025                 if (ret < 0) {
2026                         log_error("Could not watch jobs: %s", strerror(-ret));
2027                         return ret;
2028                 }
2029
2030                 s = set_new(string_hash_func, string_compare_func);
2031                 if (!s)
2032                         return log_oom();
2033         }
2034
2035         if (one_name) {
2036                 ret = start_unit_one(bus, method, one_name, mode, &error, s);
2037                 if (ret < 0)
2038                         ret = translate_bus_error_to_exit_status(ret, &error);
2039         } else {
2040                 STRV_FOREACH(name, args+1) {
2041                         r = start_unit_one(bus, method, *name, mode, &error, s);
2042                         if (r < 0) {
2043                                 ret = translate_bus_error_to_exit_status(r, &error);
2044                                 dbus_error_free(&error);
2045                         }
2046                 }
2047         }
2048
2049         if (!arg_no_block) {
2050                 r = wait_for_jobs(bus, s);
2051                 if (r < 0)
2052                         return r;
2053
2054                 /* When stopping units, warn if they can still be triggered by
2055                  * another active unit (socket, path, timer) */
2056                 if (!arg_quiet && streq(method, "StopUnit")) {
2057                         if (one_name)
2058                                 check_triggering_units(bus, one_name);
2059                         else
2060                                 STRV_FOREACH(name, args+1)
2061                                         check_triggering_units(bus, *name);
2062                 }
2063         }
2064
2065         return ret;
2066 }
2067
2068 /* Ask systemd-logind, which might grant access to unprivileged users
2069  * through PolicyKit */
2070 static int reboot_with_logind(DBusConnection *bus, enum action a) {
2071 #ifdef HAVE_LOGIND
2072         const char *method;
2073         dbus_bool_t interactive = true;
2074
2075         if (!bus)
2076                 return -EIO;
2077
2078         polkit_agent_open_if_enabled();
2079
2080         switch (a) {
2081
2082         case ACTION_REBOOT:
2083                 method = "Reboot";
2084                 break;
2085
2086         case ACTION_POWEROFF:
2087                 method = "PowerOff";
2088                 break;
2089
2090         case ACTION_SUSPEND:
2091                 method = "Suspend";
2092                 break;
2093
2094         case ACTION_HIBERNATE:
2095                 method = "Hibernate";
2096                 break;
2097
2098         case ACTION_HYBRID_SLEEP:
2099                 method = "HybridSleep";
2100                 break;
2101
2102         default:
2103                 return -EINVAL;
2104         }
2105
2106         return bus_method_call_with_reply(
2107                         bus,
2108                         "org.freedesktop.login1",
2109                         "/org/freedesktop/login1",
2110                         "org.freedesktop.login1.Manager",
2111                         method,
2112                         NULL,
2113                         NULL,
2114                         DBUS_TYPE_BOOLEAN, &interactive,
2115                         DBUS_TYPE_INVALID);
2116 #else
2117         return -ENOSYS;
2118 #endif
2119 }
2120
2121 static int check_inhibitors(DBusConnection *bus, enum action a) {
2122 #ifdef HAVE_LOGIND
2123         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2124         DBusMessageIter iter, sub, sub2;
2125         int r;
2126         unsigned c = 0;
2127         _cleanup_strv_free_ char **sessions = NULL;
2128         char **s;
2129
2130         if (!bus)
2131                 return 0;
2132
2133         if (arg_ignore_inhibitors || arg_force > 0)
2134                 return 0;
2135
2136         if (arg_when > 0)
2137                 return 0;
2138
2139         if (geteuid() == 0)
2140                 return 0;
2141
2142         if (!on_tty())
2143                 return 0;
2144
2145         r = bus_method_call_with_reply(
2146                         bus,
2147                         "org.freedesktop.login1",
2148                         "/org/freedesktop/login1",
2149                         "org.freedesktop.login1.Manager",
2150                         "ListInhibitors",
2151                         &reply,
2152                         NULL,
2153                         DBUS_TYPE_INVALID);
2154         if (r < 0)
2155                 /* If logind is not around, then there are no inhibitors... */
2156                 return 0;
2157
2158         if (!dbus_message_iter_init(reply, &iter) ||
2159             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2160             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
2161                 log_error("Failed to parse reply.");
2162                 return -EIO;
2163         }
2164
2165         dbus_message_iter_recurse(&iter, &sub);
2166         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2167                 const char *what, *who, *why, *mode;
2168                 uint32_t uid, pid;
2169                 _cleanup_strv_free_ char **sv = NULL;
2170                 _cleanup_free_ char *comm = NULL, *user = NULL;
2171
2172                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
2173                         log_error("Failed to parse reply.");
2174                         return -EIO;
2175                 }
2176
2177                 dbus_message_iter_recurse(&sub, &sub2);
2178
2179                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
2180                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
2181                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
2182                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
2183                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
2184                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
2185                         log_error("Failed to parse reply.");
2186                         return -EIO;
2187                 }
2188
2189                 if (!streq(mode, "block"))
2190                         goto next;
2191
2192                 sv = strv_split(what, ":");
2193                 if (!sv)
2194                         return log_oom();
2195
2196                 if (!strv_contains(sv,
2197                                   a == ACTION_HALT ||
2198                                   a == ACTION_POWEROFF ||
2199                                   a == ACTION_REBOOT ||
2200                                   a == ACTION_KEXEC ? "shutdown" : "sleep"))
2201                         goto next;
2202
2203                 get_process_comm(pid, &comm);
2204                 user = uid_to_name(uid);
2205                 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
2206                             who, (unsigned long) pid, strna(comm), strna(user), why);
2207                 c++;
2208
2209         next:
2210                 dbus_message_iter_next(&sub);
2211         }
2212
2213         dbus_message_iter_recurse(&iter, &sub);
2214
2215         /* Check for current sessions */
2216         sd_get_sessions(&sessions);
2217         STRV_FOREACH(s, sessions) {
2218                 uid_t uid;
2219                 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2220
2221                 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2222                         continue;
2223
2224                 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2225                         continue;
2226
2227                 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2228                         continue;
2229
2230                 sd_session_get_tty(*s, &tty);
2231                 sd_session_get_seat(*s, &seat);
2232                 sd_session_get_service(*s, &service);
2233                 user = uid_to_name(uid);
2234
2235                 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2236                 c++;
2237         }
2238
2239         if (c <= 0)
2240                 return 0;
2241
2242         log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
2243                   action_table[a].verb);
2244
2245         return -EPERM;
2246 #else
2247         return 0;
2248 #endif
2249 }
2250
2251 static int start_special(DBusConnection *bus, char **args) {
2252         enum action a;
2253         int r;
2254
2255         assert(args);
2256
2257         a = verb_to_action(args[0]);
2258
2259         r = check_inhibitors(bus, a);
2260         if (r < 0)
2261                 return r;
2262
2263         if (arg_force >= 2 && geteuid() != 0) {
2264                 log_error("Must be root.");
2265                 return -EPERM;
2266         }
2267
2268         if (arg_force >= 2 &&
2269             (a == ACTION_HALT ||
2270              a == ACTION_POWEROFF ||
2271              a == ACTION_REBOOT))
2272                 halt_now(a);
2273
2274         if (arg_force >= 1 &&
2275             (a == ACTION_HALT ||
2276              a == ACTION_POWEROFF ||
2277              a == ACTION_REBOOT ||
2278              a == ACTION_KEXEC ||
2279              a == ACTION_EXIT))
2280                 return daemon_reload(bus, args);
2281
2282         /* first try logind, to allow authentication with polkit */
2283         if (geteuid() != 0 &&
2284             (a == ACTION_POWEROFF ||
2285              a == ACTION_REBOOT ||
2286              a == ACTION_SUSPEND ||
2287              a == ACTION_HIBERNATE ||
2288              a == ACTION_HYBRID_SLEEP)) {
2289                 r = reboot_with_logind(bus, a);
2290                 if (r >= 0)
2291                         return r;
2292         }
2293
2294         r = start_unit(bus, args);
2295         if (r == EXIT_SUCCESS)
2296                 warn_wall(a);
2297
2298         return r;
2299 }
2300
2301 static int check_unit_active(DBusConnection *bus, char **args) {
2302         const char * const check_states[] = {
2303                 "active",
2304                 "reloading",
2305                 NULL
2306         };
2307
2308         char **name;
2309         int r = 3; /* According to LSB: "program is not running" */
2310
2311         assert(bus);
2312         assert(args);
2313
2314         STRV_FOREACH(name, args+1) {
2315                 int state;
2316
2317                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2318                 if (state < 0)
2319                         return state;
2320                 if (state > 0)
2321                         r = 0;
2322         }
2323
2324         return r;
2325 }
2326
2327 static int check_unit_failed(DBusConnection *bus, char **args) {
2328         const char * const check_states[] = {
2329                 "failed",
2330                 NULL
2331         };
2332
2333         char **name;
2334         int r = 1;
2335
2336         assert(bus);
2337         assert(args);
2338
2339         STRV_FOREACH(name, args+1) {
2340                 int state;
2341
2342                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
2343                 if (state < 0)
2344                         return state;
2345                 if (state > 0)
2346                         r = 0;
2347         }
2348
2349         return r;
2350 }
2351
2352 static int kill_unit(DBusConnection *bus, char **args) {
2353         char **name;
2354         int r = 0;
2355
2356         assert(bus);
2357         assert(args);
2358
2359         if (!arg_kill_who)
2360                 arg_kill_who = "all";
2361
2362         STRV_FOREACH(name, args+1) {
2363                 _cleanup_free_ char *n = NULL;
2364
2365                 n = unit_name_mangle(*name);
2366                 if (!n)
2367                         return log_oom();
2368
2369                 r = bus_method_call_with_reply(
2370                                 bus,
2371                                 "org.freedesktop.systemd1",
2372                                 "/org/freedesktop/systemd1",
2373                                 "org.freedesktop.systemd1.Manager",
2374                                 "KillUnit",
2375                                 NULL,
2376                                 NULL,
2377                                 DBUS_TYPE_STRING, &n,
2378                                 DBUS_TYPE_STRING, &arg_kill_who,
2379                                 DBUS_TYPE_INT32, &arg_signal,
2380                                 DBUS_TYPE_INVALID);
2381                 if (r < 0)
2382                         return r;
2383         }
2384         return 0;
2385 }
2386
2387 typedef struct ExecStatusInfo {
2388         char *name;
2389
2390         char *path;
2391         char **argv;
2392
2393         bool ignore;
2394
2395         usec_t start_timestamp;
2396         usec_t exit_timestamp;
2397         pid_t pid;
2398         int code;
2399         int status;
2400
2401         LIST_FIELDS(struct ExecStatusInfo, exec);
2402 } ExecStatusInfo;
2403
2404 static void exec_status_info_free(ExecStatusInfo *i) {
2405         assert(i);
2406
2407         free(i->name);
2408         free(i->path);
2409         strv_free(i->argv);
2410         free(i);
2411 }
2412
2413 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2414         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2415         DBusMessageIter sub2, sub3;
2416         const char*path;
2417         unsigned n;
2418         uint32_t pid;
2419         int32_t code, status;
2420         dbus_bool_t ignore;
2421
2422         assert(i);
2423         assert(i);
2424
2425         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2426                 return -EIO;
2427
2428         dbus_message_iter_recurse(sub, &sub2);
2429
2430         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2431                 return -EIO;
2432
2433         i->path = strdup(path);
2434         if (!i->path)
2435                 return -ENOMEM;
2436
2437         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2438             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2439                 return -EIO;
2440
2441         n = 0;
2442         dbus_message_iter_recurse(&sub2, &sub3);
2443         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2444                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2445                 dbus_message_iter_next(&sub3);
2446                 n++;
2447         }
2448
2449         i->argv = new0(char*, n+1);
2450         if (!i->argv)
2451                 return -ENOMEM;
2452
2453         n = 0;
2454         dbus_message_iter_recurse(&sub2, &sub3);
2455         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2456                 const char *s;
2457
2458                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2459                 dbus_message_iter_get_basic(&sub3, &s);
2460                 dbus_message_iter_next(&sub3);
2461
2462                 i->argv[n] = strdup(s);
2463                 if (!i->argv[n])
2464                         return -ENOMEM;
2465
2466                 n++;
2467         }
2468
2469         if (!dbus_message_iter_next(&sub2) ||
2470             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2471             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2472             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2473             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2474             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2475             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2476             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2477             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2478                 return -EIO;
2479
2480         i->ignore = ignore;
2481         i->start_timestamp = (usec_t) start_timestamp;
2482         i->exit_timestamp = (usec_t) exit_timestamp;
2483         i->pid = (pid_t) pid;
2484         i->code = code;
2485         i->status = status;
2486
2487         return 0;
2488 }
2489
2490 typedef struct UnitStatusInfo {
2491         const char *id;
2492         const char *load_state;
2493         const char *active_state;
2494         const char *sub_state;
2495         const char *unit_file_state;
2496
2497         const char *description;
2498         const char *following;
2499
2500         char **documentation;
2501
2502         const char *fragment_path;
2503         const char *source_path;
2504         const char *control_group;
2505
2506         char **dropin_paths;
2507
2508         const char *load_error;
2509         const char *result;
2510
2511         usec_t inactive_exit_timestamp;
2512         usec_t inactive_exit_timestamp_monotonic;
2513         usec_t active_enter_timestamp;
2514         usec_t active_exit_timestamp;
2515         usec_t inactive_enter_timestamp;
2516
2517         bool need_daemon_reload;
2518
2519         /* Service */
2520         pid_t main_pid;
2521         pid_t control_pid;
2522         const char *status_text;
2523         const char *pid_file;
2524         bool running:1;
2525
2526         usec_t start_timestamp;
2527         usec_t exit_timestamp;
2528
2529         int exit_code, exit_status;
2530
2531         usec_t condition_timestamp;
2532         bool condition_result;
2533
2534         /* Socket */
2535         unsigned n_accepted;
2536         unsigned n_connections;
2537         bool accept;
2538
2539         /* Pairs of type, path */
2540         char **listen;
2541
2542         /* Device */
2543         const char *sysfs_path;
2544
2545         /* Mount, Automount */
2546         const char *where;
2547
2548         /* Swap */
2549         const char *what;
2550
2551         LIST_HEAD(ExecStatusInfo, exec);
2552 } UnitStatusInfo;
2553
2554 static void print_status_info(UnitStatusInfo *i) {
2555         ExecStatusInfo *p;
2556         const char *on, *off, *ss;
2557         usec_t timestamp;
2558         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2559         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2560         const char *path;
2561         int flags =
2562                 arg_all * OUTPUT_SHOW_ALL |
2563                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2564                 on_tty() * OUTPUT_COLOR |
2565                 !arg_quiet * OUTPUT_WARN_CUTOFF |
2566                 arg_full * OUTPUT_FULL_WIDTH;
2567         char **t, **t2;
2568
2569         assert(i);
2570
2571         /* This shows pretty information about a unit. See
2572          * print_property() for a low-level property printer */
2573
2574         printf("%s", strna(i->id));
2575
2576         if (i->description && !streq_ptr(i->id, i->description))
2577                 printf(" - %s", i->description);
2578
2579         printf("\n");
2580
2581         if (i->following)
2582                 printf("   Follow: unit currently follows state of %s\n", i->following);
2583
2584         if (streq_ptr(i->load_state, "error")) {
2585                 on = ansi_highlight_red(true);
2586                 off = ansi_highlight_red(false);
2587         } else
2588                 on = off = "";
2589
2590         path = i->source_path ? i->source_path : i->fragment_path;
2591
2592         if (i->load_error)
2593                 printf("   Loaded: %s%s%s (Reason: %s)\n",
2594                        on, strna(i->load_state), off, i->load_error);
2595         else if (path && i->unit_file_state)
2596                 printf("   Loaded: %s%s%s (%s; %s)\n",
2597                        on, strna(i->load_state), off, path, i->unit_file_state);
2598         else if (path)
2599                 printf("   Loaded: %s%s%s (%s)\n",
2600                        on, strna(i->load_state), off, path);
2601         else
2602                 printf("   Loaded: %s%s%s\n",
2603                        on, strna(i->load_state), off);
2604
2605         if (!strv_isempty(i->dropin_paths)) {
2606                 char ** dropin;
2607                 char * dir = NULL;
2608                 bool last = false;
2609
2610                 STRV_FOREACH(dropin, i->dropin_paths) {
2611                         if (! dir || last) {
2612                                 printf(dir ? "        " : "  Drop-In: ");
2613
2614                                 free(dir);
2615
2616                                 if (path_get_parent(*dropin, &dir) < 0) {
2617                                         log_oom();
2618                                         return;
2619                                 }
2620
2621                                 printf("%s\n           %s", dir,
2622                                        draw_special_char(DRAW_TREE_RIGHT));
2623                         }
2624
2625                         last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2626
2627                         printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2628                 }
2629
2630                 free(dir);
2631         }
2632
2633         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2634
2635         if (streq_ptr(i->active_state, "failed")) {
2636                 on = ansi_highlight_red(true);
2637                 off = ansi_highlight_red(false);
2638         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2639                 on = ansi_highlight_green(true);
2640                 off = ansi_highlight_green(false);
2641         } else
2642                 on = off = "";
2643
2644         if (ss)
2645                 printf("   Active: %s%s (%s)%s",
2646                        on, strna(i->active_state), ss, off);
2647         else
2648                 printf("   Active: %s%s%s",
2649                        on, strna(i->active_state), off);
2650
2651         if (!isempty(i->result) && !streq(i->result, "success"))
2652                 printf(" (Result: %s)", i->result);
2653
2654         timestamp = (streq_ptr(i->active_state, "active")      ||
2655                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2656                     (streq_ptr(i->active_state, "inactive")    ||
2657                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2658                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2659                                                                   i->active_exit_timestamp;
2660
2661         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2662         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2663
2664         if (s1)
2665                 printf(" since %s; %s\n", s2, s1);
2666         else if (s2)
2667                 printf(" since %s\n", s2);
2668         else
2669                 printf("\n");
2670
2671         if (!i->condition_result && i->condition_timestamp > 0) {
2672                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2673                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2674
2675                 if (s1)
2676                         printf("          start condition failed at %s; %s\n", s2, s1);
2677                 else if (s2)
2678                         printf("          start condition failed at %s\n", s2);
2679         }
2680
2681         if (i->sysfs_path)
2682                 printf("   Device: %s\n", i->sysfs_path);
2683         if (i->where)
2684                 printf("    Where: %s\n", i->where);
2685         if (i->what)
2686                 printf("     What: %s\n", i->what);
2687
2688         STRV_FOREACH(t, i->documentation)
2689                 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
2690
2691         STRV_FOREACH_PAIR(t, t2, i->listen)
2692                 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
2693
2694         if (i->accept)
2695                 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2696
2697         LIST_FOREACH(exec, p, i->exec) {
2698                 _cleanup_free_ char *argv = NULL;
2699                 bool good;
2700
2701                 /* Only show exited processes here */
2702                 if (p->code == 0)
2703                         continue;
2704
2705                 argv = strv_join(p->argv, " ");
2706                 printf("  Process: %u %s=%s ", p->pid, p->name, strna(argv));
2707
2708                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2709                 if (!good) {
2710                         on = ansi_highlight_red(true);
2711                         off = ansi_highlight_red(false);
2712                 } else
2713                         on = off = "";
2714
2715                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2716
2717                 if (p->code == CLD_EXITED) {
2718                         const char *c;
2719
2720                         printf("status=%i", p->status);
2721
2722                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2723                         if (c)
2724                                 printf("/%s", c);
2725
2726                 } else
2727                         printf("signal=%s", signal_to_string(p->status));
2728
2729                 printf(")%s\n", off);
2730
2731                 if (i->main_pid == p->pid &&
2732                     i->start_timestamp == p->start_timestamp &&
2733                     i->exit_timestamp == p->start_timestamp)
2734                         /* Let's not show this twice */
2735                         i->main_pid = 0;
2736
2737                 if (p->pid == i->control_pid)
2738                         i->control_pid = 0;
2739         }
2740
2741         if (i->main_pid > 0 || i->control_pid > 0) {
2742                 if (i->main_pid > 0) {
2743                         printf(" Main PID: %u", (unsigned) i->main_pid);
2744
2745                         if (i->running) {
2746                                 _cleanup_free_ char *comm = NULL;
2747                                 get_process_comm(i->main_pid, &comm);
2748                                 if (comm)
2749                                         printf(" (%s)", comm);
2750                         } else if (i->exit_code > 0) {
2751                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2752
2753                                 if (i->exit_code == CLD_EXITED) {
2754                                         const char *c;
2755
2756                                         printf("status=%i", i->exit_status);
2757
2758                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2759                                         if (c)
2760                                                 printf("/%s", c);
2761
2762                                 } else
2763                                         printf("signal=%s", signal_to_string(i->exit_status));
2764                                 printf(")");
2765                         }
2766
2767                         if (i->control_pid > 0)
2768                                 printf(";");
2769                 }
2770
2771                 if (i->control_pid > 0) {
2772                         _cleanup_free_ char *c = NULL;
2773
2774                         printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
2775
2776                         get_process_comm(i->control_pid, &c);
2777                         if (c)
2778                                 printf(" (%s)", c);
2779                 }
2780
2781                 printf("\n");
2782         }
2783
2784         if (i->status_text)
2785                 printf("   Status: \"%s\"\n", i->status_text);
2786
2787         if (i->control_group &&
2788             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
2789                 unsigned c;
2790
2791                 printf("   CGroup: %s\n", i->control_group);
2792
2793                 if (arg_transport != TRANSPORT_SSH) {
2794                         unsigned k = 0;
2795                         pid_t extra[2];
2796                         char prefix[] = "           ";
2797
2798                         c = columns();
2799                         if (c > sizeof(prefix) - 1)
2800                                 c -= sizeof(prefix) - 1;
2801                         else
2802                                 c = 0;
2803
2804                         if (i->main_pid > 0)
2805                                 extra[k++] = i->main_pid;
2806
2807                         if (i->control_pid > 0)
2808                                 extra[k++] = i->control_pid;
2809
2810                         show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix,
2811                                                       c, false, extra, k, flags);
2812                 }
2813         }
2814
2815         if (i->id && arg_transport != TRANSPORT_SSH) {
2816                 printf("\n");
2817                 show_journal_by_unit(stdout,
2818                                      i->id,
2819                                      arg_output,
2820                                      0,
2821                                      i->inactive_exit_timestamp_monotonic,
2822                                      arg_lines,
2823                                      getuid(),
2824                                      flags,
2825                                      arg_scope == UNIT_FILE_SYSTEM);
2826         }
2827
2828         if (i->need_daemon_reload)
2829                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
2830                        ansi_highlight_red(true),
2831                        ansi_highlight_red(false),
2832                        arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
2833 }
2834
2835 static void show_unit_help(UnitStatusInfo *i) {
2836         char **p;
2837
2838         assert(i);
2839
2840         if (!i->documentation) {
2841                 log_info("Documentation for %s not known.", i->id);
2842                 return;
2843         }
2844
2845         STRV_FOREACH(p, i->documentation) {
2846
2847                 if (startswith(*p, "man:")) {
2848                         size_t k;
2849                         char *e = NULL;
2850                         _cleanup_free_ char *page = NULL, *section = NULL;
2851                         const char *args[4] = { "man", NULL, NULL, NULL };
2852                         pid_t pid;
2853
2854                         k = strlen(*p);
2855
2856                         if ((*p)[k-1] == ')')
2857                                 e = strrchr(*p, '(');
2858
2859                         if (e) {
2860                                 page = strndup((*p) + 4, e - *p - 4);
2861                                 section = strndup(e + 1, *p + k - e - 2);
2862                                 if (!page || !section) {
2863                                         log_oom();
2864                                         return;
2865                                 }
2866
2867                                 args[1] = section;
2868                                 args[2] = page;
2869                         } else
2870                                 args[1] = *p + 4;
2871
2872                         pid = fork();
2873                         if (pid < 0) {
2874                                 log_error("Failed to fork: %m");
2875                                 continue;
2876                         }
2877
2878                         if (pid == 0) {
2879                                 /* Child */
2880                                 execvp(args[0], (char**) args);
2881                                 log_error("Failed to execute man: %m");
2882                                 _exit(EXIT_FAILURE);
2883                         }
2884
2885                         wait_for_terminate(pid, NULL);
2886                 } else
2887                         log_info("Can't show: %s", *p);
2888         }
2889 }
2890
2891 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2892
2893         assert(name);
2894         assert(iter);
2895         assert(i);
2896
2897         switch (dbus_message_iter_get_arg_type(iter)) {
2898
2899         case DBUS_TYPE_STRING: {
2900                 const char *s;
2901
2902                 dbus_message_iter_get_basic(iter, &s);
2903
2904                 if (!isempty(s)) {
2905                         if (streq(name, "Id"))
2906                                 i->id = s;
2907                         else if (streq(name, "LoadState"))
2908                                 i->load_state = s;
2909                         else if (streq(name, "ActiveState"))
2910                                 i->active_state = s;
2911                         else if (streq(name, "SubState"))
2912                                 i->sub_state = s;
2913                         else if (streq(name, "Description"))
2914                                 i->description = s;
2915                         else if (streq(name, "FragmentPath"))
2916                                 i->fragment_path = s;
2917                         else if (streq(name, "SourcePath"))
2918                                 i->source_path = s;
2919 #ifndef LEGACY
2920                         else if (streq(name, "DefaultControlGroup")) {
2921                                 const char *e;
2922                                 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
2923                                 if (e)
2924                                         i->control_group = e;
2925                         }
2926 #endif
2927                         else if (streq(name, "ControlGroup"))
2928                                 i->control_group = s;
2929                         else if (streq(name, "StatusText"))
2930                                 i->status_text = s;
2931                         else if (streq(name, "PIDFile"))
2932                                 i->pid_file = s;
2933                         else if (streq(name, "SysFSPath"))
2934                                 i->sysfs_path = s;
2935                         else if (streq(name, "Where"))
2936                                 i->where = s;
2937                         else if (streq(name, "What"))
2938                                 i->what = s;
2939                         else if (streq(name, "Following"))
2940                                 i->following = s;
2941                         else if (streq(name, "UnitFileState"))
2942                                 i->unit_file_state = s;
2943                         else if (streq(name, "Result"))
2944                                 i->result = s;
2945                 }
2946
2947                 break;
2948         }
2949
2950         case DBUS_TYPE_BOOLEAN: {
2951                 dbus_bool_t b;
2952
2953                 dbus_message_iter_get_basic(iter, &b);
2954
2955                 if (streq(name, "Accept"))
2956                         i->accept = b;
2957                 else if (streq(name, "NeedDaemonReload"))
2958                         i->need_daemon_reload = b;
2959                 else if (streq(name, "ConditionResult"))
2960                         i->condition_result = b;
2961
2962                 break;
2963         }
2964
2965         case DBUS_TYPE_UINT32: {
2966                 uint32_t u;
2967
2968                 dbus_message_iter_get_basic(iter, &u);
2969
2970                 if (streq(name, "MainPID")) {
2971                         if (u > 0) {
2972                                 i->main_pid = (pid_t) u;
2973                                 i->running = true;
2974                         }
2975                 } else if (streq(name, "ControlPID"))
2976                         i->control_pid = (pid_t) u;
2977                 else if (streq(name, "ExecMainPID")) {
2978                         if (u > 0)
2979                                 i->main_pid = (pid_t) u;
2980                 } else if (streq(name, "NAccepted"))
2981                         i->n_accepted = u;
2982                 else if (streq(name, "NConnections"))
2983                         i->n_connections = u;
2984
2985                 break;
2986         }
2987
2988         case DBUS_TYPE_INT32: {
2989                 int32_t j;
2990
2991                 dbus_message_iter_get_basic(iter, &j);
2992
2993                 if (streq(name, "ExecMainCode"))
2994                         i->exit_code = (int) j;
2995                 else if (streq(name, "ExecMainStatus"))
2996                         i->exit_status = (int) j;
2997
2998                 break;
2999         }
3000
3001         case DBUS_TYPE_UINT64: {
3002                 uint64_t u;
3003
3004                 dbus_message_iter_get_basic(iter, &u);
3005
3006                 if (streq(name, "ExecMainStartTimestamp"))
3007                         i->start_timestamp = (usec_t) u;
3008                 else if (streq(name, "ExecMainExitTimestamp"))
3009                         i->exit_timestamp = (usec_t) u;
3010                 else if (streq(name, "ActiveEnterTimestamp"))
3011                         i->active_enter_timestamp = (usec_t) u;
3012                 else if (streq(name, "InactiveEnterTimestamp"))
3013                         i->inactive_enter_timestamp = (usec_t) u;
3014                 else if (streq(name, "InactiveExitTimestamp"))
3015                         i->inactive_exit_timestamp = (usec_t) u;
3016                 else if (streq(name, "InactiveExitTimestampMonotonic"))
3017                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
3018                 else if (streq(name, "ActiveExitTimestamp"))
3019                         i->active_exit_timestamp = (usec_t) u;
3020                 else if (streq(name, "ConditionTimestamp"))
3021                         i->condition_timestamp = (usec_t) u;
3022
3023                 break;
3024         }
3025
3026         case DBUS_TYPE_ARRAY: {
3027
3028                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3029                     startswith(name, "Exec")) {
3030                         DBusMessageIter sub;
3031
3032                         dbus_message_iter_recurse(iter, &sub);
3033                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3034                                 ExecStatusInfo *info;
3035                                 int r;
3036
3037                                 if (!(info = new0(ExecStatusInfo, 1)))
3038                                         return -ENOMEM;
3039
3040                                 if (!(info->name = strdup(name))) {
3041                                         free(info);
3042                                         return -ENOMEM;
3043                                 }
3044
3045                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
3046                                         free(info);
3047                                         return r;
3048                                 }
3049
3050                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
3051
3052                                 dbus_message_iter_next(&sub);
3053                         }
3054
3055                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3056                         DBusMessageIter sub, sub2;
3057
3058                         dbus_message_iter_recurse(iter, &sub);
3059                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3060                                 const char *type, *path;
3061
3062                                 dbus_message_iter_recurse(&sub, &sub2);
3063
3064                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3065                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
3066                                         int r;
3067
3068                                         r = strv_extend(&i->listen, type);
3069                                         if (r < 0)
3070                                                 return r;
3071                                         r = strv_extend(&i->listen, path);
3072                                         if (r < 0)
3073                                                 return r;
3074                                 }
3075
3076                                 dbus_message_iter_next(&sub);
3077                         }
3078
3079                         return 0;
3080
3081                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
3082                         int r = bus_parse_strv_iter(iter, &i->dropin_paths);
3083                         if (r < 0)
3084                                 return r;
3085
3086                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
3087                            streq(name, "Documentation")) {
3088
3089                         DBusMessageIter sub;
3090
3091                         dbus_message_iter_recurse(iter, &sub);
3092                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
3093                                 const char *s;
3094                                 int r;
3095
3096                                 dbus_message_iter_get_basic(&sub, &s);
3097
3098                                 r = strv_extend(&i->documentation, s);
3099                                 if (r < 0)
3100                                         return r;
3101
3102                                 dbus_message_iter_next(&sub);
3103                         }
3104                 }
3105
3106                 break;
3107         }
3108
3109         case DBUS_TYPE_STRUCT: {
3110
3111                 if (streq(name, "LoadError")) {
3112                         DBusMessageIter sub;
3113                         const char *n, *message;
3114                         int r;
3115
3116                         dbus_message_iter_recurse(iter, &sub);
3117
3118                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
3119                         if (r < 0)
3120                                 return r;
3121
3122                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
3123                         if (r < 0)
3124                                 return r;
3125
3126                         if (!isempty(message))
3127                                 i->load_error = message;
3128                 }
3129
3130                 break;
3131         }
3132         }
3133
3134         return 0;
3135 }
3136
3137 static int print_property(const char *name, DBusMessageIter *iter) {
3138         assert(name);
3139         assert(iter);
3140
3141         /* This is a low-level property printer, see
3142          * print_status_info() for the nicer output */
3143
3144         if (arg_properties && !strv_find(arg_properties, name))
3145                 return 0;
3146
3147         switch (dbus_message_iter_get_arg_type(iter)) {
3148
3149         case DBUS_TYPE_STRUCT: {
3150                 DBusMessageIter sub;
3151                 dbus_message_iter_recurse(iter, &sub);
3152
3153                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
3154                         uint32_t u;
3155
3156                         dbus_message_iter_get_basic(&sub, &u);
3157
3158                         if (u)
3159                                 printf("%s=%u\n", name, (unsigned) u);
3160                         else if (arg_all)
3161                                 printf("%s=\n", name);
3162
3163                         return 0;
3164                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
3165                         const char *s;
3166
3167                         dbus_message_iter_get_basic(&sub, &s);
3168
3169                         if (arg_all || s[0])
3170                                 printf("%s=%s\n", name, s);
3171
3172                         return 0;
3173                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
3174                         const char *a = NULL, *b = NULL;
3175
3176                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
3177                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
3178
3179                         if (arg_all || !isempty(a) || !isempty(b))
3180                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
3181
3182                         return 0;
3183                 }
3184
3185                 break;
3186         }
3187
3188         case DBUS_TYPE_ARRAY:
3189
3190                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
3191                         DBusMessageIter sub, sub2;
3192
3193                         dbus_message_iter_recurse(iter, &sub);
3194                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3195                                 const char *path;
3196                                 dbus_bool_t ignore;
3197
3198                                 dbus_message_iter_recurse(&sub, &sub2);
3199
3200                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3201                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
3202                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
3203
3204                                 dbus_message_iter_next(&sub);
3205                         }
3206
3207                         return 0;
3208
3209                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
3210                         DBusMessageIter sub, sub2;
3211
3212                         dbus_message_iter_recurse(iter, &sub);
3213
3214                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3215                                 const char *type, *path;
3216
3217                                 dbus_message_iter_recurse(&sub, &sub2);
3218
3219                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3220                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3221                                         printf("%s=%s\n", type, path);
3222
3223                                 dbus_message_iter_next(&sub);
3224                         }
3225
3226                         return 0;
3227
3228                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3229                         DBusMessageIter sub, sub2;
3230
3231                         dbus_message_iter_recurse(iter, &sub);
3232                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3233                                 const char *type, *path;
3234
3235                                 dbus_message_iter_recurse(&sub, &sub2);
3236
3237                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3238                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3239                                         printf("Listen%s=%s\n", type, path);
3240
3241                                 dbus_message_iter_next(&sub);
3242                         }
3243
3244                         return 0;
3245
3246                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
3247                         DBusMessageIter sub, sub2;
3248
3249                         dbus_message_iter_recurse(iter, &sub);
3250                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3251                                 const char *base;
3252                                 uint64_t value, next_elapse;
3253
3254                                 dbus_message_iter_recurse(&sub, &sub2);
3255
3256                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
3257                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
3258                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
3259                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
3260
3261                                         printf("%s={ value=%s ; next_elapse=%s }\n",
3262                                                base,
3263                                                format_timespan(timespan1, sizeof(timespan1), value, 0),
3264                                                format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
3265                                 }
3266
3267                                 dbus_message_iter_next(&sub);
3268                         }
3269
3270                         return 0;
3271
3272                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3273                         DBusMessageIter sub;
3274
3275                         dbus_message_iter_recurse(iter, &sub);
3276                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3277                                 ExecStatusInfo info = {};
3278
3279                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3280                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3281                                         _cleanup_free_ char *t;
3282
3283                                         t = strv_join(info.argv, " ");
3284
3285                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3286                                                name,
3287                                                strna(info.path),
3288                                                strna(t),
3289                                                yes_no(info.ignore),
3290                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3291                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3292                                                (unsigned) info. pid,
3293                                                sigchld_code_to_string(info.code),
3294                                                info.status,
3295                                                info.code == CLD_EXITED ? "" : "/",
3296                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3297                                 }
3298
3299                                 free(info.path);
3300                                 strv_free(info.argv);
3301
3302                                 dbus_message_iter_next(&sub);
3303                         }
3304
3305                         return 0;
3306
3307                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "DeviceAllow")) {
3308                         DBusMessageIter sub, sub2;
3309
3310                         dbus_message_iter_recurse(iter, &sub);
3311                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3312                                 const char *path, *rwm;
3313
3314                                 dbus_message_iter_recurse(&sub, &sub2);
3315
3316                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3317                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) >= 0)
3318                                         printf("%s=%s %s\n", name, strna(path), strna(rwm));
3319
3320                                 dbus_message_iter_next(&sub);
3321                         }
3322                         return 0;
3323
3324                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
3325                         DBusMessageIter sub, sub2;
3326
3327                         dbus_message_iter_recurse(iter, &sub);
3328                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3329                                 const char *path;
3330                                 uint64_t bandwidth;
3331
3332                                 dbus_message_iter_recurse(&sub, &sub2);
3333
3334                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3335                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &bandwidth, false) >= 0)
3336                                         printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
3337
3338                                 dbus_message_iter_next(&sub);
3339                         }
3340                         return 0;
3341                 }
3342
3343
3344                 break;
3345         }
3346
3347         if (generic_print_property(name, iter, arg_all) > 0)
3348                 return 0;
3349
3350         if (arg_all)
3351                 printf("%s=[unprintable]\n", name);
3352
3353         return 0;
3354 }
3355
3356 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3357         _cleanup_free_ DBusMessage *reply = NULL;
3358         const char *interface = "";
3359         int r;
3360         DBusMessageIter iter, sub, sub2, sub3;
3361         UnitStatusInfo info = {};
3362         ExecStatusInfo *p;
3363
3364         assert(path);
3365         assert(new_line);
3366
3367         r = bus_method_call_with_reply(
3368                         bus,
3369                         "org.freedesktop.systemd1",
3370                         path,
3371                         "org.freedesktop.DBus.Properties",
3372                         "GetAll",
3373                         &reply,
3374                         NULL,
3375                         DBUS_TYPE_STRING, &interface,
3376                         DBUS_TYPE_INVALID);
3377         if (r < 0)
3378                 return r;
3379
3380         if (!dbus_message_iter_init(reply, &iter) ||
3381             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3382             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3383                 log_error("Failed to parse reply.");
3384                 return -EIO;
3385         }
3386
3387         dbus_message_iter_recurse(&iter, &sub);
3388
3389         if (*new_line)
3390                 printf("\n");
3391
3392         *new_line = true;
3393
3394         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3395                 const char *name;
3396
3397                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
3398                 dbus_message_iter_recurse(&sub, &sub2);
3399
3400                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
3401                     dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
3402                         log_error("Failed to parse reply.");
3403                         return -EIO;
3404                 }
3405
3406                 dbus_message_iter_recurse(&sub2, &sub3);
3407
3408                 if (show_properties)
3409                         r = print_property(name, &sub3);
3410                 else
3411                         r = status_property(name, &sub3, &info);
3412                 if (r < 0) {
3413                         log_error("Failed to parse reply.");
3414                         return -EIO;
3415                 }
3416
3417                 dbus_message_iter_next(&sub);
3418         }
3419
3420         r = 0;
3421
3422         if (!show_properties) {
3423                 if (streq(verb, "help"))
3424                         show_unit_help(&info);
3425                 else
3426                         print_status_info(&info);
3427         }
3428
3429         strv_free(info.documentation);
3430         strv_free(info.dropin_paths);
3431         strv_free(info.listen);
3432
3433         if (!streq_ptr(info.active_state, "active") &&
3434             !streq_ptr(info.active_state, "reloading") &&
3435             streq(verb, "status")) {
3436                 /* According to LSB: "program not running" */
3437                 /* 0: program is running or service is OK
3438                  * 1: program is dead and /var/run pid file exists
3439                  * 2: program is dead and /var/lock lock file exists
3440                  * 3: program is not running
3441                  * 4: program or service status is unknown
3442                  */
3443                 if (info.pid_file && access(info.pid_file, F_OK) == 0)
3444                         r = 1;
3445                 else
3446                         r = 3;
3447         }
3448
3449         while ((p = info.exec)) {
3450                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3451                 exec_status_info_free(p);
3452         }
3453
3454         return r;
3455 }
3456
3457 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3458         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3459         const char *path = NULL;
3460         _cleanup_dbus_error_free_ DBusError error;
3461         int r;
3462
3463         dbus_error_init(&error);
3464
3465         r = bus_method_call_with_reply(
3466                         bus,
3467                         "org.freedesktop.systemd1",
3468                         "/org/freedesktop/systemd1",
3469                         "org.freedesktop.systemd1.Manager",
3470                         "GetUnitByPID",
3471                         &reply,
3472                         NULL,
3473                         DBUS_TYPE_UINT32, &pid,
3474                         DBUS_TYPE_INVALID);
3475         if (r < 0)
3476                 return r;
3477
3478         if (!dbus_message_get_args(reply, &error,
3479                                    DBUS_TYPE_OBJECT_PATH, &path,
3480                                    DBUS_TYPE_INVALID)) {
3481                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3482                 return -EIO;
3483         }
3484
3485         r = show_one(verb, bus, path, false, new_line);
3486         return r;
3487 }
3488
3489 static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) {
3490         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3491         _cleanup_free_ struct unit_info *unit_infos = NULL;
3492         unsigned c = 0;
3493         const struct unit_info *u;
3494         int r;
3495
3496         r = get_unit_list(bus, &reply, &unit_infos, &c);
3497         if (r < 0)
3498                 return r;
3499
3500         qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
3501
3502         for (u = unit_infos; u < unit_infos + c; u++) {
3503                 _cleanup_free_ char *p = NULL;
3504
3505                 if (!output_show_unit(u))
3506                         continue;
3507
3508                 p = unit_dbus_path_from_name(u->id);
3509                 if (!p)
3510                         return log_oom();
3511
3512                 printf("%s -> '%s'\n", u->id, p);
3513
3514                 r = show_one(verb, bus, p, show_properties, new_line);
3515                 if (r != 0)
3516                         return r;
3517         }
3518
3519         return 0;
3520 }
3521
3522 static int show(DBusConnection *bus, char **args) {
3523         int r, ret = 0;
3524         bool show_properties, show_status, new_line = false;
3525         char **name;
3526
3527         assert(bus);
3528         assert(args);
3529
3530         show_properties = streq(args[0], "show");
3531         show_status = streq(args[0], "status");
3532
3533         if (show_properties)
3534                 pager_open_if_enabled();
3535
3536         /* If no argument is specified inspect the manager itself */
3537
3538         if (show_properties && strv_length(args) <= 1)
3539                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3540
3541         if (show_status && strv_length(args) <= 1)
3542                 return show_all(args[0], bus, false, &new_line);
3543
3544         STRV_FOREACH(name, args+1) {
3545                 uint32_t id;
3546
3547                 if (safe_atou32(*name, &id) < 0) {
3548                         _cleanup_free_ char *p = NULL, *n = NULL;
3549                         /* Interpret as unit name */
3550
3551                         n = unit_name_mangle(*name);
3552                         if (!n)
3553                                 return log_oom();
3554
3555                         p = unit_dbus_path_from_name(n);
3556                         if (!p)
3557                                 return log_oom();
3558
3559                         r = show_one(args[0], bus, p, show_properties, &new_line);
3560                         if (r != 0)
3561                                 ret = r;
3562
3563                 } else if (show_properties) {
3564                         _cleanup_free_ char *p = NULL;
3565
3566                         /* Interpret as job id */
3567                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3568                                 return log_oom();
3569
3570                         r = show_one(args[0], bus, p, show_properties, &new_line);
3571                         if (r != 0)
3572                                 ret = r;
3573
3574                 } else {
3575                         /* Interpret as PID */
3576                         r = show_one_by_pid(args[0], bus, id, &new_line);
3577                         if (r != 0)
3578                                 ret = r;
3579                 }
3580         }
3581
3582         return ret;
3583 }
3584
3585 static int append_assignment(DBusMessageIter *iter, const char *assignment) {
3586         const char *eq;
3587         char *field;
3588         DBusMessageIter sub;
3589         int r;
3590
3591         assert(iter);
3592         assert(assignment);
3593
3594         eq = strchr(assignment, '=');
3595         if (!eq) {
3596                 log_error("Not an assignment: %s", assignment);
3597                 return -EINVAL;
3598         }
3599
3600         field = strndupa(assignment, eq - assignment);
3601         eq ++;
3602
3603         if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field))
3604                 return log_oom();
3605
3606         if (streq(field, "CPUAccounting") ||
3607             streq(field, "MemoryAccounting") ||
3608             streq(field, "BlockIOAccounting")) {
3609                 dbus_bool_t b;
3610
3611                 r = parse_boolean(eq);
3612                 if (r < 0) {
3613                         log_error("Failed to parse boolean assignment %s.", assignment);
3614                         return -EINVAL;
3615                 }
3616
3617                 b = r;
3618                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "b", &sub) ||
3619                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
3620                         return log_oom();
3621
3622         } else if (streq(field, "MemoryLimit") || streq(field, "MemorySoftLimit")) {
3623                 off_t bytes;
3624                 uint64_t u;
3625
3626                 r = parse_bytes(eq, &bytes);
3627                 if (r < 0) {
3628                         log_error("Failed to parse bytes specification %s", assignment);
3629                         return -EINVAL;
3630                 }
3631
3632                 u = bytes;
3633                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
3634                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
3635                         return log_oom();
3636
3637         } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
3638                 uint64_t u;
3639
3640                 r = safe_atou64(eq, &u);
3641                 if (r < 0) {
3642                         log_error("Failed to parse %s value %s.", field, eq);
3643                         return -EINVAL;
3644                 }
3645
3646                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
3647                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
3648                         return log_oom();
3649
3650         } else if (streq(field, "DevicePolicy")) {
3651
3652                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &sub) ||
3653                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &eq))
3654                         return log_oom();
3655
3656         } else if (streq(field, "DeviceAllow")) {
3657                 DBusMessageIter sub2;
3658
3659                 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(ss)", &sub) ||
3660                     !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(ss)", &sub2))
3661                         return log_oom();
3662
3663                 if (!isempty(eq)) {
3664                         const char *path, *rwm;
3665                         DBusMessageIter sub3;
3666                         char *e;
3667
3668                         e = strchr(eq, ' ');
3669                         if (e) {
3670                                 path = strndupa(eq, e - eq);
3671                                 rwm = e+1;
3672                         } else {
3673                                 path = eq;
3674                                 rwm = "";
3675                         }
3676
3677                         if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3678                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3679                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &rwm) ||
3680                             !dbus_message_iter_close_container(&sub2, &sub3))
3681                                 return log_oom();
3682                 }
3683
3684                 if (!dbus_message_iter_close_container(&sub, &sub2))
3685                         return log_oom();
3686
3687         } else {
3688                 log_error("Unknown assignment %s.", assignment);
3689                 return -EINVAL;
3690         }
3691
3692         if (!dbus_message_iter_close_container(iter, &sub))
3693                 return log_oom();
3694
3695         return 0;
3696 }
3697
3698 static int set_property(DBusConnection *bus, char **args) {
3699
3700         _cleanup_free_ DBusMessage *m = NULL, *reply = NULL;
3701         DBusMessageIter iter, sub;
3702         dbus_bool_t runtime;
3703         DBusError error;
3704         char **i;
3705         int r;
3706
3707         dbus_error_init(&error);
3708
3709         m = dbus_message_new_method_call(
3710                         "org.freedesktop.systemd1",
3711                         "/org/freedesktop/systemd1",
3712                         "org.freedesktop.systemd1.Manager",
3713                         "SetUnitProperties");
3714         if (!m)
3715                 return log_oom();
3716
3717         dbus_message_iter_init_append(m, &iter);
3718
3719         runtime = arg_runtime;
3720
3721         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[1]) ||
3722             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &runtime) ||
3723             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
3724                 return log_oom();
3725
3726         STRV_FOREACH(i, args + 2) {
3727                 DBusMessageIter sub2;
3728
3729                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
3730                         return log_oom();
3731
3732                 r = append_assignment(&sub2, *i);
3733                 if (r < 0)
3734                         return r;
3735
3736                 if (!dbus_message_iter_close_container(&sub, &sub2))
3737                         return log_oom();
3738
3739         }
3740
3741         if (!dbus_message_iter_close_container(&iter, &sub))
3742                 return log_oom();
3743
3744         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3745         if (!reply) {
3746                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3747                 dbus_error_free(&error);
3748                 return -EIO;
3749         }
3750
3751         return 0;
3752 }
3753
3754 static int dump(DBusConnection *bus, char **args) {
3755         _cleanup_free_ DBusMessage *reply = NULL;
3756         DBusError error;
3757         int r;
3758         const char *text;
3759
3760         dbus_error_init(&error);
3761
3762         pager_open_if_enabled();
3763
3764         r = bus_method_call_with_reply(
3765                         bus,
3766                         "org.freedesktop.systemd1",
3767                         "/org/freedesktop/systemd1",
3768                         "org.freedesktop.systemd1.Manager",
3769                         "Dump",
3770                         &reply,
3771                         NULL,
3772                         DBUS_TYPE_INVALID);
3773         if (r < 0)
3774                 return r;
3775
3776         if (!dbus_message_get_args(reply, &error,
3777                                    DBUS_TYPE_STRING, &text,
3778                                    DBUS_TYPE_INVALID)) {
3779                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3780                 dbus_error_free(&error);
3781                 return  -EIO;
3782         }
3783
3784         fputs(text, stdout);
3785         return 0;
3786 }
3787
3788 static int snapshot(DBusConnection *bus, char **args) {
3789         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3790         DBusError error;
3791         int r;
3792         dbus_bool_t cleanup = FALSE;
3793         DBusMessageIter iter, sub;
3794         const char
3795                 *path, *id,
3796                 *interface = "org.freedesktop.systemd1.Unit",
3797                 *property = "Id";
3798         _cleanup_free_ char *n = NULL;
3799
3800         dbus_error_init(&error);
3801
3802         if (strv_length(args) > 1)
3803                 n = unit_name_mangle_with_suffix(args[1], ".snapshot");
3804         else
3805                 n = strdup("");
3806         if (!n)
3807                 return log_oom();
3808
3809         r = bus_method_call_with_reply(
3810                         bus,
3811                         "org.freedesktop.systemd1",
3812                         "/org/freedesktop/systemd1",
3813                         "org.freedesktop.systemd1.Manager",
3814                         "CreateSnapshot",
3815                         &reply,
3816                         NULL,
3817                         DBUS_TYPE_STRING, &n,
3818                         DBUS_TYPE_BOOLEAN, &cleanup,
3819                         DBUS_TYPE_INVALID);
3820         if (r < 0)
3821                 return r;
3822
3823         if (!dbus_message_get_args(reply, &error,
3824                                    DBUS_TYPE_OBJECT_PATH, &path,
3825                                    DBUS_TYPE_INVALID)) {
3826                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3827                 dbus_error_free(&error);
3828                 return -EIO;
3829         }
3830
3831         dbus_message_unref(reply);
3832         reply = NULL;
3833
3834         r = bus_method_call_with_reply (
3835                         bus,
3836                         "org.freedesktop.systemd1",
3837                         path,
3838                         "org.freedesktop.DBus.Properties",
3839                         "Get",
3840                         &reply,
3841                         NULL,
3842                         DBUS_TYPE_STRING, &interface,
3843                         DBUS_TYPE_STRING, &property,
3844                         DBUS_TYPE_INVALID);
3845         if (r < 0)
3846                 return r;
3847
3848         if (!dbus_message_iter_init(reply, &iter) ||
3849             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3850                 log_error("Failed to parse reply.");
3851                 return -EIO;
3852         }
3853
3854         dbus_message_iter_recurse(&iter, &sub);
3855
3856         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3857                 log_error("Failed to parse reply.");
3858                 return -EIO;
3859         }
3860
3861         dbus_message_iter_get_basic(&sub, &id);
3862
3863         if (!arg_quiet)
3864                 puts(id);
3865
3866         return 0;
3867 }
3868
3869 static int delete_snapshot(DBusConnection *bus, char **args) {
3870         char **name;
3871
3872         assert(args);
3873
3874         STRV_FOREACH(name, args+1) {
3875                 _cleanup_free_ char *n = NULL;
3876                 int r;
3877
3878                 n = unit_name_mangle_with_suffix(*name, ".snapshot");
3879                 if (!n)
3880                         return log_oom();
3881
3882                 r = bus_method_call_with_reply(
3883                                 bus,
3884                                 "org.freedesktop.systemd1",
3885                                 "/org/freedesktop/systemd1",
3886                                 "org.freedesktop.systemd1.Manager",
3887                                 "RemoveSnapshot",
3888                                 NULL,
3889                                 NULL,
3890                                 DBUS_TYPE_STRING, &n,
3891                                 DBUS_TYPE_INVALID);
3892                 if (r < 0)
3893                         return r;
3894         }
3895
3896         return 0;
3897 }
3898
3899 static int daemon_reload(DBusConnection *bus, char **args) {
3900         int r;
3901         const char *method;
3902         DBusError error;
3903
3904         if (arg_action == ACTION_RELOAD)
3905                 method = "Reload";
3906         else if (arg_action == ACTION_REEXEC)
3907                 method = "Reexecute";
3908         else {
3909                 assert(arg_action == ACTION_SYSTEMCTL);
3910
3911                 method =
3912                         streq(args[0], "clear-jobs")    ||
3913                         streq(args[0], "cancel")        ? "ClearJobs" :
3914                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3915                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3916                         streq(args[0], "halt")          ? "Halt" :
3917                         streq(args[0], "poweroff")      ? "PowerOff" :
3918                         streq(args[0], "reboot")        ? "Reboot" :
3919                         streq(args[0], "kexec")         ? "KExec" :
3920                         streq(args[0], "exit")          ? "Exit" :
3921                                     /* "daemon-reload" */ "Reload";
3922         }
3923
3924         r = bus_method_call_with_reply(
3925                         bus,
3926                         "org.freedesktop.systemd1",
3927                         "/org/freedesktop/systemd1",
3928                         "org.freedesktop.systemd1.Manager",
3929                         method,
3930                         NULL,
3931                         &error,
3932                         DBUS_TYPE_INVALID);
3933
3934         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3935                 /* There's always a fallback possible for
3936                  * legacy actions. */
3937                 r = -EADDRNOTAVAIL;
3938         else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3939                 /* On reexecution, we expect a disconnect, not
3940                  * a reply */
3941                 r = 0;
3942         else if (r < 0)
3943                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3944
3945         dbus_error_free(&error);
3946         return r;
3947 }
3948
3949 static int reset_failed(DBusConnection *bus, char **args) {
3950         int r = 0;
3951         char **name;
3952
3953         if (strv_length(args) <= 1)
3954                 return daemon_reload(bus, args);
3955
3956         STRV_FOREACH(name, args+1) {
3957                 _cleanup_free_ char *n;
3958
3959                 n = unit_name_mangle(*name);
3960                 if (!n)
3961                         return log_oom();
3962
3963                 r = bus_method_call_with_reply(
3964                                 bus,
3965                                 "org.freedesktop.systemd1",
3966                                 "/org/freedesktop/systemd1",
3967                                 "org.freedesktop.systemd1.Manager",
3968                                 "ResetFailedUnit",
3969                                 NULL,
3970                                 NULL,
3971                                 DBUS_TYPE_STRING, &n,
3972                                 DBUS_TYPE_INVALID);
3973                 if (r < 0)
3974                         return r;
3975         }
3976
3977         return 0;
3978 }
3979
3980 static int show_enviroment(DBusConnection *bus, char **args) {
3981         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3982         DBusMessageIter iter, sub, sub2;
3983         int r;
3984         const char
3985                 *interface = "org.freedesktop.systemd1.Manager",
3986                 *property = "Environment";
3987
3988         pager_open_if_enabled();
3989
3990         r = bus_method_call_with_reply(
3991                         bus,
3992                         "org.freedesktop.systemd1",
3993                         "/org/freedesktop/systemd1",
3994                         "org.freedesktop.DBus.Properties",
3995                         "Get",
3996                         &reply,
3997                         NULL,
3998                         DBUS_TYPE_STRING, &interface,
3999                         DBUS_TYPE_STRING, &property,
4000                         DBUS_TYPE_INVALID);
4001         if (r < 0)
4002                 return r;
4003
4004         if (!dbus_message_iter_init(reply, &iter) ||
4005             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
4006                 log_error("Failed to parse reply.");
4007                 return -EIO;
4008         }
4009
4010         dbus_message_iter_recurse(&iter, &sub);
4011
4012         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
4013             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
4014                 log_error("Failed to parse reply.");
4015                 return -EIO;
4016         }
4017
4018         dbus_message_iter_recurse(&sub, &sub2);
4019
4020         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
4021                 const char *text;
4022
4023                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
4024                         log_error("Failed to parse reply.");
4025                         return -EIO;
4026                 }
4027
4028                 dbus_message_iter_get_basic(&sub2, &text);
4029                 puts(text);
4030
4031                 dbus_message_iter_next(&sub2);
4032         }
4033
4034         return 0;
4035 }
4036
4037 static int switch_root(DBusConnection *bus, char **args) {
4038         unsigned l;
4039         const char *root;
4040         _cleanup_free_ char *init = NULL;
4041
4042         l = strv_length(args);
4043         if (l < 2 || l > 3) {
4044                 log_error("Wrong number of arguments.");
4045                 return -EINVAL;
4046         }
4047
4048         root = args[1];
4049
4050         if (l >= 3)
4051                 init = strdup(args[2]);
4052         else {
4053                 parse_env_file("/proc/cmdline", WHITESPACE,
4054                                "init", &init,
4055                                NULL);
4056
4057                 if (!init)
4058                         init = strdup("");
4059         }
4060         if (!init)
4061                 return log_oom();
4062
4063         log_debug("switching root - root: %s; init: %s", root, init);
4064
4065         return bus_method_call_with_reply(
4066                         bus,
4067                         "org.freedesktop.systemd1",
4068                         "/org/freedesktop/systemd1",
4069                         "org.freedesktop.systemd1.Manager",
4070                         "SwitchRoot",
4071                         NULL,
4072                         NULL,
4073                         DBUS_TYPE_STRING, &root,
4074                         DBUS_TYPE_STRING, &init,
4075                         DBUS_TYPE_INVALID);
4076 }
4077
4078 static int set_environment(DBusConnection *bus, char **args) {
4079         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4080         DBusError error;
4081         const char *method;
4082         DBusMessageIter iter;
4083         int r;
4084
4085         assert(bus);
4086         assert(args);
4087
4088         dbus_error_init(&error);
4089
4090         method = streq(args[0], "set-environment")
4091                 ? "SetEnvironment"
4092                 : "UnsetEnvironment";
4093
4094         m = dbus_message_new_method_call(
4095                         "org.freedesktop.systemd1",
4096                         "/org/freedesktop/systemd1",
4097                         "org.freedesktop.systemd1.Manager",
4098                         method);
4099         if (!m)
4100                 return log_oom();
4101
4102         dbus_message_iter_init_append(m, &iter);
4103
4104         r = bus_append_strv_iter(&iter, args + 1);
4105         if (r < 0)
4106                 return log_oom();
4107
4108         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4109         if (!reply) {
4110                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4111                 dbus_error_free(&error);
4112                 return -EIO;
4113         }
4114
4115         return 0;
4116 }
4117
4118 static int enable_sysv_units(char **args) {
4119         int r = 0;
4120
4121 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
4122         const char *verb = args[0];
4123         unsigned f = 1, t = 1;
4124         LookupPaths paths = {};
4125
4126         if (arg_scope != UNIT_FILE_SYSTEM)
4127                 return 0;
4128
4129         if (!streq(verb, "enable") &&
4130             !streq(verb, "disable") &&
4131             !streq(verb, "is-enabled"))
4132                 return 0;
4133
4134         /* Processes all SysV units, and reshuffles the array so that
4135          * afterwards only the native units remain */
4136
4137         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
4138         if (r < 0)
4139                 return r;
4140
4141         r = 0;
4142         for (f = 1; args[f]; f++) {
4143                 const char *name;
4144                 _cleanup_free_ char *p = NULL, *q = NULL;
4145                 bool found_native = false, found_sysv;
4146                 unsigned c = 1;
4147                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4148                 char **k, *l;
4149                 int j;
4150                 pid_t pid;
4151                 siginfo_t status;
4152
4153                 name = args[f];
4154
4155                 if (!endswith(name, ".service"))
4156                         continue;
4157
4158                 if (path_is_absolute(name))
4159                         continue;
4160
4161                 STRV_FOREACH(k, paths.unit_path) {
4162                         if (!isempty(arg_root))
4163                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4164                         else
4165                                 asprintf(&p, "%s/%s", *k, name);
4166
4167                         if (!p) {
4168                                 r = log_oom();
4169                                 goto finish;
4170                         }
4171
4172                         found_native = access(p, F_OK) >= 0;
4173                         free(p);
4174                         p = NULL;
4175
4176                         if (found_native)
4177                                 break;
4178                 }
4179
4180                 if (found_native)
4181                         continue;
4182
4183                 if (!isempty(arg_root))
4184                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4185                 else
4186                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4187                 if (!p) {
4188                         r = log_oom();
4189                         goto finish;
4190                 }
4191
4192                 p[strlen(p) - sizeof(".service") + 1] = 0;
4193                 found_sysv = access(p, F_OK) >= 0;
4194
4195                 if (!found_sysv)
4196                         continue;
4197
4198                 /* Mark this entry, so that we don't try enabling it as native unit */
4199                 args[f] = (char*) "";
4200
4201                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
4202
4203                 if (!isempty(arg_root))
4204                         argv[c++] = q = strappend("--root=", arg_root);
4205
4206                 argv[c++] = path_get_file_name(p);
4207                 argv[c++] =
4208                         streq(verb, "enable") ? "on" :
4209                         streq(verb, "disable") ? "off" : "--level=5";
4210                 argv[c] = NULL;
4211
4212                 l = strv_join((char**)argv, " ");
4213                 if (!l) {
4214                         r = log_oom();
4215                         goto finish;
4216                 }
4217
4218                 log_info("Executing %s", l);
4219                 free(l);
4220
4221                 pid = fork();
4222                 if (pid < 0) {
4223                         log_error("Failed to fork: %m");
4224                         r = -errno;
4225                         goto finish;
4226                 } else if (pid == 0) {
4227                         /* Child */
4228
4229                         execv(argv[0], (char**) argv);
4230                         _exit(EXIT_FAILURE);
4231                 }
4232
4233                 j = wait_for_terminate(pid, &status);
4234                 if (j < 0) {
4235                         log_error("Failed to wait for child: %s", strerror(-r));
4236                         r = j;
4237                         goto finish;
4238                 }
4239
4240                 if (status.si_code == CLD_EXITED) {
4241                         if (streq(verb, "is-enabled")) {
4242                                 if (status.si_status == 0) {
4243                                         if (!arg_quiet)
4244                                                 puts("enabled");
4245                                         r = 1;
4246                                 } else {
4247                                         if (!arg_quiet)
4248                                                 puts("disabled");
4249                                 }
4250
4251                         } else if (status.si_status != 0) {
4252                                 r = -EINVAL;
4253                                 goto finish;
4254                         }
4255                 } else {
4256                         r = -EPROTO;
4257                         goto finish;
4258                 }
4259         }
4260
4261 finish:
4262         lookup_paths_free(&paths);
4263
4264         /* Drop all SysV units */
4265         for (f = 1, t = 1; args[f]; f++) {
4266
4267                 if (isempty(args[f]))
4268                         continue;
4269
4270                 args[t++] = args[f];
4271         }
4272
4273         args[t] = NULL;
4274
4275 #endif
4276         return r;
4277 }
4278
4279 static int mangle_names(char **original_names, char ***mangled_names) {
4280         char **i, **l, **name;
4281
4282         l = new(char*, strv_length(original_names) + 1);
4283         if (!l)
4284                 return log_oom();
4285
4286         i = l;
4287         STRV_FOREACH(name, original_names) {
4288
4289                 /* When enabling units qualified path names are OK,
4290                  * too, hence allow them explicitly. */
4291
4292                 if (is_path(*name))
4293                         *i = strdup(*name);
4294                 else
4295                         *i = unit_name_mangle(*name);
4296
4297                 if (!*i) {
4298                         strv_free(l);
4299                         return log_oom();
4300                 }
4301
4302                 i++;
4303         }
4304
4305         *i = NULL;
4306         *mangled_names = l;
4307
4308         return 0;
4309 }
4310
4311 static int enable_unit(DBusConnection *bus, char **args) {
4312         const char *verb = args[0];
4313         UnitFileChange *changes = NULL;
4314         unsigned n_changes = 0, i;
4315         int carries_install_info = -1;
4316         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4317         int r;
4318         _cleanup_dbus_error_free_ DBusError error;
4319         _cleanup_strv_free_ char **mangled_names = NULL;
4320
4321         dbus_error_init(&error);
4322
4323         r = enable_sysv_units(args);
4324         if (r < 0)
4325                 return r;
4326
4327         if (!args[1])
4328                 return 0;
4329
4330         r = mangle_names(args+1, &mangled_names);
4331         if (r < 0)
4332                 goto finish;
4333
4334         if (!bus || avoid_bus()) {
4335                 if (streq(verb, "enable")) {
4336                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4337                         carries_install_info = r;
4338                 } else if (streq(verb, "disable"))
4339                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
4340                 else if (streq(verb, "reenable")) {
4341                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4342                         carries_install_info = r;
4343                 } else if (streq(verb, "link"))
4344                         r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4345                 else if (streq(verb, "preset")) {
4346                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4347                         carries_install_info = r;
4348                 } else if (streq(verb, "mask"))
4349                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4350                 else if (streq(verb, "unmask"))
4351                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
4352                 else if (streq(verb, "set-default"))
4353                         r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
4354                 else
4355                         assert_not_reached("Unknown verb");
4356
4357                 if (r < 0) {
4358                         log_error("Operation failed: %s", strerror(-r));
4359                         goto finish;
4360                 }
4361
4362                 if (!arg_quiet) {
4363                         for (i = 0; i < n_changes; i++) {
4364                                 if (changes[i].type == UNIT_FILE_SYMLINK)
4365                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4366                                 else
4367                                         log_info("rm '%s'", changes[i].path);
4368                         }
4369                 }
4370
4371                 r = 0;
4372         } else {
4373                 const char *method;
4374                 bool send_force = true, expect_carries_install_info = false;
4375                 dbus_bool_t a, b;
4376                 DBusMessageIter iter, sub, sub2;
4377
4378                 if (streq(verb, "enable")) {
4379                         method = "EnableUnitFiles";
4380                         expect_carries_install_info = true;
4381                 } else if (streq(verb, "disable")) {
4382                         method = "DisableUnitFiles";
4383                         send_force = false;
4384                 } else if (streq(verb, "reenable")) {
4385                         method = "ReenableUnitFiles";
4386                         expect_carries_install_info = true;
4387                 } else if (streq(verb, "link"))
4388                         method = "LinkUnitFiles";
4389                 else if (streq(verb, "preset")) {
4390                         method = "PresetUnitFiles";
4391                         expect_carries_install_info = true;
4392                 } else if (streq(verb, "mask"))
4393                         method = "MaskUnitFiles";
4394                 else if (streq(verb, "unmask")) {
4395                         method = "UnmaskUnitFiles";
4396                         send_force = false;
4397                 } else if (streq(verb, "set-default")) {
4398                         method = "SetDefaultTarget";
4399                 } else
4400                         assert_not_reached("Unknown verb");
4401
4402                 m = dbus_message_new_method_call(
4403                                 "org.freedesktop.systemd1",
4404                                 "/org/freedesktop/systemd1",
4405                                 "org.freedesktop.systemd1.Manager",
4406                                 method);
4407                 if (!m) {
4408                         r = log_oom();
4409                         goto finish;
4410                 }
4411
4412                 dbus_message_iter_init_append(m, &iter);
4413
4414                 r = bus_append_strv_iter(&iter, mangled_names);
4415                 if (r < 0) {
4416                         log_error("Failed to append unit files.");
4417                         goto finish;
4418                 }
4419
4420                 a = arg_runtime;
4421                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4422                         log_error("Failed to append runtime boolean.");
4423                         r = -ENOMEM;
4424                         goto finish;
4425                 }
4426
4427                 if (send_force) {
4428                         b = arg_force;
4429
4430                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4431                                 log_error("Failed to append force boolean.");
4432                                 r = -ENOMEM;
4433                                 goto finish;
4434                         }
4435                 }
4436
4437                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4438                 if (!reply) {
4439                         log_error("Failed to issue method call: %s", bus_error_message(&error));
4440                         r = -EIO;
4441                         goto finish;
4442                 }
4443
4444                 if (!dbus_message_iter_init(reply, &iter)) {
4445                         log_error("Failed to initialize iterator.");
4446                         goto finish;
4447                 }
4448
4449                 if (expect_carries_install_info) {
4450                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4451                         if (r < 0) {
4452                                 log_error("Failed to parse reply.");
4453                                 goto finish;
4454                         }
4455
4456                         carries_install_info = b;
4457                 }
4458
4459                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4460                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4461                         log_error("Failed to parse reply.");
4462                         r = -EIO;
4463                         goto finish;
4464                 }
4465
4466                 dbus_message_iter_recurse(&iter, &sub);
4467                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4468                         const char *type, *path, *source;
4469
4470                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4471                                 log_error("Failed to parse reply.");
4472                                 r = -EIO;
4473                                 goto finish;
4474                         }
4475
4476                         dbus_message_iter_recurse(&sub, &sub2);
4477
4478                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4479                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4480                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4481                                 log_error("Failed to parse reply.");
4482                                 r = -EIO;
4483                                 goto finish;
4484                         }
4485
4486                         if (!arg_quiet) {
4487                                 if (streq(type, "symlink"))
4488                                         log_info("ln -s '%s' '%s'", source, path);
4489                                 else
4490                                         log_info("rm '%s'", path);
4491                         }
4492
4493                         dbus_message_iter_next(&sub);
4494                 }
4495
4496                 /* Try to reload if enabeld */
4497                 if (!arg_no_reload)
4498                         r = daemon_reload(bus, args);
4499         }
4500
4501         if (carries_install_info == 0)
4502                 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4503                             "using systemctl.\n"
4504                             "Possible reasons for having this kind of units are:\n"
4505                             "1) A unit may be statically enabled by being symlinked from another unit's\n"
4506                             "   .wants/ or .requires/ directory.\n"
4507                             "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4508                             "   a requirement dependency on it.\n"
4509                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
4510                             "   D-Bus, udev, scripted systemctl call, ...).\n");
4511
4512 finish:
4513         unit_file_changes_free(changes, n_changes);
4514
4515         return r;
4516 }
4517
4518 static int set_log_level(DBusConnection *bus, char **args) {
4519         _cleanup_dbus_error_free_ DBusError error;
4520         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4521         DBusMessageIter iter, sub;
4522         const char* property = "LogLevel";
4523         const char* interface = "org.freedesktop.systemd1.Manager";
4524         const char* value;
4525
4526         assert(bus);
4527         assert(args);
4528
4529         value = args[1];
4530         dbus_error_init(&error);
4531
4532         m = dbus_message_new_method_call("org.freedesktop.systemd1",
4533                                          "/org/freedesktop/systemd1",
4534                                          "org.freedesktop.DBus.Properties",
4535                                          "Set");
4536         if (!m)
4537                 return log_oom();
4538
4539         dbus_message_iter_init_append(m, &iter);
4540
4541         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
4542             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property) ||
4543             !dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub))
4544                 return log_oom();
4545
4546         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &value)) {
4547                 dbus_message_iter_abandon_container(&iter, &sub);
4548                 return log_oom();
4549         }
4550
4551         if (!dbus_message_iter_close_container(&iter, &sub))
4552                 return log_oom();
4553
4554         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4555         if (!reply) {
4556                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4557                 return -EIO;
4558         }
4559
4560         return 0;
4561 }
4562
4563 static int unit_is_enabled(DBusConnection *bus, char **args) {
4564         _cleanup_dbus_error_free_ DBusError error;
4565         int r;
4566         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
4567         bool enabled;
4568         char **name;
4569         char *n;
4570
4571         dbus_error_init(&error);
4572
4573         r = enable_sysv_units(args);
4574         if (r < 0)
4575                 return r;
4576
4577         enabled = r > 0;
4578
4579         if (!bus || avoid_bus()) {
4580
4581                 STRV_FOREACH(name, args+1) {
4582                         UnitFileState state;
4583
4584                         n = unit_name_mangle(*name);
4585                         if (!n)
4586                                 return log_oom();
4587
4588                         state = unit_file_get_state(arg_scope, arg_root, n);
4589
4590                         free(n);
4591
4592                         if (state < 0)
4593                                 return state;
4594
4595                         if (state == UNIT_FILE_ENABLED ||
4596                             state == UNIT_FILE_ENABLED_RUNTIME ||
4597                             state == UNIT_FILE_STATIC)
4598                                 enabled = true;
4599
4600                         if (!arg_quiet)
4601                                 puts(unit_file_state_to_string(state));
4602                 }
4603
4604         } else {
4605                 STRV_FOREACH(name, args+1) {
4606                         const char *s;
4607
4608                         n = unit_name_mangle(*name);
4609                         if (!n)
4610                                 return log_oom();
4611
4612                         r = bus_method_call_with_reply (
4613                                         bus,
4614                                         "org.freedesktop.systemd1",
4615                                         "/org/freedesktop/systemd1",
4616                                         "org.freedesktop.systemd1.Manager",
4617                                         "GetUnitFileState",
4618                                         &reply,
4619                                         NULL,
4620                                         DBUS_TYPE_STRING, &n,
4621                                         DBUS_TYPE_INVALID);
4622
4623                         free(n);
4624
4625                         if (r)
4626                                 return r;
4627
4628                         if (!dbus_message_get_args(reply, &error,
4629                                                    DBUS_TYPE_STRING, &s,
4630                                                    DBUS_TYPE_INVALID)) {
4631                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4632                                 return -EIO;
4633                         }
4634
4635                         dbus_message_unref(reply);
4636                         reply = NULL;
4637
4638                         if (streq(s, "enabled") ||
4639                             streq(s, "enabled-runtime") ||
4640                             streq(s, "static"))
4641                                 enabled = true;
4642
4643                         if (!arg_quiet)
4644                                 puts(s);
4645                 }
4646         }
4647
4648         return enabled ? 0 : 1;
4649 }
4650
4651 static int systemctl_help(void) {
4652
4653         pager_open_if_enabled();
4654
4655         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4656                "Query or send control commands to the systemd manager.\n\n"
4657                "  -h --help           Show this help\n"
4658                "     --version        Show package version\n"
4659                "  -t --type=TYPE      List only units of a particular type\n"
4660                "  -p --property=NAME  Show only properties by this name\n"
4661                "  -a --all            Show all loaded units/properties, including dead/empty\n"
4662                "                      ones. To list all units installed on the system, use\n"
4663                "                      the 'list-unit-files' command instead.\n"
4664                "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
4665                "     --failed         Show only failed units\n"
4666                "  -l --full           Don't ellipsize unit names on output\n"
4667                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4668                "                      pending\n"
4669                "     --irreversible   Create jobs which cannot be implicitly cancelled\n"
4670                "     --show-types     When showing sockets, explicitly show their type\n"
4671                "     --ignore-dependencies\n"
4672                "                      When queueing a new job, ignore all its dependencies\n"
4673                "  -i --ignore-inhibitors\n"
4674                "                      When shutting down or sleeping, ignore inhibitors\n"
4675                "     --kill-who=WHO   Who to send signal to\n"
4676                "  -s --signal=SIGNAL  Which signal to send\n"
4677                "  -H --host=[USER@]HOST\n"
4678                "                      Show information for remote host\n"
4679                "  -P --privileged     Acquire privileges before execution\n"
4680                "  -q --quiet          Suppress output\n"
4681                "     --no-block       Do not wait until operation finished\n"
4682                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4683                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4684                "                      configuration\n"
4685                "     --no-legend      Do not print a legend (column headers and hints)\n"
4686                "     --no-pager       Do not pipe output into a pager\n"
4687                "     --no-ask-password\n"
4688                "                      Do not ask for system passwords\n"
4689                "     --system         Connect to system manager\n"
4690                "     --user           Connect to user service manager\n"
4691                "     --global         Enable/disable unit files globally\n"
4692                "  -f --force          When enabling unit files, override existing symlinks\n"
4693                "                      When shutting down, execute action immediately\n"
4694                "     --root=PATH      Enable unit files in the specified root directory\n"
4695                "     --runtime        Enable unit files only temporarily until next reboot\n"
4696                "  -n --lines=INTEGER  Journal entries to show\n"
4697                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4698                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
4699                "Unit Commands:\n"
4700                "  list-units                      List loaded units\n"
4701                "  list-sockets                    List loaded sockets ordered by address\n"
4702                "  start [NAME...]                 Start (activate) one or more units\n"
4703                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4704                "  reload [NAME...]                Reload one or more units\n"
4705                "  restart [NAME...]               Start or restart one or more units\n"
4706                "  try-restart [NAME...]           Restart one or more units if active\n"
4707                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
4708                "                                  otherwise start or restart\n"
4709                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
4710                "                                  otherwise restart if active\n"
4711                "  isolate [NAME]                  Start one unit and stop all others\n"
4712                "  kill [NAME...]                  Send signal to processes of a unit\n"
4713                "  is-active [NAME...]             Check whether units are active\n"
4714                "  is-failed [NAME...]             Check whether units are failed\n"
4715                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4716                "  show [NAME...|JOB...]           Show properties of one or more\n"
4717                "                                  units/jobs or the manager\n"
4718                "  set-property [NAME] [ASSIGNMENT...]\n"
4719                "                                  Sets one or more properties of a unit\n"
4720                "  help [NAME...|PID...]           Show manual for one or more units\n"
4721                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4722                "                                  units\n"
4723                "  load [NAME...]                  Load one or more units\n"
4724                "  list-dependencies [NAME]        Recursively show units which are required\n"
4725                "                                  or wanted by this unit or by which this\n"
4726                "                                  unit is required or wanted\n\n"
4727                "Unit File Commands:\n"
4728                "  list-unit-files                 List installed unit files\n"
4729                "  enable [NAME...]                Enable one or more unit files\n"
4730                "  disable [NAME...]               Disable one or more unit files\n"
4731                "  reenable [NAME...]              Reenable one or more unit files\n"
4732                "  preset [NAME...]                Enable/disable one or more unit files\n"
4733                "                                  based on preset configuration\n"
4734                "  mask [NAME...]                  Mask one or more units\n"
4735                "  unmask [NAME...]                Unmask one or more units\n"
4736                "  link [PATH...]                  Link one or more units files into\n"
4737                "                                  the search path\n"
4738                "  get-default                     Get the name of the default target\n"
4739                "  set-default NAME                Set the default target\n"
4740                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4741                "Job Commands:\n"
4742                "  list-jobs                       List jobs\n"
4743                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4744                "Status Commands:\n"
4745                "  dump                            Dump server status\n"
4746                "Snapshot Commands:\n"
4747                "  snapshot [NAME]                 Create a snapshot\n"
4748                "  delete [NAME...]                Remove one or more snapshots\n\n"
4749                "Environment Commands:\n"
4750                "  show-environment                Dump environment\n"
4751                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4752                "  unset-environment [NAME...]     Unset one or more environment variables\n"
4753                "  set-log-level LEVEL             Set logging threshold for systemd\n\n"
4754                "Manager Lifecycle Commands:\n"
4755                "  daemon-reload                   Reload systemd manager configuration\n"
4756                "  daemon-reexec                   Reexecute systemd manager\n\n"
4757                "System Commands:\n"
4758                "  default                         Enter system default mode\n"
4759                "  rescue                          Enter system rescue mode\n"
4760                "  emergency                       Enter system emergency mode\n"
4761                "  halt                            Shut down and halt the system\n"
4762                "  poweroff                        Shut down and power-off the system\n"
4763                "  reboot                          Shut down and reboot the system\n"
4764                "  kexec                           Shut down and reboot the system with kexec\n"
4765                "  exit                            Request user instance exit\n"
4766                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4767                "  suspend                         Suspend the system\n"
4768                "  hibernate                       Hibernate the system\n"
4769                "  hybrid-sleep                    Hibernate and suspend the system\n",
4770                program_invocation_short_name);
4771
4772         return 0;
4773 }
4774
4775 static int halt_help(void) {
4776
4777         printf("%s [OPTIONS...]\n\n"
4778                "%s the system.\n\n"
4779                "     --help      Show this help\n"
4780                "     --halt      Halt the machine\n"
4781                "  -p --poweroff  Switch off the machine\n"
4782                "     --reboot    Reboot the machine\n"
4783                "  -f --force     Force immediate halt/power-off/reboot\n"
4784                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4785                "  -d --no-wtmp   Don't write wtmp record\n"
4786                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4787                program_invocation_short_name,
4788                arg_action == ACTION_REBOOT   ? "Reboot" :
4789                arg_action == ACTION_POWEROFF ? "Power off" :
4790                                                "Halt");
4791
4792         return 0;
4793 }
4794
4795 static int shutdown_help(void) {
4796
4797         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4798                "Shut down the system.\n\n"
4799                "     --help      Show this help\n"
4800                "  -H --halt      Halt the machine\n"
4801                "  -P --poweroff  Power-off the machine\n"
4802                "  -r --reboot    Reboot the machine\n"
4803                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4804                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4805                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4806                "  -c             Cancel a pending shutdown\n",
4807                program_invocation_short_name);
4808
4809         return 0;
4810 }
4811
4812 static int telinit_help(void) {
4813
4814         printf("%s [OPTIONS...] {COMMAND}\n\n"
4815                "Send control commands to the init daemon.\n\n"
4816                "     --help      Show this help\n"
4817                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4818                "Commands:\n"
4819                "  0              Power-off the machine\n"
4820                "  6              Reboot the machine\n"
4821                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4822                "  1, s, S        Enter rescue mode\n"
4823                "  q, Q           Reload init daemon configuration\n"
4824                "  u, U           Reexecute init daemon\n",
4825                program_invocation_short_name);
4826
4827         return 0;
4828 }
4829
4830 static int runlevel_help(void) {
4831
4832         printf("%s [OPTIONS...]\n\n"
4833                "Prints the previous and current runlevel of the init system.\n\n"
4834                "     --help      Show this help\n",
4835                program_invocation_short_name);
4836
4837         return 0;
4838 }
4839
4840 static int help_types(void) {
4841         int i;
4842         const char *t;
4843
4844         puts("Available unit types:");
4845         for(i = 0; i < _UNIT_TYPE_MAX; i++) {
4846                 t = unit_type_to_string(i);
4847                 if (t)
4848                         puts(t);
4849         }
4850
4851         puts("\nAvailable unit load states: ");
4852         for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) {
4853                 t = unit_load_state_to_string(i);
4854                 if (t)
4855                         puts(t);
4856         }
4857
4858         return 0;
4859 }
4860
4861 static int systemctl_parse_argv(int argc, char *argv[]) {
4862
4863         enum {
4864                 ARG_FAIL = 0x100,
4865                 ARG_REVERSE,
4866                 ARG_AFTER,
4867                 ARG_BEFORE,
4868                 ARG_SHOW_TYPES,
4869                 ARG_IRREVERSIBLE,
4870                 ARG_IGNORE_DEPENDENCIES,
4871                 ARG_VERSION,
4872                 ARG_USER,
4873                 ARG_SYSTEM,
4874                 ARG_GLOBAL,
4875                 ARG_NO_BLOCK,
4876                 ARG_NO_LEGEND,
4877                 ARG_NO_PAGER,
4878                 ARG_NO_WALL,
4879                 ARG_ROOT,
4880                 ARG_NO_RELOAD,
4881                 ARG_KILL_WHO,
4882                 ARG_NO_ASK_PASSWORD,
4883                 ARG_FAILED,
4884                 ARG_RUNTIME,
4885                 ARG_FORCE,
4886                 ARG_PLAIN
4887         };
4888
4889         static const struct option options[] = {
4890                 { "help",      no_argument,       NULL, 'h'           },
4891                 { "version",   no_argument,       NULL, ARG_VERSION   },
4892                 { "type",      required_argument, NULL, 't'           },
4893                 { "property",  required_argument, NULL, 'p'           },
4894                 { "all",       no_argument,       NULL, 'a'           },
4895                 { "reverse",   no_argument,       NULL, ARG_REVERSE   },
4896                 { "after",     no_argument,       NULL, ARG_AFTER     },
4897                 { "before",    no_argument,       NULL, ARG_BEFORE    },
4898                 { "show-types", no_argument,      NULL, ARG_SHOW_TYPES },
4899                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4900                 { "full",      no_argument,       NULL, 'l'           },
4901                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4902                 { "irreversible", no_argument,    NULL, ARG_IRREVERSIBLE },
4903                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4904                 { "ignore-inhibitors", no_argument, NULL, 'i'         },
4905                 { "user",      no_argument,       NULL, ARG_USER      },
4906                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4907                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4908                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4909                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4910                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4911                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4912                 { "quiet",     no_argument,       NULL, 'q'           },
4913                 { "root",      required_argument, NULL, ARG_ROOT      },
4914                 { "force",     no_argument,       NULL, ARG_FORCE     },
4915                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4916                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4917                 { "signal",    required_argument, NULL, 's'           },
4918                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4919                 { "host",      required_argument, NULL, 'H'           },
4920                 { "privileged",no_argument,       NULL, 'P'           },
4921                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4922                 { "lines",     required_argument, NULL, 'n'           },
4923                 { "output",    required_argument, NULL, 'o'           },
4924                 { "plain",     no_argument,       NULL, ARG_PLAIN     },
4925                 { NULL,        0,                 NULL, 0             }
4926         };
4927
4928         int c;
4929
4930         assert(argc >= 0);
4931         assert(argv);
4932
4933         while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:Pn:o:i", options, NULL)) >= 0) {
4934
4935                 switch (c) {
4936
4937                 case 'h':
4938                         systemctl_help();
4939                         return 0;
4940
4941                 case ARG_VERSION:
4942                         puts(PACKAGE_STRING);
4943                         puts(SYSTEMD_FEATURES);
4944                         return 0;
4945
4946                 case 't': {
4947                         char *word, *state;
4948                         size_t size;
4949
4950                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
4951                                 _cleanup_free_ char *type;
4952
4953                                 type = strndup(word, size);
4954                                 if (!type)
4955                                         return -ENOMEM;
4956
4957                                 if (streq(type, "help")) {
4958                                         help_types();
4959                                         return 0;
4960                                 }
4961
4962                                 if (unit_type_from_string(type) >= 0) {
4963                                         if (strv_push(&arg_types, type))
4964                                                 return log_oom();
4965                                         type = NULL;
4966                                         continue;
4967                                 }
4968
4969                                 if (unit_load_state_from_string(optarg) >= 0) {
4970                                         if (strv_push(&arg_load_states, type))
4971                                                 return log_oom();
4972                                         type = NULL;
4973                                         continue;
4974                                 }
4975
4976                                 log_error("Unknown unit type or load state '%s'.", type);
4977                                 log_info("Use -t help to see a list of allowed values.");
4978                                 return -EINVAL;
4979                         }
4980
4981                         break;
4982                 }
4983
4984                 case 'p': {
4985                         /* Make sure that if the empty property list
4986                            was specified, we won't show any properties. */
4987                         if (isempty(optarg) && !arg_properties) {
4988                                 arg_properties = strv_new(NULL, NULL);
4989                                 if (!arg_properties)
4990                                         return log_oom();
4991                         } else {
4992                                 char *word, *state;
4993                                 size_t size;
4994
4995                                 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
4996                                         char *prop;
4997
4998                                         prop = strndup(word, size);
4999                                         if (!prop)
5000                                                 return log_oom();
5001
5002                                         if (strv_push(&arg_properties, prop)) {
5003                                                 free(prop);
5004                                                 return log_oom();
5005                                         }
5006                                 }
5007                         }
5008
5009                         /* If the user asked for a particular
5010                          * property, show it to him, even if it is
5011                          * empty. */
5012                         arg_all = true;
5013
5014                         break;
5015                 }
5016
5017                 case 'a':
5018                         arg_all = true;
5019                         break;
5020
5021                 case ARG_REVERSE:
5022                         arg_dependency = DEPENDENCY_REVERSE;
5023                         break;
5024
5025                 case ARG_AFTER:
5026                         arg_dependency = DEPENDENCY_AFTER;
5027                         break;
5028
5029                 case ARG_BEFORE:
5030                         arg_dependency = DEPENDENCY_BEFORE;
5031                         break;
5032
5033                 case ARG_SHOW_TYPES:
5034                         arg_show_types = true;
5035                         break;
5036
5037                 case ARG_FAIL:
5038                         arg_job_mode = "fail";
5039                         break;
5040
5041                 case ARG_IRREVERSIBLE:
5042                         arg_job_mode = "replace-irreversibly";
5043                         break;
5044
5045                 case ARG_IGNORE_DEPENDENCIES:
5046                         arg_job_mode = "ignore-dependencies";
5047                         break;
5048
5049                 case ARG_USER:
5050                         arg_scope = UNIT_FILE_USER;
5051                         break;
5052
5053                 case ARG_SYSTEM:
5054                         arg_scope = UNIT_FILE_SYSTEM;
5055                         break;
5056
5057                 case ARG_GLOBAL:
5058                         arg_scope = UNIT_FILE_GLOBAL;
5059                         break;
5060
5061                 case ARG_NO_BLOCK:
5062                         arg_no_block = true;
5063                         break;
5064
5065                 case ARG_NO_LEGEND:
5066                         arg_no_legend = true;
5067                         break;
5068
5069                 case ARG_NO_PAGER:
5070                         arg_no_pager = true;
5071                         break;
5072
5073                 case ARG_NO_WALL:
5074                         arg_no_wall = true;
5075                         break;
5076
5077                 case ARG_ROOT:
5078                         arg_root = optarg;
5079                         break;
5080
5081                 case 'l':
5082                         arg_full = true;
5083                         break;
5084
5085                 case ARG_FAILED:
5086                         arg_failed = true;
5087                         break;
5088
5089                 case 'q':
5090                         arg_quiet = true;
5091                         break;
5092
5093                 case ARG_FORCE:
5094                         arg_force ++;
5095                         break;
5096
5097                 case 'f':
5098                         arg_force ++;
5099                         break;
5100
5101                 case ARG_NO_RELOAD:
5102                         arg_no_reload = true;
5103                         break;
5104
5105                 case ARG_KILL_WHO:
5106                         arg_kill_who = optarg;
5107                         break;
5108
5109                 case 's':
5110                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5111                                 log_error("Failed to parse signal string %s.", optarg);
5112                                 return -EINVAL;
5113                         }
5114                         break;
5115
5116                 case ARG_NO_ASK_PASSWORD:
5117                         arg_ask_password = false;
5118                         break;
5119
5120                 case 'P':
5121                         arg_transport = TRANSPORT_POLKIT;
5122                         break;
5123
5124                 case 'H':
5125                         arg_transport = TRANSPORT_SSH;
5126                         parse_user_at_host(optarg, &arg_user, &arg_host);
5127                         break;
5128
5129                 case ARG_RUNTIME:
5130                         arg_runtime = true;
5131                         break;
5132
5133                 case 'n':
5134                         if (safe_atou(optarg, &arg_lines) < 0) {
5135                                 log_error("Failed to parse lines '%s'", optarg);
5136                                 return -EINVAL;
5137                         }
5138                         break;
5139
5140                 case 'o':
5141                         arg_output = output_mode_from_string(optarg);
5142                         if (arg_output < 0) {
5143                                 log_error("Unknown output '%s'.", optarg);
5144                                 return -EINVAL;
5145                         }
5146                         break;
5147
5148                 case 'i':
5149                         arg_ignore_inhibitors = true;
5150                         break;
5151
5152                 case ARG_PLAIN:
5153                         arg_plain = true;
5154                         break;
5155
5156                 case '?':
5157                         return -EINVAL;
5158
5159                 default:
5160                         log_error("Unknown option code '%c'.", c);
5161                         return -EINVAL;
5162                 }
5163         }
5164
5165         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
5166                 log_error("Cannot access user instance remotely.");
5167                 return -EINVAL;
5168         }
5169
5170         return 1;
5171 }
5172
5173 static int halt_parse_argv(int argc, char *argv[]) {
5174
5175         enum {
5176                 ARG_HELP = 0x100,
5177                 ARG_HALT,
5178                 ARG_REBOOT,
5179                 ARG_NO_WALL
5180         };
5181
5182         static const struct option options[] = {
5183                 { "help",      no_argument,       NULL, ARG_HELP    },
5184                 { "halt",      no_argument,       NULL, ARG_HALT    },
5185                 { "poweroff",  no_argument,       NULL, 'p'         },
5186                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
5187                 { "force",     no_argument,       NULL, 'f'         },
5188                 { "wtmp-only", no_argument,       NULL, 'w'         },
5189                 { "no-wtmp",   no_argument,       NULL, 'd'         },
5190                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5191                 { NULL,        0,                 NULL, 0           }
5192         };
5193
5194         int c, runlevel;
5195
5196         assert(argc >= 0);
5197         assert(argv);
5198
5199         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5200                 if (runlevel == '0' || runlevel == '6')
5201                         arg_force = 2;
5202
5203         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5204                 switch (c) {
5205
5206                 case ARG_HELP:
5207                         halt_help();
5208                         return 0;
5209
5210                 case ARG_HALT:
5211                         arg_action = ACTION_HALT;
5212                         break;
5213
5214                 case 'p':
5215                         if (arg_action != ACTION_REBOOT)
5216                                 arg_action = ACTION_POWEROFF;
5217                         break;
5218
5219                 case ARG_REBOOT:
5220                         arg_action = ACTION_REBOOT;
5221                         break;
5222
5223                 case 'f':
5224                         arg_force = 2;
5225                         break;
5226
5227                 case 'w':
5228                         arg_dry = true;
5229                         break;
5230
5231                 case 'd':
5232                         arg_no_wtmp = true;
5233                         break;
5234
5235                 case ARG_NO_WALL:
5236                         arg_no_wall = true;
5237                         break;
5238
5239                 case 'i':
5240                 case 'h':
5241                 case 'n':
5242                         /* Compatibility nops */
5243                         break;
5244
5245                 case '?':
5246                         return -EINVAL;
5247
5248                 default:
5249                         log_error("Unknown option code '%c'.", c);
5250                         return -EINVAL;
5251                 }
5252         }
5253
5254         if (optind < argc) {
5255                 log_error("Too many arguments.");
5256                 return -EINVAL;
5257         }
5258
5259         return 1;
5260 }
5261
5262 static int parse_time_spec(const char *t, usec_t *_u) {
5263         assert(t);
5264         assert(_u);
5265
5266         if (streq(t, "now"))
5267                 *_u = 0;
5268         else if (!strchr(t, ':')) {
5269                 uint64_t u;
5270
5271                 if (safe_atou64(t, &u) < 0)
5272                         return -EINVAL;
5273
5274                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5275         } else {
5276                 char *e = NULL;
5277                 long hour, minute;
5278                 struct tm tm = {};
5279                 time_t s;
5280                 usec_t n;
5281
5282                 errno = 0;
5283                 hour = strtol(t, &e, 10);
5284                 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
5285                         return -EINVAL;
5286
5287                 minute = strtol(e+1, &e, 10);
5288                 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
5289                         return -EINVAL;
5290
5291                 n = now(CLOCK_REALTIME);
5292                 s = (time_t) (n / USEC_PER_SEC);
5293
5294                 assert_se(localtime_r(&s, &tm));
5295
5296                 tm.tm_hour = (int) hour;
5297                 tm.tm_min = (int) minute;
5298                 tm.tm_sec = 0;
5299
5300                 assert_se(s = mktime(&tm));
5301
5302                 *_u = (usec_t) s * USEC_PER_SEC;
5303
5304                 while (*_u <= n)
5305                         *_u += USEC_PER_DAY;
5306         }
5307
5308         return 0;
5309 }
5310
5311 static int shutdown_parse_argv(int argc, char *argv[]) {
5312
5313         enum {
5314                 ARG_HELP = 0x100,
5315                 ARG_NO_WALL
5316         };
5317
5318         static const struct option options[] = {
5319                 { "help",      no_argument,       NULL, ARG_HELP    },
5320                 { "halt",      no_argument,       NULL, 'H'         },
5321                 { "poweroff",  no_argument,       NULL, 'P'         },
5322                 { "reboot",    no_argument,       NULL, 'r'         },
5323                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
5324                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5325                 { NULL,        0,                 NULL, 0           }
5326         };
5327
5328         int c, r;
5329
5330         assert(argc >= 0);
5331         assert(argv);
5332
5333         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
5334                 switch (c) {
5335
5336                 case ARG_HELP:
5337                         shutdown_help();
5338                         return 0;
5339
5340                 case 'H':
5341                         arg_action = ACTION_HALT;
5342                         break;
5343
5344                 case 'P':
5345                         arg_action = ACTION_POWEROFF;
5346                         break;
5347
5348                 case 'r':
5349                         if (kexec_loaded())
5350                                 arg_action = ACTION_KEXEC;
5351                         else
5352                                 arg_action = ACTION_REBOOT;
5353                         break;
5354
5355                 case 'K':
5356                         arg_action = ACTION_KEXEC;
5357                         break;
5358
5359                 case 'h':
5360                         if (arg_action != ACTION_HALT)
5361                                 arg_action = ACTION_POWEROFF;
5362                         break;
5363
5364                 case 'k':
5365                         arg_dry = true;
5366                         break;
5367
5368                 case ARG_NO_WALL:
5369                         arg_no_wall = true;
5370                         break;
5371
5372                 case 't':
5373                 case 'a':
5374                         /* Compatibility nops */
5375                         break;
5376
5377                 case 'c':
5378                         arg_action = ACTION_CANCEL_SHUTDOWN;
5379                         break;
5380
5381                 case '?':
5382                         return -EINVAL;
5383
5384                 default:
5385                         log_error("Unknown option code '%c'.", c);
5386                         return -EINVAL;
5387                 }
5388         }
5389
5390         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
5391                 r = parse_time_spec(argv[optind], &arg_when);
5392                 if (r < 0) {
5393                         log_error("Failed to parse time specification: %s", argv[optind]);
5394                         return r;
5395                 }
5396         } else
5397                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
5398
5399         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5400                 /* No time argument for shutdown cancel */
5401                 arg_wall = argv + optind;
5402         else if (argc > optind + 1)
5403                 /* We skip the time argument */
5404                 arg_wall = argv + optind + 1;
5405
5406         optind = argc;
5407
5408         return 1;
5409 }
5410
5411 static int telinit_parse_argv(int argc, char *argv[]) {
5412
5413         enum {
5414                 ARG_HELP = 0x100,
5415                 ARG_NO_WALL
5416         };
5417
5418         static const struct option options[] = {
5419                 { "help",      no_argument,       NULL, ARG_HELP    },
5420                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5421                 { NULL,        0,                 NULL, 0           }
5422         };
5423
5424         static const struct {
5425                 char from;
5426                 enum action to;
5427         } table[] = {
5428                 { '0', ACTION_POWEROFF },
5429                 { '6', ACTION_REBOOT },
5430                 { '1', ACTION_RESCUE },
5431                 { '2', ACTION_RUNLEVEL2 },
5432                 { '3', ACTION_RUNLEVEL3 },
5433                 { '4', ACTION_RUNLEVEL4 },
5434                 { '5', ACTION_RUNLEVEL5 },
5435                 { 's', ACTION_RESCUE },
5436                 { 'S', ACTION_RESCUE },
5437                 { 'q', ACTION_RELOAD },
5438                 { 'Q', ACTION_RELOAD },
5439                 { 'u', ACTION_REEXEC },
5440                 { 'U', ACTION_REEXEC }
5441         };
5442
5443         unsigned i;
5444         int c;
5445
5446         assert(argc >= 0);
5447         assert(argv);
5448
5449         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5450                 switch (c) {
5451
5452                 case ARG_HELP:
5453                         telinit_help();
5454                         return 0;
5455
5456                 case ARG_NO_WALL:
5457                         arg_no_wall = true;
5458                         break;
5459
5460                 case '?':
5461                         return -EINVAL;
5462
5463                 default:
5464                         log_error("Unknown option code '%c'.", c);
5465                         return -EINVAL;
5466                 }
5467         }
5468
5469         if (optind >= argc) {
5470                 telinit_help();
5471                 return -EINVAL;
5472         }
5473
5474         if (optind + 1 < argc) {
5475                 log_error("Too many arguments.");
5476                 return -EINVAL;
5477         }
5478
5479         if (strlen(argv[optind]) != 1) {
5480                 log_error("Expected single character argument.");
5481                 return -EINVAL;
5482         }
5483
5484         for (i = 0; i < ELEMENTSOF(table); i++)
5485                 if (table[i].from == argv[optind][0])
5486                         break;
5487
5488         if (i >= ELEMENTSOF(table)) {
5489                 log_error("Unknown command '%s'.", argv[optind]);
5490                 return -EINVAL;
5491         }
5492
5493         arg_action = table[i].to;
5494
5495         optind ++;
5496
5497         return 1;
5498 }
5499
5500 static int runlevel_parse_argv(int argc, char *argv[]) {
5501
5502         enum {
5503                 ARG_HELP = 0x100,
5504         };
5505
5506         static const struct option options[] = {
5507                 { "help",      no_argument,       NULL, ARG_HELP    },
5508                 { NULL,        0,                 NULL, 0           }
5509         };
5510
5511         int c;
5512
5513         assert(argc >= 0);
5514         assert(argv);
5515
5516         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5517                 switch (c) {
5518
5519                 case ARG_HELP:
5520                         runlevel_help();
5521                         return 0;
5522
5523                 case '?':
5524                         return -EINVAL;
5525
5526                 default:
5527                         log_error("Unknown option code '%c'.", c);
5528                         return -EINVAL;
5529                 }
5530         }
5531
5532         if (optind < argc) {
5533                 log_error("Too many arguments.");
5534                 return -EINVAL;
5535         }
5536
5537         return 1;
5538 }
5539
5540 static int parse_argv(int argc, char *argv[]) {
5541         assert(argc >= 0);
5542         assert(argv);
5543
5544         if (program_invocation_short_name) {
5545
5546                 if (strstr(program_invocation_short_name, "halt")) {
5547                         arg_action = ACTION_HALT;
5548                         return halt_parse_argv(argc, argv);
5549                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5550                         arg_action = ACTION_POWEROFF;
5551                         return halt_parse_argv(argc, argv);
5552                 } else if (strstr(program_invocation_short_name, "reboot")) {
5553                         if (kexec_loaded())
5554                                 arg_action = ACTION_KEXEC;
5555                         else
5556                                 arg_action = ACTION_REBOOT;
5557                         return halt_parse_argv(argc, argv);
5558                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5559                         arg_action = ACTION_POWEROFF;
5560                         return shutdown_parse_argv(argc, argv);
5561                 } else if (strstr(program_invocation_short_name, "init")) {
5562
5563                         if (sd_booted() > 0) {
5564                                 arg_action = ACTION_INVALID;
5565                                 return telinit_parse_argv(argc, argv);
5566                         } else {
5567                                 /* Hmm, so some other init system is
5568                                  * running, we need to forward this
5569                                  * request to it. For now we simply
5570                                  * guess that it is Upstart. */
5571
5572                                 execv(TELINIT, argv);
5573
5574                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5575                                 return -EIO;
5576                         }
5577
5578                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5579                         arg_action = ACTION_RUNLEVEL;
5580                         return runlevel_parse_argv(argc, argv);
5581                 }
5582         }
5583
5584         arg_action = ACTION_SYSTEMCTL;
5585         return systemctl_parse_argv(argc, argv);
5586 }
5587
5588 _pure_ static int action_to_runlevel(void) {
5589
5590         static const char table[_ACTION_MAX] = {
5591                 [ACTION_HALT] =      '0',
5592                 [ACTION_POWEROFF] =  '0',
5593                 [ACTION_REBOOT] =    '6',
5594                 [ACTION_RUNLEVEL2] = '2',
5595                 [ACTION_RUNLEVEL3] = '3',
5596                 [ACTION_RUNLEVEL4] = '4',
5597                 [ACTION_RUNLEVEL5] = '5',
5598                 [ACTION_RESCUE] =    '1'
5599         };
5600
5601         assert(arg_action < _ACTION_MAX);
5602
5603         return table[arg_action];
5604 }
5605
5606 static int talk_upstart(void) {
5607         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
5608         _cleanup_dbus_error_free_ DBusError error;
5609         int previous, rl, r;
5610         char
5611                 env1_buf[] = "RUNLEVEL=X",
5612                 env2_buf[] = "PREVLEVEL=X";
5613         char *env1 = env1_buf, *env2 = env2_buf;
5614         const char *emit = "runlevel";
5615         dbus_bool_t b_false = FALSE;
5616         DBusMessageIter iter, sub;
5617         DBusConnection *bus;
5618
5619         dbus_error_init(&error);
5620
5621         if (!(rl = action_to_runlevel()))
5622                 return 0;
5623
5624         if (utmp_get_runlevel(&previous, NULL) < 0)
5625                 previous = 'N';
5626
5627         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5628                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5629                         r = 0;
5630                         goto finish;
5631                 }
5632
5633                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5634                 r = -EIO;
5635                 goto finish;
5636         }
5637
5638         if ((r = bus_check_peercred(bus)) < 0) {
5639                 log_error("Failed to verify owner of bus.");
5640                 goto finish;
5641         }
5642
5643         if (!(m = dbus_message_new_method_call(
5644                               "com.ubuntu.Upstart",
5645                               "/com/ubuntu/Upstart",
5646                               "com.ubuntu.Upstart0_6",
5647                               "EmitEvent"))) {
5648
5649                 log_error("Could not allocate message.");
5650                 r = -ENOMEM;
5651                 goto finish;
5652         }
5653
5654         dbus_message_iter_init_append(m, &iter);
5655
5656         env1_buf[sizeof(env1_buf)-2] = rl;
5657         env2_buf[sizeof(env2_buf)-2] = previous;
5658
5659         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5660             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5661             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5662             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5663             !dbus_message_iter_close_container(&iter, &sub) ||
5664             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5665                 log_error("Could not append arguments to message.");
5666                 r = -ENOMEM;
5667                 goto finish;
5668         }
5669
5670         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5671
5672                 if (bus_error_is_no_service(&error)) {
5673                         r = -EADDRNOTAVAIL;
5674                         goto finish;
5675                 }
5676
5677                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5678                 r = -EIO;
5679                 goto finish;
5680         }
5681
5682         r = 1;
5683
5684 finish:
5685         if (bus) {
5686                 dbus_connection_flush(bus);
5687                 dbus_connection_close(bus);
5688                 dbus_connection_unref(bus);
5689         }
5690
5691         return r;
5692 }
5693
5694 static int talk_initctl(void) {
5695         struct init_request request = {};
5696         int r;
5697         _cleanup_close_ int fd = -1;
5698         char rl;
5699
5700         rl = action_to_runlevel();
5701         if (!rl)
5702                 return 0;
5703
5704         request.magic = INIT_MAGIC;
5705         request.sleeptime = 0;
5706         request.cmd = INIT_CMD_RUNLVL;
5707         request.runlevel = rl;
5708
5709         fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5710         if (fd < 0) {
5711                 if (errno == ENOENT)
5712                         return 0;
5713
5714                 log_error("Failed to open "INIT_FIFO": %m");
5715                 return -errno;
5716         }
5717
5718         errno = 0;
5719         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5720         if (r) {
5721                 log_error("Failed to write to "INIT_FIFO": %m");
5722                 return errno > 0 ? -errno : -EIO;
5723         }
5724
5725         return 1;
5726 }
5727
5728 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5729
5730         static const struct {
5731                 const char* verb;
5732                 const enum {
5733                         MORE,
5734                         LESS,
5735                         EQUAL
5736                 } argc_cmp;
5737                 const int argc;
5738                 int (* const dispatch)(DBusConnection *bus, char **args);
5739         } verbs[] = {
5740                 { "list-units",            LESS,  1, list_units        },
5741                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5742                 { "list-sockets",          LESS,  1, list_sockets      },
5743                 { "list-jobs",             EQUAL, 1, list_jobs         },
5744                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5745                 { "load",                  MORE,  2, load_unit         },
5746                 { "cancel",                MORE,  2, cancel_job        },
5747                 { "start",                 MORE,  2, start_unit        },
5748                 { "stop",                  MORE,  2, start_unit        },
5749                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5750                 { "reload",                MORE,  2, start_unit        },
5751                 { "restart",               MORE,  2, start_unit        },
5752                 { "try-restart",           MORE,  2, start_unit        },
5753                 { "reload-or-restart",     MORE,  2, start_unit        },
5754                 { "reload-or-try-restart", MORE,  2, start_unit        },
5755                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5756                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5757                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5758                 { "isolate",               EQUAL, 2, start_unit        },
5759                 { "kill",                  MORE,  2, kill_unit         },
5760                 { "is-active",             MORE,  2, check_unit_active },
5761                 { "check",                 MORE,  2, check_unit_active },
5762                 { "is-failed",             MORE,  2, check_unit_failed },
5763                 { "show",                  MORE,  1, show              },
5764                 { "status",                MORE,  1, show              },
5765                 { "help",                  MORE,  2, show              },
5766                 { "dump",                  EQUAL, 1, dump              },
5767                 { "snapshot",              LESS,  2, snapshot          },
5768                 { "delete",                MORE,  2, delete_snapshot   },
5769                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5770                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5771                 { "show-environment",      EQUAL, 1, show_enviroment   },
5772                 { "set-environment",       MORE,  2, set_environment   },
5773                 { "unset-environment",     MORE,  2, set_environment   },
5774                 { "halt",                  EQUAL, 1, start_special     },
5775                 { "poweroff",              EQUAL, 1, start_special     },
5776                 { "reboot",                EQUAL, 1, start_special     },
5777                 { "kexec",                 EQUAL, 1, start_special     },
5778                 { "suspend",               EQUAL, 1, start_special     },
5779                 { "hibernate",             EQUAL, 1, start_special     },
5780                 { "hybrid-sleep",          EQUAL, 1, start_special     },
5781                 { "default",               EQUAL, 1, start_special     },
5782                 { "rescue",                EQUAL, 1, start_special     },
5783                 { "emergency",             EQUAL, 1, start_special     },
5784                 { "exit",                  EQUAL, 1, start_special     },
5785                 { "reset-failed",          MORE,  1, reset_failed      },
5786                 { "enable",                MORE,  2, enable_unit       },
5787                 { "disable",               MORE,  2, enable_unit       },
5788                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5789                 { "reenable",              MORE,  2, enable_unit       },
5790                 { "preset",                MORE,  2, enable_unit       },
5791                 { "mask",                  MORE,  2, enable_unit       },
5792                 { "unmask",                MORE,  2, enable_unit       },
5793                 { "link",                  MORE,  2, enable_unit       },
5794                 { "switch-root",           MORE,  2, switch_root       },
5795                 { "list-dependencies",     LESS,  2, list_dependencies },
5796                 { "set-default",           EQUAL, 2, enable_unit       },
5797                 { "get-default",           LESS,  1, get_default       },
5798                 { "set-log-level",         EQUAL, 2, set_log_level     },
5799                 { "set-property",          MORE,  3, set_property      },
5800         };
5801
5802         int left;
5803         unsigned i;
5804
5805         assert(argc >= 0);
5806         assert(argv);
5807         assert(error);
5808
5809         left = argc - optind;
5810
5811         if (left <= 0)
5812                 /* Special rule: no arguments means "list-units" */
5813                 i = 0;
5814         else {
5815                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5816                         log_error("This command expects one or more "
5817                                   "unit names. Did you mean --help?");
5818                         return -EINVAL;
5819                 }
5820
5821                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5822                         if (streq(argv[optind], verbs[i].verb))
5823                                 break;
5824
5825                 if (i >= ELEMENTSOF(verbs)) {
5826                         log_error("Unknown operation '%s'.", argv[optind]);
5827                         return -EINVAL;
5828                 }
5829         }
5830
5831         switch (verbs[i].argc_cmp) {
5832
5833         case EQUAL:
5834                 if (left != verbs[i].argc) {
5835                         log_error("Invalid number of arguments.");
5836                         return -EINVAL;
5837                 }
5838
5839                 break;
5840
5841         case MORE:
5842                 if (left < verbs[i].argc) {
5843                         log_error("Too few arguments.");
5844                         return -EINVAL;
5845                 }
5846
5847                 break;
5848
5849         case LESS:
5850                 if (left > verbs[i].argc) {
5851                         log_error("Too many arguments.");
5852                         return -EINVAL;
5853                 }
5854
5855                 break;
5856
5857         default:
5858                 assert_not_reached("Unknown comparison operator.");
5859         }
5860
5861         /* Require a bus connection for all operations but
5862          * enable/disable */
5863         if (!streq(verbs[i].verb, "enable") &&
5864             !streq(verbs[i].verb, "disable") &&
5865             !streq(verbs[i].verb, "is-enabled") &&
5866             !streq(verbs[i].verb, "list-unit-files") &&
5867             !streq(verbs[i].verb, "reenable") &&
5868             !streq(verbs[i].verb, "preset") &&
5869             !streq(verbs[i].verb, "mask") &&
5870             !streq(verbs[i].verb, "unmask") &&
5871             !streq(verbs[i].verb, "link") &&
5872             !streq(verbs[i].verb, "set-default") &&
5873             !streq(verbs[i].verb, "get-default")) {
5874
5875                 if (running_in_chroot() > 0) {
5876                         log_info("Running in chroot, ignoring request.");
5877                         return 0;
5878                 }
5879
5880                 if (((!streq(verbs[i].verb, "reboot") &&
5881                       !streq(verbs[i].verb, "halt") &&
5882                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5883                         log_error("Failed to get D-Bus connection: %s",
5884                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5885                         return -EIO;
5886                 }
5887
5888         } else {
5889
5890                 if (!bus && !avoid_bus()) {
5891                         log_error("Failed to get D-Bus connection: %s",
5892                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5893                         return -EIO;
5894                 }
5895         }
5896
5897         return verbs[i].dispatch(bus, argv + optind);
5898 }
5899
5900 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5901         _cleanup_close_ int fd;
5902         struct sd_shutdown_command c = {
5903                 .usec = t,
5904                 .mode = mode,
5905                 .dry_run = dry_run,
5906                 .warn_wall = warn,
5907         };
5908         union sockaddr_union sockaddr = {
5909                 .un.sun_family = AF_UNIX,
5910                 .un.sun_path = "/run/systemd/shutdownd",
5911         };
5912         struct iovec iovec[2] = {
5913                 {.iov_base = (char*) &c,
5914                  .iov_len = offsetof(struct sd_shutdown_command, wall_message),
5915                 }
5916         };
5917         struct msghdr msghdr = {
5918                 .msg_name = &sockaddr,
5919                 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
5920                                + sizeof("/run/systemd/shutdownd") - 1,
5921                 .msg_iov = iovec,
5922                 .msg_iovlen = 1,
5923         };
5924
5925         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5926         if (fd < 0)
5927                 return -errno;
5928
5929         if (!isempty(message)) {
5930                 iovec[1].iov_base = (char*) message;
5931                 iovec[1].iov_len = strlen(message);
5932                 msghdr.msg_iovlen++;
5933         }
5934
5935         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
5936                 return -errno;
5937
5938         return 0;
5939 }
5940
5941 static int reload_with_fallback(DBusConnection *bus) {
5942
5943         if (bus) {
5944                 /* First, try systemd via D-Bus. */
5945                 if (daemon_reload(bus, NULL) >= 0)
5946                         return 0;
5947         }
5948
5949         /* Nothing else worked, so let's try signals */
5950         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5951
5952         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5953                 log_error("kill() failed: %m");
5954                 return -errno;
5955         }
5956
5957         return 0;
5958 }
5959
5960 static int start_with_fallback(DBusConnection *bus) {
5961
5962         if (bus) {
5963                 /* First, try systemd via D-Bus. */
5964                 if (start_unit(bus, NULL) >= 0)
5965                         goto done;
5966         }
5967
5968         /* Hmm, talking to systemd via D-Bus didn't work. Then
5969          * let's try to talk to Upstart via D-Bus. */
5970         if (talk_upstart() > 0)
5971                 goto done;
5972
5973         /* Nothing else worked, so let's try
5974          * /dev/initctl */
5975         if (talk_initctl() > 0)
5976                 goto done;
5977
5978         log_error("Failed to talk to init daemon.");
5979         return -EIO;
5980
5981 done:
5982         warn_wall(arg_action);
5983         return 0;
5984 }
5985
5986 static _noreturn_ void halt_now(enum action a) {
5987
5988        /* Make sure C-A-D is handled by the kernel from this
5989          * point on... */
5990         reboot(RB_ENABLE_CAD);
5991
5992         switch (a) {
5993
5994         case ACTION_HALT:
5995                 log_info("Halting.");
5996                 reboot(RB_HALT_SYSTEM);
5997                 break;
5998
5999         case ACTION_POWEROFF:
6000                 log_info("Powering off.");
6001                 reboot(RB_POWER_OFF);
6002                 break;
6003
6004         case ACTION_REBOOT:
6005                 log_info("Rebooting.");
6006                 reboot(RB_AUTOBOOT);
6007                 break;
6008
6009         default:
6010                 assert_not_reached("Unknown halt action.");
6011         }
6012
6013         assert_not_reached("Uh? This shouldn't happen.");
6014 }
6015
6016 static int halt_main(DBusConnection *bus) {
6017         int r;
6018
6019         r = check_inhibitors(bus, arg_action);
6020         if (r < 0)
6021                 return r;
6022
6023         if (geteuid() != 0) {
6024                 /* Try logind if we are a normal user and no special
6025                  * mode applies. Maybe PolicyKit allows us to shutdown
6026                  * the machine. */
6027
6028                 if (arg_when <= 0 &&
6029                     !arg_dry &&
6030                     arg_force <= 0 &&
6031                     (arg_action == ACTION_POWEROFF ||
6032                      arg_action == ACTION_REBOOT)) {
6033                         r = reboot_with_logind(bus, arg_action);
6034                         if (r >= 0)
6035                                 return r;
6036                 }
6037
6038                 log_error("Must be root.");
6039                 return -EPERM;
6040         }
6041
6042         if (arg_when > 0) {
6043                 _cleanup_free_ char *m;
6044
6045                 m = strv_join(arg_wall, " ");
6046                 r = send_shutdownd(arg_when,
6047                                    arg_action == ACTION_HALT     ? 'H' :
6048                                    arg_action == ACTION_POWEROFF ? 'P' :
6049                                    arg_action == ACTION_KEXEC    ? 'K' :
6050                                                                    'r',
6051                                    arg_dry,
6052                                    !arg_no_wall,
6053                                    m);
6054
6055                 if (r < 0)
6056                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
6057                 else {
6058                         char date[FORMAT_TIMESTAMP_MAX];
6059
6060                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6061                                  format_timestamp(date, sizeof(date), arg_when));
6062                         return 0;
6063                 }
6064         }
6065
6066         if (!arg_dry && !arg_force)
6067                 return start_with_fallback(bus);
6068
6069         if (!arg_no_wtmp) {
6070                 if (sd_booted() > 0)
6071                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
6072                 else {
6073                         r = utmp_put_shutdown();
6074                         if (r < 0)
6075                                 log_warning("Failed to write utmp record: %s", strerror(-r));
6076                 }
6077         }
6078
6079         if (arg_dry)
6080                 return 0;
6081
6082         halt_now(arg_action);
6083         /* We should never reach this. */
6084         return -ENOSYS;
6085 }
6086
6087 static int runlevel_main(void) {
6088         int r, runlevel, previous;
6089
6090         r = utmp_get_runlevel(&runlevel, &previous);
6091         if (r < 0) {
6092                 puts("unknown");
6093                 return r;
6094         }
6095
6096         printf("%c %c\n",
6097                previous <= 0 ? 'N' : previous,
6098                runlevel <= 0 ? 'N' : runlevel);
6099
6100         return 0;
6101 }
6102
6103 int main(int argc, char*argv[]) {
6104         int r, retval = EXIT_FAILURE;
6105         DBusConnection *bus = NULL;
6106         _cleanup_dbus_error_free_ DBusError error;
6107
6108         dbus_error_init(&error);
6109
6110         setlocale(LC_ALL, "");
6111         log_parse_environment();
6112         log_open();
6113
6114         r = parse_argv(argc, argv);
6115         if (r < 0)
6116                 goto finish;
6117         else if (r == 0) {
6118                 retval = EXIT_SUCCESS;
6119                 goto finish;
6120         }
6121
6122         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6123          * let's shortcut this */
6124         if (arg_action == ACTION_RUNLEVEL) {
6125                 r = runlevel_main();
6126                 retval = r < 0 ? EXIT_FAILURE : r;
6127                 goto finish;
6128         }
6129
6130         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6131                 log_info("Running in chroot, ignoring request.");
6132                 retval = 0;
6133                 goto finish;
6134         }
6135
6136         if (!avoid_bus()) {
6137                 if (arg_transport == TRANSPORT_NORMAL)
6138                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
6139                 else if (arg_transport == TRANSPORT_POLKIT) {
6140                         bus_connect_system_polkit(&bus, &error);
6141                         private_bus = false;
6142                 } else if (arg_transport == TRANSPORT_SSH) {
6143                         bus_connect_system_ssh(arg_user, arg_host, &bus, &error);
6144                         private_bus = false;
6145                 } else
6146                         assert_not_reached("Uh, invalid transport...");
6147         }
6148
6149         switch (arg_action) {
6150
6151         case ACTION_SYSTEMCTL:
6152                 r = systemctl_main(bus, argc, argv, &error);
6153                 break;
6154
6155         case ACTION_HALT:
6156         case ACTION_POWEROFF:
6157         case ACTION_REBOOT:
6158         case ACTION_KEXEC:
6159                 r = halt_main(bus);
6160                 break;
6161
6162         case ACTION_RUNLEVEL2:
6163         case ACTION_RUNLEVEL3:
6164         case ACTION_RUNLEVEL4:
6165         case ACTION_RUNLEVEL5:
6166         case ACTION_RESCUE:
6167         case ACTION_EMERGENCY:
6168         case ACTION_DEFAULT:
6169                 r = start_with_fallback(bus);
6170                 break;
6171
6172         case ACTION_RELOAD:
6173         case ACTION_REEXEC:
6174                 r = reload_with_fallback(bus);
6175                 break;
6176
6177         case ACTION_CANCEL_SHUTDOWN: {
6178                 char *m = NULL;
6179
6180                 if (arg_wall) {
6181                         m = strv_join(arg_wall, " ");
6182                         if (!m) {
6183                                 retval = EXIT_FAILURE;
6184                                 goto finish;
6185                         }
6186                 }
6187                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6188                 if (r < 0)
6189                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
6190                 free(m);
6191                 break;
6192         }
6193
6194         case ACTION_INVALID:
6195         case ACTION_RUNLEVEL:
6196         default:
6197                 assert_not_reached("Unknown action");
6198         }
6199
6200         retval = r < 0 ? EXIT_FAILURE : r;
6201
6202 finish:
6203         if (bus) {
6204                 dbus_connection_flush(bus);
6205                 dbus_connection_close(bus);
6206                 dbus_connection_unref(bus);
6207         }
6208
6209         dbus_shutdown();
6210
6211         strv_free(arg_types);
6212         strv_free(arg_load_states);
6213         strv_free(arg_properties);
6214
6215         pager_close();
6216         ask_password_agent_close();
6217         polkit_agent_close();
6218
6219         return retval;
6220 }