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