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