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