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