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