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