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