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