chiark / gitweb /
408a4f0506dd080da0bbe0809cf0527f50d8ca55
[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         const char *runtime;
2181
2182         assert(bus);
2183         assert(args);
2184
2185         dbus_error_init(&error);
2186
2187         method =
2188                 streq(args[0], "set-cgroup")  ? "SetUnitControlGroups" :
2189                 streq(args[0], "unset-group") ? "UnsetUnitControlGroups"
2190                                               : "UnsetUnitControlGroupAttributes";
2191
2192         n = unit_name_mangle(args[1]);
2193         if (!n)
2194                 return log_oom();
2195
2196         m = dbus_message_new_method_call(
2197                         "org.freedesktop.systemd1",
2198                         "/org/freedesktop/systemd1",
2199                         "org.freedesktop.systemd1.Manager",
2200                         method);
2201         if (!m)
2202                 return log_oom();
2203
2204         dbus_message_iter_init_append(m, &iter);
2205         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2206                 return log_oom();
2207
2208         r = bus_append_strv_iter(&iter, args + 2);
2209         if (r < 0)
2210                 return log_oom();
2211
2212         runtime = arg_runtime ? "runtime" : "persistent";
2213         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2214                 return log_oom();
2215
2216         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2217         if (!reply) {
2218                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2219                 dbus_error_free(&error);
2220                 return -EIO;
2221         }
2222
2223         return 0;
2224 }
2225
2226 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2227         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2228         DBusError error;
2229         DBusMessageIter iter, sub, sub2;
2230         char **x, **y;
2231         _cleanup_free_ char *n = NULL;
2232         const char *runtime;
2233
2234         assert(bus);
2235         assert(args);
2236
2237         dbus_error_init(&error);
2238
2239         if (strv_length(args) % 2 != 0) {
2240                 log_error("Expecting an uneven number of arguments!");
2241                 return -EINVAL;
2242         }
2243
2244         n = unit_name_mangle(args[1]);
2245         if (!n)
2246                 return log_oom();
2247
2248         m = dbus_message_new_method_call(
2249                         "org.freedesktop.systemd1",
2250                         "/org/freedesktop/systemd1",
2251                         "org.freedesktop.systemd1.Manager",
2252                         "SetUnitControlGroupAttributes");
2253         if (!m)
2254                 return log_oom();
2255
2256         dbus_message_iter_init_append(m, &iter);
2257         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2258             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub))
2259                 return log_oom();
2260
2261         STRV_FOREACH_PAIR(x, y, args + 2) {
2262                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2263                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) ||
2264                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) ||
2265                     !dbus_message_iter_close_container(&sub, &sub2))
2266                         return log_oom();
2267         }
2268
2269         runtime = arg_runtime ? "runtime" : "persistent";
2270         if (!dbus_message_iter_close_container(&iter, &sub) ||
2271             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2272                 return log_oom();
2273
2274         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2275         if (!reply) {
2276                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2277                 dbus_error_free(&error);
2278                 return -EIO;
2279         }
2280
2281         return 0;
2282 }
2283
2284 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2285         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2286         DBusError error;
2287         DBusMessageIter iter;
2288         int r;
2289         _cleanup_free_ char *n = NULL;
2290         _cleanup_strv_free_ char **list = NULL;
2291         char **a;
2292
2293         assert(bus);
2294         assert(args);
2295
2296         dbus_error_init(&error);
2297
2298         n = unit_name_mangle(args[1]);
2299         if (!n)
2300                 return log_oom();
2301
2302         m = dbus_message_new_method_call(
2303                         "org.freedesktop.systemd1",
2304                         "/org/freedesktop/systemd1",
2305                         "org.freedesktop.systemd1.Manager",
2306                         "GetUnitControlGroupAttributes");
2307         if (!m)
2308                 return log_oom();
2309
2310         dbus_message_iter_init_append(m, &iter);
2311         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2312                 return log_oom();
2313
2314         r = bus_append_strv_iter(&iter, args + 2);
2315         if (r < 0)
2316                 return log_oom();
2317
2318         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2319         if (!reply) {
2320                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2321                 dbus_error_free(&error);
2322                 return -EIO;
2323         }
2324
2325         dbus_message_iter_init(reply, &iter);
2326         r = bus_parse_strv_iter(&iter, &list);
2327         if (r < 0) {
2328                 log_error("Failed to parse value list.");
2329                 return r;
2330         }
2331
2332         STRV_FOREACH(a, list) {
2333                 if (endswith(*a, "\n"))
2334                         fputs(*a, stdout);
2335                 else
2336                         puts(*a);
2337         }
2338
2339         return 0;
2340 }
2341
2342 typedef struct ExecStatusInfo {
2343         char *name;
2344
2345         char *path;
2346         char **argv;
2347
2348         bool ignore;
2349
2350         usec_t start_timestamp;
2351         usec_t exit_timestamp;
2352         pid_t pid;
2353         int code;
2354         int status;
2355
2356         LIST_FIELDS(struct ExecStatusInfo, exec);
2357 } ExecStatusInfo;
2358
2359 static void exec_status_info_free(ExecStatusInfo *i) {
2360         assert(i);
2361
2362         free(i->name);
2363         free(i->path);
2364         strv_free(i->argv);
2365         free(i);
2366 }
2367
2368 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2369         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2370         DBusMessageIter sub2, sub3;
2371         const char*path;
2372         unsigned n;
2373         uint32_t pid;
2374         int32_t code, status;
2375         dbus_bool_t ignore;
2376
2377         assert(i);
2378         assert(i);
2379
2380         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2381                 return -EIO;
2382
2383         dbus_message_iter_recurse(sub, &sub2);
2384
2385         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2386                 return -EIO;
2387
2388         i->path = strdup(path);
2389         if (!i->path)
2390                 return -ENOMEM;
2391
2392         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2393             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2394                 return -EIO;
2395
2396         n = 0;
2397         dbus_message_iter_recurse(&sub2, &sub3);
2398         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2399                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2400                 dbus_message_iter_next(&sub3);
2401                 n++;
2402         }
2403
2404         i->argv = new0(char*, n+1);
2405         if (!i->argv)
2406                 return -ENOMEM;
2407
2408         n = 0;
2409         dbus_message_iter_recurse(&sub2, &sub3);
2410         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2411                 const char *s;
2412
2413                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2414                 dbus_message_iter_get_basic(&sub3, &s);
2415                 dbus_message_iter_next(&sub3);
2416
2417                 i->argv[n] = strdup(s);
2418                 if (!i->argv[n])
2419                         return -ENOMEM;
2420
2421                 n++;
2422         }
2423
2424         if (!dbus_message_iter_next(&sub2) ||
2425             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2426             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2427             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2428             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2429             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2430             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2431             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2432             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2433                 return -EIO;
2434
2435         i->ignore = ignore;
2436         i->start_timestamp = (usec_t) start_timestamp;
2437         i->exit_timestamp = (usec_t) exit_timestamp;
2438         i->pid = (pid_t) pid;
2439         i->code = code;
2440         i->status = status;
2441
2442         return 0;
2443 }
2444
2445 typedef struct UnitStatusInfo {
2446         const char *id;
2447         const char *load_state;
2448         const char *active_state;
2449         const char *sub_state;
2450         const char *unit_file_state;
2451
2452         const char *description;
2453         const char *following;
2454
2455         char **documentation;
2456
2457         const char *fragment_path;
2458         const char *source_path;
2459         const char *default_control_group;
2460
2461         const char *load_error;
2462         const char *result;
2463
2464         usec_t inactive_exit_timestamp;
2465         usec_t inactive_exit_timestamp_monotonic;
2466         usec_t active_enter_timestamp;
2467         usec_t active_exit_timestamp;
2468         usec_t inactive_enter_timestamp;
2469
2470         bool need_daemon_reload;
2471
2472         /* Service */
2473         pid_t main_pid;
2474         pid_t control_pid;
2475         const char *status_text;
2476         bool running:1;
2477
2478         usec_t start_timestamp;
2479         usec_t exit_timestamp;
2480
2481         int exit_code, exit_status;
2482
2483         usec_t condition_timestamp;
2484         bool condition_result;
2485
2486         /* Socket */
2487         unsigned n_accepted;
2488         unsigned n_connections;
2489         bool accept;
2490
2491         /* Device */
2492         const char *sysfs_path;
2493
2494         /* Mount, Automount */
2495         const char *where;
2496
2497         /* Swap */
2498         const char *what;
2499
2500         LIST_HEAD(ExecStatusInfo, exec);
2501 } UnitStatusInfo;
2502
2503 static void print_status_info(UnitStatusInfo *i) {
2504         ExecStatusInfo *p;
2505         const char *on, *off, *ss;
2506         usec_t timestamp;
2507         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2508         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2509         const char *path;
2510         int flags =
2511                 arg_all * OUTPUT_SHOW_ALL |
2512                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2513                 on_tty() * OUTPUT_COLOR |
2514                 !arg_quiet * OUTPUT_WARN_CUTOFF |
2515                 arg_full * OUTPUT_FULL_WIDTH;
2516
2517         assert(i);
2518
2519         /* This shows pretty information about a unit. See
2520          * print_property() for a low-level property printer */
2521
2522         printf("%s", strna(i->id));
2523
2524         if (i->description && !streq_ptr(i->id, i->description))
2525                 printf(" - %s", i->description);
2526
2527         printf("\n");
2528
2529         if (i->following)
2530                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2531
2532         if (streq_ptr(i->load_state, "error")) {
2533                 on = ansi_highlight_red(true);
2534                 off = ansi_highlight_red(false);
2535         } else
2536                 on = off = "";
2537
2538         path = i->source_path ? i->source_path : i->fragment_path;
2539
2540         if (i->load_error)
2541                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2542         else if (path && i->unit_file_state)
2543                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2544         else if (path)
2545                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2546         else
2547                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2548
2549         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2550
2551         if (streq_ptr(i->active_state, "failed")) {
2552                 on = ansi_highlight_red(true);
2553                 off = ansi_highlight_red(false);
2554         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2555                 on = ansi_highlight_green(true);
2556                 off = ansi_highlight_green(false);
2557         } else
2558                 on = off = "";
2559
2560         if (ss)
2561                 printf("\t  Active: %s%s (%s)%s",
2562                        on,
2563                        strna(i->active_state),
2564                        ss,
2565                        off);
2566         else
2567                 printf("\t  Active: %s%s%s",
2568                        on,
2569                        strna(i->active_state),
2570                        off);
2571
2572         if (!isempty(i->result) && !streq(i->result, "success"))
2573                 printf(" (Result: %s)", i->result);
2574
2575         timestamp = (streq_ptr(i->active_state, "active")      ||
2576                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2577                     (streq_ptr(i->active_state, "inactive")    ||
2578                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2579                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2580                                                                   i->active_exit_timestamp;
2581
2582         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2583         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2584
2585         if (s1)
2586                 printf(" since %s; %s\n", s2, s1);
2587         else if (s2)
2588                 printf(" since %s\n", s2);
2589         else
2590                 printf("\n");
2591
2592         if (!i->condition_result && i->condition_timestamp > 0) {
2593                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2594                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2595
2596                 if (s1)
2597                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2598                 else if (s2)
2599                         printf("\t          start condition failed at %s\n", s2);
2600         }
2601
2602         if (i->sysfs_path)
2603                 printf("\t  Device: %s\n", i->sysfs_path);
2604         if (i->where)
2605                 printf("\t   Where: %s\n", i->where);
2606         if (i->what)
2607                 printf("\t    What: %s\n", i->what);
2608
2609         if (!strv_isempty(i->documentation)) {
2610                 char **t;
2611                 bool first = true;
2612
2613                 STRV_FOREACH(t, i->documentation) {
2614                         if (first) {
2615                                 printf("\t    Docs: %s\n", *t);
2616                                 first = false;
2617                         } else
2618                                 printf("\t          %s\n", *t);
2619                 }
2620         }
2621
2622         if (i->accept)
2623                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2624
2625         LIST_FOREACH(exec, p, i->exec) {
2626                 _cleanup_free_ char *t = NULL;
2627                 bool good;
2628
2629                 /* Only show exited processes here */
2630                 if (p->code == 0)
2631                         continue;
2632
2633                 t = strv_join(p->argv, " ");
2634                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2635
2636                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2637                 if (!good) {
2638                         on = ansi_highlight_red(true);
2639                         off = ansi_highlight_red(false);
2640                 } else
2641                         on = off = "";
2642
2643                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2644
2645                 if (p->code == CLD_EXITED) {
2646                         const char *c;
2647
2648                         printf("status=%i", p->status);
2649
2650                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2651                         if (c)
2652                                 printf("/%s", c);
2653
2654                 } else
2655                         printf("signal=%s", signal_to_string(p->status));
2656
2657                 printf(")%s\n", off);
2658
2659                 if (i->main_pid == p->pid &&
2660                     i->start_timestamp == p->start_timestamp &&
2661                     i->exit_timestamp == p->start_timestamp)
2662                         /* Let's not show this twice */
2663                         i->main_pid = 0;
2664
2665                 if (p->pid == i->control_pid)
2666                         i->control_pid = 0;
2667         }
2668
2669         if (i->main_pid > 0 || i->control_pid > 0) {
2670                 printf("\t");
2671
2672                 if (i->main_pid > 0) {
2673                         printf("Main PID: %u", (unsigned) i->main_pid);
2674
2675                         if (i->running) {
2676                                 _cleanup_free_ char *t = NULL;
2677                                 get_process_comm(i->main_pid, &t);
2678                                 if (t)
2679                                         printf(" (%s)", t);
2680                         } else if (i->exit_code > 0) {
2681                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2682
2683                                 if (i->exit_code == CLD_EXITED) {
2684                                         const char *c;
2685
2686                                         printf("status=%i", i->exit_status);
2687
2688                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2689                                         if (c)
2690                                                 printf("/%s", c);
2691
2692                                 } else
2693                                         printf("signal=%s", signal_to_string(i->exit_status));
2694                                 printf(")");
2695                         }
2696                 }
2697
2698                 if (i->main_pid > 0 && i->control_pid > 0)
2699                         printf(";");
2700
2701                 if (i->control_pid > 0) {
2702                         _cleanup_free_ char *t = NULL;
2703
2704                         printf(" Control: %u", (unsigned) i->control_pid);
2705
2706                         get_process_comm(i->control_pid, &t);
2707                         if (t)
2708                                 printf(" (%s)", t);
2709                 }
2710
2711                 printf("\n");
2712         }
2713
2714         if (i->status_text)
2715                 printf("\t  Status: \"%s\"\n", i->status_text);
2716
2717         if (i->default_control_group &&
2718             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2719                 unsigned c;
2720
2721                 printf("\t  CGroup: %s\n", i->default_control_group);
2722
2723                 if (arg_transport != TRANSPORT_SSH) {
2724                         unsigned k = 0;
2725                         pid_t extra[2];
2726
2727                         c = columns();
2728                         if (c > 18)
2729                                 c -= 18;
2730                         else
2731                                 c = 0;
2732
2733                         if (i->main_pid > 0)
2734                                 extra[k++] = i->main_pid;
2735
2736                         if (i->control_pid > 0)
2737                                 extra[k++] = i->control_pid;
2738
2739                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, extra, k, flags);
2740                 }
2741         }
2742
2743         if (i->id && arg_transport != TRANSPORT_SSH) {
2744                 printf("\n");
2745                 if(arg_scope == UNIT_FILE_SYSTEM)
2746                         show_journal_by_unit(stdout,
2747                                              i->id,
2748                                              arg_output,
2749                                              0,
2750                                              i->inactive_exit_timestamp_monotonic,
2751                                              arg_lines,
2752                                              flags);
2753                 else
2754                         show_journal_by_user_unit(stdout,
2755                                                   i->id,
2756                                                   arg_output,
2757                                                   0,
2758                                                   i->inactive_exit_timestamp_monotonic,
2759                                                   arg_lines,
2760                                                   getuid(),
2761                                                   flags);
2762         }
2763
2764         if (i->need_daemon_reload)
2765                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2766                        ansi_highlight_red(true),
2767                        ansi_highlight_red(false),
2768                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2769 }
2770
2771 static void show_unit_help(UnitStatusInfo *i) {
2772         char **p;
2773
2774         assert(i);
2775
2776         if (!i->documentation) {
2777                 log_info("Documentation for %s not known.", i->id);
2778                 return;
2779         }
2780
2781         STRV_FOREACH(p, i->documentation) {
2782
2783                 if (startswith(*p, "man:")) {
2784                         size_t k;
2785                         char *e = NULL;
2786                         char *page = NULL, *section = NULL;
2787                         const char *args[4] = { "man", NULL, NULL, NULL };
2788                         pid_t pid;
2789
2790                         k = strlen(*p);
2791
2792                         if ((*p)[k-1] == ')')
2793                                 e = strrchr(*p, '(');
2794
2795                         if (e) {
2796                                 page = strndup((*p) + 4, e - *p - 4);
2797                                 if (!page) {
2798                                         log_oom();
2799                                         return;
2800                                 }
2801
2802                                 section = strndup(e + 1, *p + k - e - 2);
2803                                 if (!section) {
2804                                         free(page);
2805                                         log_oom();
2806                                         return;
2807                                 }
2808
2809                                 args[1] = section;
2810                                 args[2] = page;
2811                         } else
2812                                 args[1] = *p + 4;
2813
2814                         pid = fork();
2815                         if (pid < 0) {
2816                                 log_error("Failed to fork: %m");
2817                                 free(page);
2818                                 free(section);
2819                                 continue;
2820                         }
2821
2822                         if (pid == 0) {
2823                                 /* Child */
2824                                 execvp(args[0], (char**) args);
2825                                 log_error("Failed to execute man: %m");
2826                                 _exit(EXIT_FAILURE);
2827                         }
2828
2829                         free(page);
2830                         free(section);
2831
2832                         wait_for_terminate(pid, NULL);
2833                 } else
2834                         log_info("Can't show: %s", *p);
2835         }
2836 }
2837
2838 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2839
2840         assert(name);
2841         assert(iter);
2842         assert(i);
2843
2844         switch (dbus_message_iter_get_arg_type(iter)) {
2845
2846         case DBUS_TYPE_STRING: {
2847                 const char *s;
2848
2849                 dbus_message_iter_get_basic(iter, &s);
2850
2851                 if (!isempty(s)) {
2852                         if (streq(name, "Id"))
2853                                 i->id = s;
2854                         else if (streq(name, "LoadState"))
2855                                 i->load_state = s;
2856                         else if (streq(name, "ActiveState"))
2857                                 i->active_state = s;
2858                         else if (streq(name, "SubState"))
2859                                 i->sub_state = s;
2860                         else if (streq(name, "Description"))
2861                                 i->description = s;
2862                         else if (streq(name, "FragmentPath"))
2863                                 i->fragment_path = s;
2864                         else if (streq(name, "SourcePath"))
2865                                 i->source_path = s;
2866                         else if (streq(name, "DefaultControlGroup"))
2867                                 i->default_control_group = s;
2868                         else if (streq(name, "StatusText"))
2869                                 i->status_text = s;
2870                         else if (streq(name, "SysFSPath"))
2871                                 i->sysfs_path = s;
2872                         else if (streq(name, "Where"))
2873                                 i->where = s;
2874                         else if (streq(name, "What"))
2875                                 i->what = s;
2876                         else if (streq(name, "Following"))
2877                                 i->following = s;
2878                         else if (streq(name, "UnitFileState"))
2879                                 i->unit_file_state = s;
2880                         else if (streq(name, "Result"))
2881                                 i->result = s;
2882                 }
2883
2884                 break;
2885         }
2886
2887         case DBUS_TYPE_BOOLEAN: {
2888                 dbus_bool_t b;
2889
2890                 dbus_message_iter_get_basic(iter, &b);
2891
2892                 if (streq(name, "Accept"))
2893                         i->accept = b;
2894                 else if (streq(name, "NeedDaemonReload"))
2895                         i->need_daemon_reload = b;
2896                 else if (streq(name, "ConditionResult"))
2897                         i->condition_result = b;
2898
2899                 break;
2900         }
2901
2902         case DBUS_TYPE_UINT32: {
2903                 uint32_t u;
2904
2905                 dbus_message_iter_get_basic(iter, &u);
2906
2907                 if (streq(name, "MainPID")) {
2908                         if (u > 0) {
2909                                 i->main_pid = (pid_t) u;
2910                                 i->running = true;
2911                         }
2912                 } else if (streq(name, "ControlPID"))
2913                         i->control_pid = (pid_t) u;
2914                 else if (streq(name, "ExecMainPID")) {
2915                         if (u > 0)
2916                                 i->main_pid = (pid_t) u;
2917                 } else if (streq(name, "NAccepted"))
2918                         i->n_accepted = u;
2919                 else if (streq(name, "NConnections"))
2920                         i->n_connections = u;
2921
2922                 break;
2923         }
2924
2925         case DBUS_TYPE_INT32: {
2926                 int32_t j;
2927
2928                 dbus_message_iter_get_basic(iter, &j);
2929
2930                 if (streq(name, "ExecMainCode"))
2931                         i->exit_code = (int) j;
2932                 else if (streq(name, "ExecMainStatus"))
2933                         i->exit_status = (int) j;
2934
2935                 break;
2936         }
2937
2938         case DBUS_TYPE_UINT64: {
2939                 uint64_t u;
2940
2941                 dbus_message_iter_get_basic(iter, &u);
2942
2943                 if (streq(name, "ExecMainStartTimestamp"))
2944                         i->start_timestamp = (usec_t) u;
2945                 else if (streq(name, "ExecMainExitTimestamp"))
2946                         i->exit_timestamp = (usec_t) u;
2947                 else if (streq(name, "ActiveEnterTimestamp"))
2948                         i->active_enter_timestamp = (usec_t) u;
2949                 else if (streq(name, "InactiveEnterTimestamp"))
2950                         i->inactive_enter_timestamp = (usec_t) u;
2951                 else if (streq(name, "InactiveExitTimestamp"))
2952                         i->inactive_exit_timestamp = (usec_t) u;
2953                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2954                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2955                 else if (streq(name, "ActiveExitTimestamp"))
2956                         i->active_exit_timestamp = (usec_t) u;
2957                 else if (streq(name, "ConditionTimestamp"))
2958                         i->condition_timestamp = (usec_t) u;
2959
2960                 break;
2961         }
2962
2963         case DBUS_TYPE_ARRAY: {
2964
2965                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2966                     startswith(name, "Exec")) {
2967                         DBusMessageIter sub;
2968
2969                         dbus_message_iter_recurse(iter, &sub);
2970                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2971                                 ExecStatusInfo *info;
2972                                 int r;
2973
2974                                 if (!(info = new0(ExecStatusInfo, 1)))
2975                                         return -ENOMEM;
2976
2977                                 if (!(info->name = strdup(name))) {
2978                                         free(info);
2979                                         return -ENOMEM;
2980                                 }
2981
2982                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2983                                         free(info);
2984                                         return r;
2985                                 }
2986
2987                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2988
2989                                 dbus_message_iter_next(&sub);
2990                         }
2991                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2992                            streq(name, "Documentation")) {
2993
2994                         DBusMessageIter sub;
2995
2996                         dbus_message_iter_recurse(iter, &sub);
2997                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2998                                 const char *s;
2999                                 char **l;
3000
3001                                 dbus_message_iter_get_basic(&sub, &s);
3002
3003                                 l = strv_append(i->documentation, s);
3004                                 if (!l)
3005                                         return -ENOMEM;
3006
3007                                 strv_free(i->documentation);
3008                                 i->documentation = l;
3009
3010                                 dbus_message_iter_next(&sub);
3011                         }
3012                 }
3013
3014                 break;
3015         }
3016
3017         case DBUS_TYPE_STRUCT: {
3018
3019                 if (streq(name, "LoadError")) {
3020                         DBusMessageIter sub;
3021                         const char *n, *message;
3022                         int r;
3023
3024                         dbus_message_iter_recurse(iter, &sub);
3025
3026                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
3027                         if (r < 0)
3028                                 return r;
3029
3030                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
3031                         if (r < 0)
3032                                 return r;
3033
3034                         if (!isempty(message))
3035                                 i->load_error = message;
3036                 }
3037
3038                 break;
3039         }
3040         }
3041
3042         return 0;
3043 }
3044
3045 static int print_property(const char *name, DBusMessageIter *iter) {
3046         assert(name);
3047         assert(iter);
3048
3049         /* This is a low-level property printer, see
3050          * print_status_info() for the nicer output */
3051
3052         if (arg_property && !strv_find(arg_property, name))
3053                 return 0;
3054
3055         switch (dbus_message_iter_get_arg_type(iter)) {
3056
3057         case DBUS_TYPE_STRUCT: {
3058                 DBusMessageIter sub;
3059                 dbus_message_iter_recurse(iter, &sub);
3060
3061                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
3062                         uint32_t u;
3063
3064                         dbus_message_iter_get_basic(&sub, &u);
3065
3066                         if (u)
3067                                 printf("%s=%u\n", name, (unsigned) u);
3068                         else if (arg_all)
3069                                 printf("%s=\n", name);
3070
3071                         return 0;
3072                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
3073                         const char *s;
3074
3075                         dbus_message_iter_get_basic(&sub, &s);
3076
3077                         if (arg_all || s[0])
3078                                 printf("%s=%s\n", name, s);
3079
3080                         return 0;
3081                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
3082                         const char *a = NULL, *b = NULL;
3083
3084                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
3085                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
3086
3087                         if (arg_all || !isempty(a) || !isempty(b))
3088                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
3089
3090                         return 0;
3091                 }
3092
3093                 break;
3094         }
3095
3096         case DBUS_TYPE_ARRAY:
3097
3098                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
3099                         DBusMessageIter sub, sub2;
3100
3101                         dbus_message_iter_recurse(iter, &sub);
3102                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3103                                 const char *path;
3104                                 dbus_bool_t ignore;
3105
3106                                 dbus_message_iter_recurse(&sub, &sub2);
3107
3108                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3109                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
3110                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
3111
3112                                 dbus_message_iter_next(&sub);
3113                         }
3114
3115                         return 0;
3116
3117                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
3118                         DBusMessageIter sub, sub2;
3119
3120                         dbus_message_iter_recurse(iter, &sub);
3121                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3122                                 const char *type, *path;
3123
3124                                 dbus_message_iter_recurse(&sub, &sub2);
3125
3126                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3127                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3128                                         printf("%s=%s\n", type, path);
3129
3130                                 dbus_message_iter_next(&sub);
3131                         }
3132
3133                         return 0;
3134
3135                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
3136                         DBusMessageIter sub, sub2;
3137
3138                         dbus_message_iter_recurse(iter, &sub);
3139                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3140                                 const char *base;
3141                                 uint64_t value, next_elapse;
3142
3143                                 dbus_message_iter_recurse(&sub, &sub2);
3144
3145                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
3146                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
3147                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
3148                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
3149
3150                                         printf("%s={ value=%s ; next_elapse=%s }\n",
3151                                                base,
3152                                                format_timespan(timespan1, sizeof(timespan1), value),
3153                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
3154                                 }
3155
3156                                 dbus_message_iter_next(&sub);
3157                         }
3158
3159                         return 0;
3160
3161                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
3162                         DBusMessageIter sub, sub2;
3163
3164                         dbus_message_iter_recurse(iter, &sub);
3165                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3166                                 const char *controller, *attr, *value;
3167
3168                                 dbus_message_iter_recurse(&sub, &sub2);
3169
3170                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
3171                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
3172                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
3173
3174                                         printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
3175                                                controller,
3176                                                attr,
3177                                                value);
3178                                 }
3179
3180                                 dbus_message_iter_next(&sub);
3181                         }
3182
3183                         return 0;
3184
3185                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3186                         DBusMessageIter sub;
3187
3188                         dbus_message_iter_recurse(iter, &sub);
3189                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3190                                 ExecStatusInfo info;
3191
3192                                 zero(info);
3193                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3194                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3195                                         char *t;
3196
3197                                         t = strv_join(info.argv, " ");
3198
3199                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3200                                                name,
3201                                                strna(info.path),
3202                                                strna(t),
3203                                                yes_no(info.ignore),
3204                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3205                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3206                                                (unsigned) info. pid,
3207                                                sigchld_code_to_string(info.code),
3208                                                info.status,
3209                                                info.code == CLD_EXITED ? "" : "/",
3210                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3211
3212                                         free(t);
3213                                 }
3214
3215                                 free(info.path);
3216                                 strv_free(info.argv);
3217
3218                                 dbus_message_iter_next(&sub);
3219                         }
3220
3221                         return 0;
3222                 }
3223
3224                 break;
3225         }
3226
3227         if (generic_print_property(name, iter, arg_all) > 0)
3228                 return 0;
3229
3230         if (arg_all)
3231                 printf("%s=[unprintable]\n", name);
3232
3233         return 0;
3234 }
3235
3236 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3237         _cleanup_free_ DBusMessage *reply = NULL;
3238         const char *interface = "";
3239         int r;
3240         DBusMessageIter iter, sub, sub2, sub3;
3241         UnitStatusInfo info;
3242         ExecStatusInfo *p;
3243
3244         assert(path);
3245         assert(new_line);
3246
3247         zero(info);
3248
3249         r = bus_method_call_with_reply(
3250                         bus,
3251                         "org.freedesktop.systemd1",
3252                         path,
3253                         "org.freedesktop.DBus.Properties",
3254                         "GetAll",
3255                         &reply,
3256                         NULL,
3257                         DBUS_TYPE_STRING, &interface,
3258                         DBUS_TYPE_INVALID);
3259         if (r < 0)
3260                 return r;
3261
3262         if (!dbus_message_iter_init(reply, &iter) ||
3263             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3264             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3265                 log_error("Failed to parse reply.");
3266                 return -EIO;
3267         }
3268
3269         dbus_message_iter_recurse(&iter, &sub);
3270
3271         if (*new_line)
3272                 printf("\n");
3273
3274         *new_line = true;
3275
3276         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3277                 const char *name;
3278
3279                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
3280                 dbus_message_iter_recurse(&sub, &sub2);
3281
3282                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
3283                     dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
3284                         log_error("Failed to parse reply.");
3285                         return -EIO;
3286                 }
3287
3288                 dbus_message_iter_recurse(&sub2, &sub3);
3289
3290                 if (show_properties)
3291                         r = print_property(name, &sub3);
3292                 else
3293                         r = status_property(name, &sub3, &info);
3294                 if (r < 0) {
3295                         log_error("Failed to parse reply.");
3296                         return -EIO;
3297                 }
3298
3299                 dbus_message_iter_next(&sub);
3300         }
3301
3302         r = 0;
3303
3304         if (!show_properties) {
3305                 if (streq(verb, "help"))
3306                         show_unit_help(&info);
3307                 else
3308                         print_status_info(&info);
3309         }
3310
3311         strv_free(info.documentation);
3312
3313         if (!streq_ptr(info.active_state, "active") &&
3314             !streq_ptr(info.active_state, "reloading") &&
3315             streq(verb, "status"))
3316                 /* According to LSB: "program not running" */
3317                 r = 3;
3318
3319         while ((p = info.exec)) {
3320                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3321                 exec_status_info_free(p);
3322         }
3323
3324         return r;
3325 }
3326
3327 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3328         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3329         const char *path = NULL;
3330         DBusError error;
3331         int r;
3332
3333         dbus_error_init(&error);
3334
3335         r = bus_method_call_with_reply(
3336                         bus,
3337                         "org.freedesktop.systemd1",
3338                         "/org/freedesktop/systemd1",
3339                         "org.freedesktop.systemd1.Manager",
3340                         "GetUnitByPID",
3341                         &reply,
3342                         NULL,
3343                         DBUS_TYPE_UINT32, &pid,
3344                         DBUS_TYPE_INVALID);
3345         if (r < 0)
3346                 goto finish;
3347
3348         if (!dbus_message_get_args(reply, &error,
3349                                    DBUS_TYPE_OBJECT_PATH, &path,
3350                                    DBUS_TYPE_INVALID)) {
3351                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3352                 r = -EIO;
3353                 goto finish;
3354         }
3355
3356         r = show_one(verb, bus, path, false, new_line);
3357
3358 finish:
3359         dbus_error_free(&error);
3360
3361         return r;
3362 }
3363
3364 static int show(DBusConnection *bus, char **args) {
3365         int r, ret = 0;
3366         bool show_properties, new_line = false;
3367         char **name;
3368
3369         assert(bus);
3370         assert(args);
3371
3372         show_properties = streq(args[0], "show");
3373
3374         if (show_properties)
3375                 pager_open_if_enabled();
3376
3377         /* If no argument is specified inspect the manager itself */
3378
3379         if (show_properties && strv_length(args) <= 1)
3380                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3381
3382         STRV_FOREACH(name, args+1) {
3383                 uint32_t id;
3384
3385                 if (safe_atou32(*name, &id) < 0) {
3386                         _cleanup_free_ char *p = NULL, *n = NULL;
3387                         /* Interpret as unit name */
3388
3389                         n = unit_name_mangle(*name);
3390                         if (!n)
3391                                 return log_oom();
3392
3393                         p = unit_dbus_path_from_name(n);
3394                         if (!p)
3395                                 return log_oom();
3396
3397                         r = show_one(args[0], bus, p, show_properties, &new_line);
3398                         if (r != 0)
3399                                 ret = r;
3400
3401                 } else if (show_properties) {
3402                         _cleanup_free_ char *p = NULL;
3403
3404                         /* Interpret as job id */
3405                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3406                                 return log_oom();
3407
3408                         r = show_one(args[0], bus, p, show_properties, &new_line);
3409                         if (r != 0)
3410                                 ret = r;
3411
3412                 } else {
3413                         /* Interpret as PID */
3414                         r = show_one_by_pid(args[0], bus, id, &new_line);
3415                         if (r != 0)
3416                                 ret = r;
3417                 }
3418         }
3419
3420         return ret;
3421 }
3422
3423 static int dump(DBusConnection *bus, char **args) {
3424         _cleanup_free_ DBusMessage *reply = NULL;
3425         DBusError error;
3426         int r;
3427         const char *text;
3428
3429         dbus_error_init(&error);
3430
3431         pager_open_if_enabled();
3432
3433         r = bus_method_call_with_reply(
3434                         bus,
3435                         "org.freedesktop.systemd1",
3436                         "/org/freedesktop/systemd1",
3437                         "org.freedesktop.systemd1.Manager",
3438                         "Dump",
3439                         &reply,
3440                         NULL,
3441                         DBUS_TYPE_INVALID);
3442         if (r < 0)
3443                 return r;
3444
3445         if (!dbus_message_get_args(reply, &error,
3446                                    DBUS_TYPE_STRING, &text,
3447                                    DBUS_TYPE_INVALID)) {
3448                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3449                 dbus_error_free(&error);
3450                 return  -EIO;
3451         }
3452
3453         fputs(text, stdout);
3454         return 0;
3455 }
3456
3457 static int snapshot(DBusConnection *bus, char **args) {
3458         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3459         DBusError error;
3460         int r;
3461         dbus_bool_t cleanup = FALSE;
3462         DBusMessageIter iter, sub;
3463         const char
3464                 *path, *id,
3465                 *interface = "org.freedesktop.systemd1.Unit",
3466                 *property = "Id";
3467         _cleanup_free_ char *n = NULL;
3468
3469         dbus_error_init(&error);
3470
3471         if (strv_length(args) > 1)
3472                 n = snapshot_name_mangle(args[1]);
3473         else
3474                 n = strdup("");
3475         if (!n)
3476                 return log_oom();
3477
3478         r = bus_method_call_with_reply (
3479                         bus,
3480                         "org.freedesktop.systemd1",
3481                         "/org/freedesktop/systemd1",
3482                         "org.freedesktop.systemd1.Manager",
3483                         "CreateSnapshot",
3484                         &reply,
3485                         NULL,
3486                         DBUS_TYPE_STRING, &n,
3487                         DBUS_TYPE_BOOLEAN, &cleanup,
3488                         DBUS_TYPE_INVALID);
3489         if (r < 0)
3490                 return r;
3491
3492         if (!dbus_message_get_args(reply, &error,
3493                                    DBUS_TYPE_OBJECT_PATH, &path,
3494                                    DBUS_TYPE_INVALID)) {
3495                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3496                 dbus_error_free(&error);
3497                 return -EIO;
3498         }
3499
3500         dbus_message_unref(reply);
3501         reply = NULL;
3502
3503         r = bus_method_call_with_reply (
3504                         bus,
3505                         "org.freedesktop.systemd1",
3506                         path,
3507                         "org.freedesktop.DBus.Properties",
3508                         "Get",
3509                         &reply,
3510                         NULL,
3511                         DBUS_TYPE_STRING, &interface,
3512                         DBUS_TYPE_STRING, &property,
3513                         DBUS_TYPE_INVALID);
3514         if (r < 0)
3515                 return r;
3516
3517         if (!dbus_message_iter_init(reply, &iter) ||
3518             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3519                 log_error("Failed to parse reply.");
3520                 return -EIO;
3521         }
3522
3523         dbus_message_iter_recurse(&iter, &sub);
3524
3525         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3526                 log_error("Failed to parse reply.");
3527                 return -EIO;
3528         }
3529
3530         dbus_message_iter_get_basic(&sub, &id);
3531
3532         if (!arg_quiet)
3533                 puts(id);
3534
3535         return 0;
3536 }
3537
3538 static int delete_snapshot(DBusConnection *bus, char **args) {
3539         char **name;
3540
3541         assert(args);
3542
3543         STRV_FOREACH(name, args+1) {
3544                 _cleanup_free_ char *n = NULL;
3545                 int r;
3546
3547                 n = snapshot_name_mangle(*name);
3548                 if (!n)
3549                         return log_oom();
3550
3551                 r = bus_method_call_with_reply(
3552                                 bus,
3553                                 "org.freedesktop.systemd1",
3554                                 "/org/freedesktop/systemd1",
3555                                 "org.freedesktop.systemd1.Manager",
3556                                 "RemoveSnapshot",
3557                                 NULL,
3558                                 NULL,
3559                                 DBUS_TYPE_STRING, &n,
3560                                 DBUS_TYPE_INVALID);
3561                 if (r < 0)
3562                         return r;
3563         }
3564
3565         return 0;
3566 }
3567
3568 static int daemon_reload(DBusConnection *bus, char **args) {
3569         int r;
3570         const char *method;
3571         DBusError error;
3572
3573         if (arg_action == ACTION_RELOAD)
3574                 method = "Reload";
3575         else if (arg_action == ACTION_REEXEC)
3576                 method = "Reexecute";
3577         else {
3578                 assert(arg_action == ACTION_SYSTEMCTL);
3579
3580                 method =
3581                         streq(args[0], "clear-jobs")    ||
3582                         streq(args[0], "cancel")        ? "ClearJobs" :
3583                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3584                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3585                         streq(args[0], "halt")          ? "Halt" :
3586                         streq(args[0], "poweroff")      ? "PowerOff" :
3587                         streq(args[0], "reboot")        ? "Reboot" :
3588                         streq(args[0], "kexec")         ? "KExec" :
3589                         streq(args[0], "exit")          ? "Exit" :
3590                                     /* "daemon-reload" */ "Reload";
3591         }
3592
3593         r = bus_method_call_with_reply(
3594                         bus,
3595                         "org.freedesktop.systemd1",
3596                         "/org/freedesktop/systemd1",
3597                         "org.freedesktop.systemd1.Manager",
3598                         method,
3599                         NULL,
3600                         &error,
3601                         DBUS_TYPE_INVALID);
3602
3603         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3604                 /* There's always a fallback possible for
3605                  * legacy actions. */
3606                 r = -EADDRNOTAVAIL;
3607         else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3608                 /* On reexecution, we expect a disconnect, not
3609                  * a reply */
3610                 r = 0;
3611         else if (r < 0)
3612                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3613
3614         dbus_error_free(&error);
3615         return r;
3616 }
3617
3618 static int reset_failed(DBusConnection *bus, char **args) {
3619         int r = 0;
3620         char **name;
3621
3622         if (strv_length(args) <= 1)
3623                 return daemon_reload(bus, args);
3624
3625         STRV_FOREACH(name, args+1) {
3626                 _cleanup_free_ char *n;
3627
3628                 n = unit_name_mangle(*name);
3629                 if (!n)
3630                         return log_oom();
3631
3632                 r = bus_method_call_with_reply(
3633                                 bus,
3634                                 "org.freedesktop.systemd1",
3635                                 "/org/freedesktop/systemd1",
3636                                 "org.freedesktop.systemd1.Manager",
3637                                 "ResetFailedUnit",
3638                                 NULL,
3639                                 NULL,
3640                                 DBUS_TYPE_STRING, &n,
3641                                 DBUS_TYPE_INVALID);
3642                 if (r < 0)
3643                         return r;
3644         }
3645
3646         return 0;
3647 }
3648
3649 static int show_enviroment(DBusConnection *bus, char **args) {
3650         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3651         DBusMessageIter iter, sub, sub2;
3652         int r;
3653         const char
3654                 *interface = "org.freedesktop.systemd1.Manager",
3655                 *property = "Environment";
3656
3657         pager_open_if_enabled();
3658
3659         r = bus_method_call_with_reply(
3660                         bus,
3661                         "org.freedesktop.systemd1",
3662                         "/org/freedesktop/systemd1",
3663                         "org.freedesktop.DBus.Properties",
3664                         "Get",
3665                         &reply,
3666                         NULL,
3667                         DBUS_TYPE_STRING, &interface,
3668                         DBUS_TYPE_STRING, &property,
3669                         DBUS_TYPE_INVALID);
3670         if (r < 0)
3671                 return r;
3672
3673         if (!dbus_message_iter_init(reply, &iter) ||
3674             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3675                 log_error("Failed to parse reply.");
3676                 return -EIO;
3677         }
3678
3679         dbus_message_iter_recurse(&iter, &sub);
3680
3681         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3682             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3683                 log_error("Failed to parse reply.");
3684                 return -EIO;
3685         }
3686
3687         dbus_message_iter_recurse(&sub, &sub2);
3688
3689         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3690                 const char *text;
3691
3692                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3693                         log_error("Failed to parse reply.");
3694                         return -EIO;
3695                 }
3696
3697                 dbus_message_iter_get_basic(&sub2, &text);
3698                 puts(text);
3699
3700                 dbus_message_iter_next(&sub2);
3701         }
3702
3703         return 0;
3704 }
3705
3706 static int switch_root(DBusConnection *bus, char **args) {
3707         unsigned l;
3708         const char *root;
3709         _cleanup_free_ char *init = NULL;
3710
3711         l = strv_length(args);
3712         if (l < 2 || l > 3) {
3713                 log_error("Wrong number of arguments.");
3714                 return -EINVAL;
3715         }
3716
3717         root = args[1];
3718
3719         if (l >= 3)
3720                 init = strdup(args[2]);
3721         else {
3722                 parse_env_file("/proc/cmdline", WHITESPACE,
3723                                "init", &init,
3724                                NULL);
3725
3726                 if (!init)
3727                         init = strdup("");
3728         }
3729         if (!init)
3730                 return log_oom();
3731
3732         log_debug("switching root - root: %s; init: %s", root, init);
3733
3734         return bus_method_call_with_reply(
3735                         bus,
3736                         "org.freedesktop.systemd1",
3737                         "/org/freedesktop/systemd1",
3738                         "org.freedesktop.systemd1.Manager",
3739                         "SwitchRoot",
3740                         NULL,
3741                         NULL,
3742                         DBUS_TYPE_STRING, &root,
3743                         DBUS_TYPE_STRING, &init,
3744                         DBUS_TYPE_INVALID);
3745 }
3746
3747 static int set_environment(DBusConnection *bus, char **args) {
3748         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
3749         DBusError error;
3750         const char *method;
3751         DBusMessageIter iter;
3752         int r;
3753
3754         assert(bus);
3755         assert(args);
3756
3757         dbus_error_init(&error);
3758
3759         method = streq(args[0], "set-environment")
3760                 ? "SetEnvironment"
3761                 : "UnsetEnvironment";
3762
3763         m = dbus_message_new_method_call(
3764                         "org.freedesktop.systemd1",
3765                         "/org/freedesktop/systemd1",
3766                         "org.freedesktop.systemd1.Manager",
3767                         method);
3768         if (!m)
3769                 return log_oom();
3770
3771         dbus_message_iter_init_append(m, &iter);
3772
3773         r = bus_append_strv_iter(&iter, args + 1);
3774         if (r < 0)
3775                 return log_oom();
3776
3777         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3778         if (!reply) {
3779                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3780                 dbus_error_free(&error);
3781                 return -EIO;
3782         }
3783
3784         return 0;
3785 }
3786
3787 static int enable_sysv_units(char **args) {
3788         int r = 0;
3789
3790 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
3791         const char *verb = args[0];
3792         unsigned f = 1, t = 1;
3793         LookupPaths paths;
3794
3795         if (arg_scope != UNIT_FILE_SYSTEM)
3796                 return 0;
3797
3798         if (!streq(verb, "enable") &&
3799             !streq(verb, "disable") &&
3800             !streq(verb, "is-enabled"))
3801                 return 0;
3802
3803         /* Processes all SysV units, and reshuffles the array so that
3804          * afterwards only the native units remain */
3805
3806         zero(paths);
3807         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
3808         if (r < 0)
3809                 return r;
3810
3811         r = 0;
3812         for (f = 1; args[f]; f++) {
3813                 const char *name;
3814                 char *p;
3815                 bool found_native = false, found_sysv;
3816                 unsigned c = 1;
3817                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3818                 char **k, *l, *q = NULL;
3819                 int j;
3820                 pid_t pid;
3821                 siginfo_t status;
3822
3823                 name = args[f];
3824
3825                 if (!endswith(name, ".service"))
3826                         continue;
3827
3828                 if (path_is_absolute(name))
3829                         continue;
3830
3831                 STRV_FOREACH(k, paths.unit_path) {
3832                         p = NULL;
3833
3834                         if (!isempty(arg_root))
3835                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3836                         else
3837                                 asprintf(&p, "%s/%s", *k, name);
3838
3839                         if (!p) {
3840                                 r = log_oom();
3841                                 goto finish;
3842                         }
3843
3844                         found_native = access(p, F_OK) >= 0;
3845                         free(p);
3846
3847                         if (found_native)
3848                                 break;
3849                 }
3850
3851                 if (found_native)
3852                         continue;
3853
3854                 p = NULL;
3855                 if (!isempty(arg_root))
3856                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3857                 else
3858                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3859                 if (!p) {
3860                         r = log_oom();
3861                         goto finish;
3862                 }
3863
3864                 p[strlen(p) - sizeof(".service") + 1] = 0;
3865                 found_sysv = access(p, F_OK) >= 0;
3866
3867                 if (!found_sysv) {
3868                         free(p);
3869                         continue;
3870                 }
3871
3872                 /* Mark this entry, so that we don't try enabling it as native unit */
3873                 args[f] = (char*) "";
3874
3875                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3876
3877                 if (!isempty(arg_root))
3878                         argv[c++] = q = strappend("--root=", arg_root);
3879
3880                 argv[c++] = path_get_file_name(p);
3881                 argv[c++] =
3882                         streq(verb, "enable") ? "on" :
3883                         streq(verb, "disable") ? "off" : "--level=5";
3884                 argv[c] = NULL;
3885
3886                 l = strv_join((char**)argv, " ");
3887                 if (!l) {
3888                         free(q);
3889                         free(p);
3890                         r = log_oom();
3891                         goto finish;
3892                 }
3893
3894                 log_info("Executing %s", l);
3895                 free(l);
3896
3897                 pid = fork();
3898                 if (pid < 0) {
3899                         log_error("Failed to fork: %m");
3900                         free(p);
3901                         free(q);
3902                         r = -errno;
3903                         goto finish;
3904                 } else if (pid == 0) {
3905                         /* Child */
3906
3907                         execv(argv[0], (char**) argv);
3908                         _exit(EXIT_FAILURE);
3909                 }
3910
3911                 free(p);
3912                 free(q);
3913
3914                 j = wait_for_terminate(pid, &status);
3915                 if (j < 0) {
3916                         log_error("Failed to wait for child: %s", strerror(-r));
3917                         r = j;
3918                         goto finish;
3919                 }
3920
3921                 if (status.si_code == CLD_EXITED) {
3922                         if (streq(verb, "is-enabled")) {
3923                                 if (status.si_status == 0) {
3924                                         if (!arg_quiet)
3925                                                 puts("enabled");
3926                                         r = 1;
3927                                 } else {
3928                                         if (!arg_quiet)
3929                                                 puts("disabled");
3930                                 }
3931
3932                         } else if (status.si_status != 0) {
3933                                 r = -EINVAL;
3934                                 goto finish;
3935                         }
3936                 } else {
3937                         r = -EPROTO;
3938                         goto finish;
3939                 }
3940         }
3941
3942 finish:
3943         lookup_paths_free(&paths);
3944
3945         /* Drop all SysV units */
3946         for (f = 1, t = 1; args[f]; f++) {
3947
3948                 if (isempty(args[f]))
3949                         continue;
3950
3951                 args[t++] = args[f];
3952         }
3953
3954         args[t] = NULL;
3955
3956 #endif
3957         return r;
3958 }
3959
3960 static int mangle_names(char **original_names, char ***mangled_names) {
3961         char **i, **l, **name;
3962
3963         l = new(char*, strv_length(original_names) + 1);
3964         if (!l)
3965                 return log_oom();
3966
3967         i = l;
3968         STRV_FOREACH(name, original_names) {
3969
3970                 /* When enabling units qualified path names are OK,
3971                  * too, hence allow them explicitly. */
3972
3973                 if (is_path(*name))
3974                         *i = strdup(*name);
3975                 else
3976                         *i = unit_name_mangle(*name);
3977
3978                 if (!*i) {
3979                         strv_free(l);
3980                         return log_oom();
3981                 }
3982
3983                 i++;
3984         }
3985
3986         *i = NULL;
3987         *mangled_names = l;
3988
3989         return 0;
3990 }
3991
3992 static int enable_unit(DBusConnection *bus, char **args) {
3993         const char *verb = args[0];
3994         UnitFileChange *changes = NULL;
3995         unsigned n_changes = 0, i;
3996         int carries_install_info = -1;
3997         DBusMessage *m = NULL, *reply = NULL;
3998         int r;
3999         DBusError error;
4000         char **mangled_names = NULL;
4001
4002         r = enable_sysv_units(args);
4003         if (r < 0)
4004                 return r;
4005
4006         if (!args[1])
4007                 return 0;
4008
4009         dbus_error_init(&error);
4010
4011         if (!bus || avoid_bus()) {
4012                 if (streq(verb, "enable")) {
4013                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4014                         carries_install_info = r;
4015                 } else if (streq(verb, "disable"))
4016                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4017                 else if (streq(verb, "reenable")) {
4018                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4019                         carries_install_info = r;
4020                 } else if (streq(verb, "link"))
4021                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4022                 else if (streq(verb, "preset")) {
4023                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4024                         carries_install_info = r;
4025                 } else if (streq(verb, "mask"))
4026                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4027                 else if (streq(verb, "unmask"))
4028                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4029                 else
4030                         assert_not_reached("Unknown verb");
4031
4032                 if (r < 0) {
4033                         log_error("Operation failed: %s", strerror(-r));
4034                         goto finish;
4035                 }
4036
4037                 if (!arg_quiet) {
4038                         for (i = 0; i < n_changes; i++) {
4039                                 if (changes[i].type == UNIT_FILE_SYMLINK)
4040                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4041                                 else
4042                                         log_info("rm '%s'", changes[i].path);
4043                         }
4044                 }
4045
4046                 r = 0;
4047         } else {
4048                 const char *method;
4049                 bool send_force = true, expect_carries_install_info = false;
4050                 dbus_bool_t a, b;
4051                 DBusMessageIter iter, sub, sub2;
4052
4053                 if (streq(verb, "enable")) {
4054                         method = "EnableUnitFiles";
4055                         expect_carries_install_info = true;
4056                 } else if (streq(verb, "disable")) {
4057                         method = "DisableUnitFiles";
4058                         send_force = false;
4059                 } else if (streq(verb, "reenable")) {
4060                         method = "ReenableUnitFiles";
4061                         expect_carries_install_info = true;
4062                 } else if (streq(verb, "link"))
4063                         method = "LinkUnitFiles";
4064                 else if (streq(verb, "preset")) {
4065                         method = "PresetUnitFiles";
4066                         expect_carries_install_info = true;
4067                 } else if (streq(verb, "mask"))
4068                         method = "MaskUnitFiles";
4069                 else if (streq(verb, "unmask")) {
4070                         method = "UnmaskUnitFiles";
4071                         send_force = false;
4072                 } else
4073                         assert_not_reached("Unknown verb");
4074
4075                 m = dbus_message_new_method_call(
4076                                 "org.freedesktop.systemd1",
4077                                 "/org/freedesktop/systemd1",
4078                                 "org.freedesktop.systemd1.Manager",
4079                                 method);
4080                 if (!m) {
4081                         r = log_oom();
4082                         goto finish;
4083                 }
4084
4085                 dbus_message_iter_init_append(m, &iter);
4086
4087                 r = mangle_names(args+1, &mangled_names);
4088                 if(r < 0)
4089                         goto finish;
4090
4091                 r = bus_append_strv_iter(&iter, mangled_names);
4092                 if (r < 0) {
4093                         log_error("Failed to append unit files.");
4094                         goto finish;
4095                 }
4096
4097                 a = arg_runtime;
4098                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4099                         log_error("Failed to append runtime boolean.");
4100                         r = -ENOMEM;
4101                         goto finish;
4102                 }
4103
4104                 if (send_force) {
4105                         b = arg_force;
4106
4107                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4108                                 log_error("Failed to append force boolean.");
4109                                 r = -ENOMEM;
4110                                 goto finish;
4111                         }
4112                 }
4113
4114                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4115                 if (!reply) {
4116                         log_error("Failed to issue method call: %s", bus_error_message(&error));
4117                         r = -EIO;
4118                         goto finish;
4119                 }
4120
4121                 if (!dbus_message_iter_init(reply, &iter)) {
4122                         log_error("Failed to initialize iterator.");
4123                         goto finish;
4124                 }
4125
4126                 if (expect_carries_install_info) {
4127                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4128                         if (r < 0) {
4129                                 log_error("Failed to parse reply.");
4130                                 goto finish;
4131                         }
4132
4133                         carries_install_info = b;
4134                 }
4135
4136                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4137                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4138                         log_error("Failed to parse reply.");
4139                         r = -EIO;
4140                         goto finish;
4141                 }
4142
4143                 dbus_message_iter_recurse(&iter, &sub);
4144                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4145                         const char *type, *path, *source;
4146
4147                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4148                                 log_error("Failed to parse reply.");
4149                                 r = -EIO;
4150                                 goto finish;
4151                         }
4152
4153                         dbus_message_iter_recurse(&sub, &sub2);
4154
4155                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4156                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4157                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4158                                 log_error("Failed to parse reply.");
4159                                 r = -EIO;
4160                                 goto finish;
4161                         }
4162
4163                         if (!arg_quiet) {
4164                                 if (streq(type, "symlink"))
4165                                         log_info("ln -s '%s' '%s'", source, path);
4166                                 else
4167                                         log_info("rm '%s'", path);
4168                         }
4169
4170                         dbus_message_iter_next(&sub);
4171                 }
4172
4173                 /* Try to reload if enabeld */
4174                 if (!arg_no_reload)
4175                         r = daemon_reload(bus, args);
4176         }
4177
4178         if (carries_install_info == 0)
4179                 log_warning(
4180 "The unit files have no [Install] section. They are not meant to be enabled\n"
4181 "using systemctl.\n"
4182 "Possible reasons for having this kind of units are:\n"
4183 "1) A unit may be statically enabled by being symlinked from another unit's\n"
4184 "   .wants/ or .requires/ directory.\n"
4185 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4186 "   a requirement dependency on it.\n"
4187 "3) A unit may be started when needed via activation (socket, path, timer,\n"
4188 "   D-Bus, udev, scripted systemctl call, ...).\n");
4189
4190 finish:
4191         if (m)
4192                 dbus_message_unref(m);
4193
4194         if (reply)
4195                 dbus_message_unref(reply);
4196
4197         unit_file_changes_free(changes, n_changes);
4198
4199         dbus_error_free(&error);
4200
4201         strv_free(mangled_names);
4202
4203         return r;
4204 }
4205
4206 static int unit_is_enabled(DBusConnection *bus, char **args) {
4207         DBusError error;
4208         int r;
4209         DBusMessage *reply = NULL;
4210         bool enabled;
4211         char **name;
4212
4213         dbus_error_init(&error);
4214
4215         r = enable_sysv_units(args);
4216         if (r < 0)
4217                 return r;
4218
4219         enabled = r > 0;
4220
4221         if (!bus || avoid_bus()) {
4222
4223                 STRV_FOREACH(name, args+1) {
4224                         UnitFileState state;
4225
4226                         state = unit_file_get_state(arg_scope, arg_root, *name);
4227                         if (state < 0) {
4228                                 r = state;
4229                                 goto finish;
4230                         }
4231
4232                         if (state == UNIT_FILE_ENABLED ||
4233                             state == UNIT_FILE_ENABLED_RUNTIME ||
4234                             state == UNIT_FILE_STATIC)
4235                                 enabled = true;
4236
4237                         if (!arg_quiet)
4238                                 puts(unit_file_state_to_string(state));
4239                 }
4240
4241         } else {
4242                 STRV_FOREACH(name, args+1) {
4243                         const char *s;
4244
4245                         r = bus_method_call_with_reply (
4246                                         bus,
4247                                         "org.freedesktop.systemd1",
4248                                         "/org/freedesktop/systemd1",
4249                                         "org.freedesktop.systemd1.Manager",
4250                                         "GetUnitFileState",
4251                                         &reply,
4252                                         NULL,
4253                                         DBUS_TYPE_STRING, name,
4254                                         DBUS_TYPE_INVALID);
4255                         if (r)
4256                                 goto finish;
4257
4258                         if (!dbus_message_get_args(reply, &error,
4259                                                    DBUS_TYPE_STRING, &s,
4260                                                    DBUS_TYPE_INVALID)) {
4261                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4262                                 r = -EIO;
4263                                 goto finish;
4264                         }
4265
4266                         dbus_message_unref(reply);
4267                         reply = NULL;
4268
4269                         if (streq(s, "enabled") ||
4270                             streq(s, "enabled-runtime") ||
4271                             streq(s, "static"))
4272                                 enabled = true;
4273
4274                         if (!arg_quiet)
4275                                 puts(s);
4276                 }
4277         }
4278
4279         r = enabled ? 0 : 1;
4280
4281 finish:
4282         if (reply)
4283                 dbus_message_unref(reply);
4284
4285         dbus_error_free(&error);
4286         return r;
4287 }
4288
4289 static int systemctl_help(void) {
4290
4291         pager_open_if_enabled();
4292
4293         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4294                "Query or send control commands to the systemd manager.\n\n"
4295                "  -h --help           Show this help\n"
4296                "     --version        Show package version\n"
4297                "  -t --type=TYPE      List only units of a particular type\n"
4298                "  -p --property=NAME  Show only properties by this name\n"
4299                "  -a --all            Show all units/properties, including dead/empty ones\n"
4300                "     --failed         Show only failed units\n"
4301                "     --full           Don't ellipsize unit names on output\n"
4302                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4303                "                      pending\n"
4304                "     --ignore-dependencies\n"
4305                "                      When queueing a new job, ignore all its dependencies\n"
4306                "  -i --ignore-inhibitors\n"
4307                "                      When shutting down or sleeping, ignore inhibitors\n"
4308                "     --kill-who=WHO   Who to send signal to\n"
4309                "  -s --signal=SIGNAL  Which signal to send\n"
4310                "  -H --host=[USER@]HOST\n"
4311                "                      Show information for remote host\n"
4312                "  -P --privileged     Acquire privileges before execution\n"
4313                "  -q --quiet          Suppress output\n"
4314                "     --no-block       Do not wait until operation finished\n"
4315                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4316                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4317                "                      configuration\n"
4318                "     --no-legend      Do not print a legend (column headers and hints)\n"
4319                "     --no-pager       Do not pipe output into a pager\n"
4320                "     --no-ask-password\n"
4321                "                      Do not ask for system passwords\n"
4322                "     --order          When generating graph for dot, show only order\n"
4323                "     --require        When generating graph for dot, show only requirement\n"
4324                "     --system         Connect to system manager\n"
4325                "     --user           Connect to user service manager\n"
4326                "     --global         Enable/disable unit files globally\n"
4327                "  -f --force          When enabling unit files, override existing symlinks\n"
4328                "                      When shutting down, execute action immediately\n"
4329                "     --root=PATH      Enable unit files in the specified root directory\n"
4330                "     --runtime        Enable unit files only temporarily until next reboot\n"
4331                "  -n --lines=INTEGER  Journal entries to show\n"
4332                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4333                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
4334                "Unit Commands:\n"
4335                "  list-units                      List loaded units\n"
4336                "  start [NAME...]                 Start (activate) one or more units\n"
4337                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4338                "  reload [NAME...]                Reload one or more units\n"
4339                "  restart [NAME...]               Start or restart one or more units\n"
4340                "  try-restart [NAME...]           Restart one or more units if active\n"
4341                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
4342                "                                  otherwise start or restart\n"
4343                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
4344                "                                  otherwise restart if active\n"
4345                "  isolate [NAME]                  Start one unit and stop all others\n"
4346                "  kill [NAME...]                  Send signal to processes of a unit\n"
4347                "  is-active [NAME...]             Check whether units are active\n"
4348                "  is-failed [NAME...]             Check whether units are failed\n"
4349                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4350                "  show [NAME...|JOB...]           Show properties of one or more\n"
4351                "                                  units/jobs or the manager\n"
4352                "  help [NAME...|PID...]           Show manual for one or more units\n"
4353                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4354                "                                  units\n"
4355                "  get-cgroup-attr [NAME] [ATTR] ...\n"
4356                "                                  Get control group attrubute\n"
4357                "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
4358                "                                  Set control group attribute\n"
4359                "  unset-cgroup-attr [NAME] [ATTR...]\n"
4360                "                                  Unset control group attribute\n"
4361                "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
4362                "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
4363                "  load [NAME...]                  Load one or more units\n"
4364                "  list-dependencies [NAME]        Recursively show units which are required\n"
4365                "                                  or wanted by this unit\n\n"
4366                "Unit File Commands:\n"
4367                "  list-unit-files                 List installed unit files\n"
4368                "  enable [NAME...]                Enable one or more unit files\n"
4369                "  disable [NAME...]               Disable one or more unit files\n"
4370                "  reenable [NAME...]              Reenable one or more unit files\n"
4371                "  preset [NAME...]                Enable/disable one or more unit files\n"
4372                "                                  based on preset configuration\n"
4373                "  mask [NAME...]                  Mask one or more units\n"
4374                "  unmask [NAME...]                Unmask one or more units\n"
4375                "  link [PATH...]                  Link one or more units files into\n"
4376                "                                  the search path\n"
4377                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4378                "Job Commands:\n"
4379                "  list-jobs                       List jobs\n"
4380                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4381                "Status Commands:\n"
4382                "  dump                            Dump server status\n"
4383                "  dot                             Dump dependency graph for dot(1)\n\n"
4384                "Snapshot Commands:\n"
4385                "  snapshot [NAME]                 Create a snapshot\n"
4386                "  delete [NAME...]                Remove one or more snapshots\n\n"
4387                "Environment Commands:\n"
4388                "  show-environment                Dump environment\n"
4389                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4390                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4391                "Manager Lifecycle Commands:\n"
4392                "  daemon-reload                   Reload systemd manager configuration\n"
4393                "  daemon-reexec                   Reexecute systemd manager\n\n"
4394                "System Commands:\n"
4395                "  default                         Enter system default mode\n"
4396                "  rescue                          Enter system rescue mode\n"
4397                "  emergency                       Enter system emergency mode\n"
4398                "  halt                            Shut down and halt the system\n"
4399                "  poweroff                        Shut down and power-off the system\n"
4400                "  reboot                          Shut down and reboot the system\n"
4401                "  kexec                           Shut down and reboot the system with kexec\n"
4402                "  exit                            Request user instance exit\n"
4403                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4404                "  suspend                         Suspend the system\n"
4405                "  hibernate                       Hibernate the system\n"
4406                "  hybrid-sleep                    Hibernate and suspend the system\n",
4407                program_invocation_short_name);
4408
4409         return 0;
4410 }
4411
4412 static int halt_help(void) {
4413
4414         printf("%s [OPTIONS...]\n\n"
4415                "%s the system.\n\n"
4416                "     --help      Show this help\n"
4417                "     --halt      Halt the machine\n"
4418                "  -p --poweroff  Switch off the machine\n"
4419                "     --reboot    Reboot the machine\n"
4420                "  -f --force     Force immediate halt/power-off/reboot\n"
4421                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4422                "  -d --no-wtmp   Don't write wtmp record\n"
4423                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4424                program_invocation_short_name,
4425                arg_action == ACTION_REBOOT   ? "Reboot" :
4426                arg_action == ACTION_POWEROFF ? "Power off" :
4427                                                "Halt");
4428
4429         return 0;
4430 }
4431
4432 static int shutdown_help(void) {
4433
4434         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4435                "Shut down the system.\n\n"
4436                "     --help      Show this help\n"
4437                "  -H --halt      Halt the machine\n"
4438                "  -P --poweroff  Power-off the machine\n"
4439                "  -r --reboot    Reboot the machine\n"
4440                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4441                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4442                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4443                "  -c             Cancel a pending shutdown\n",
4444                program_invocation_short_name);
4445
4446         return 0;
4447 }
4448
4449 static int telinit_help(void) {
4450
4451         printf("%s [OPTIONS...] {COMMAND}\n\n"
4452                "Send control commands to the init daemon.\n\n"
4453                "     --help      Show this help\n"
4454                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4455                "Commands:\n"
4456                "  0              Power-off the machine\n"
4457                "  6              Reboot the machine\n"
4458                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4459                "  1, s, S        Enter rescue mode\n"
4460                "  q, Q           Reload init daemon configuration\n"
4461                "  u, U           Reexecute init daemon\n",
4462                program_invocation_short_name);
4463
4464         return 0;
4465 }
4466
4467 static int runlevel_help(void) {
4468
4469         printf("%s [OPTIONS...]\n\n"
4470                "Prints the previous and current runlevel of the init system.\n\n"
4471                "     --help      Show this help\n",
4472                program_invocation_short_name);
4473
4474         return 0;
4475 }
4476
4477 static int help_types(void) {
4478         int i;
4479
4480         puts("Available unit types:");
4481         for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++)
4482                 if (unit_type_table[i])
4483                         puts(unit_type_table[i]);
4484
4485         puts("\nAvailable unit load states: ");
4486         for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++)
4487                 if (unit_type_table[i])
4488                         puts(unit_load_state_table[i]);
4489
4490         return 0;
4491 }
4492
4493 static int systemctl_parse_argv(int argc, char *argv[]) {
4494
4495         enum {
4496                 ARG_FAIL = 0x100,
4497                 ARG_IGNORE_DEPENDENCIES,
4498                 ARG_VERSION,
4499                 ARG_USER,
4500                 ARG_SYSTEM,
4501                 ARG_GLOBAL,
4502                 ARG_NO_BLOCK,
4503                 ARG_NO_LEGEND,
4504                 ARG_NO_PAGER,
4505                 ARG_NO_WALL,
4506                 ARG_ORDER,
4507                 ARG_REQUIRE,
4508                 ARG_ROOT,
4509                 ARG_FULL,
4510                 ARG_NO_RELOAD,
4511                 ARG_KILL_WHO,
4512                 ARG_NO_ASK_PASSWORD,
4513                 ARG_FAILED,
4514                 ARG_RUNTIME,
4515                 ARG_FORCE
4516         };
4517
4518         static const struct option options[] = {
4519                 { "help",      no_argument,       NULL, 'h'           },
4520                 { "version",   no_argument,       NULL, ARG_VERSION   },
4521                 { "type",      required_argument, NULL, 't'           },
4522                 { "property",  required_argument, NULL, 'p'           },
4523                 { "all",       no_argument,       NULL, 'a'           },
4524                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4525                 { "full",      no_argument,       NULL, ARG_FULL      },
4526                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4527                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4528                 { "ignore-inhibitors", no_argument, NULL, 'i'         },
4529                 { "user",      no_argument,       NULL, ARG_USER      },
4530                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4531                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4532                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4533                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4534                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4535                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4536                 { "quiet",     no_argument,       NULL, 'q'           },
4537                 { "order",     no_argument,       NULL, ARG_ORDER     },
4538                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4539                 { "root",      required_argument, NULL, ARG_ROOT      },
4540                 { "force",     no_argument,       NULL, ARG_FORCE     },
4541                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4542                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4543                 { "signal",    required_argument, NULL, 's'           },
4544                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4545                 { "host",      required_argument, NULL, 'H'           },
4546                 { "privileged",no_argument,       NULL, 'P'           },
4547                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4548                 { "lines",     required_argument, NULL, 'n'           },
4549                 { "output",    required_argument, NULL, 'o'           },
4550                 { NULL,        0,                 NULL, 0             }
4551         };
4552
4553         int c;
4554
4555         assert(argc >= 0);
4556         assert(argv);
4557
4558         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) {
4559
4560                 switch (c) {
4561
4562                 case 'h':
4563                         systemctl_help();
4564                         return 0;
4565
4566                 case ARG_VERSION:
4567                         puts(PACKAGE_STRING);
4568                         puts(SYSTEMD_FEATURES);
4569                         return 0;
4570
4571                 case 't':
4572                         if (streq(optarg, "help")) {
4573                                 help_types();
4574                                 return 0;
4575                         }
4576
4577                         if (unit_type_from_string(optarg) >= 0) {
4578                                 arg_type = optarg;
4579                                 break;
4580                         }
4581                         if (unit_load_state_from_string(optarg) >= 0) {
4582                                 arg_load_state = optarg;
4583                                 break;
4584                         }
4585                         log_error("Unkown unit type or load state '%s'.",
4586                                   optarg);
4587                         log_info("Use -t help to see a list of allowed values.");
4588                         return -EINVAL;
4589                 case 'p': {
4590                         char **l;
4591
4592                         if (!(l = strv_append(arg_property, optarg)))
4593                                 return -ENOMEM;
4594
4595                         strv_free(arg_property);
4596                         arg_property = l;
4597
4598                         /* If the user asked for a particular
4599                          * property, show it to him, even if it is
4600                          * empty. */
4601                         arg_all = true;
4602                         break;
4603                 }
4604
4605                 case 'a':
4606                         arg_all = true;
4607                         break;
4608
4609                 case ARG_FAIL:
4610                         arg_job_mode = "fail";
4611                         break;
4612
4613                 case ARG_IGNORE_DEPENDENCIES:
4614                         arg_job_mode = "ignore-dependencies";
4615                         break;
4616
4617                 case ARG_USER:
4618                         arg_scope = UNIT_FILE_USER;
4619                         break;
4620
4621                 case ARG_SYSTEM:
4622                         arg_scope = UNIT_FILE_SYSTEM;
4623                         break;
4624
4625                 case ARG_GLOBAL:
4626                         arg_scope = UNIT_FILE_GLOBAL;
4627                         break;
4628
4629                 case ARG_NO_BLOCK:
4630                         arg_no_block = true;
4631                         break;
4632
4633                 case ARG_NO_LEGEND:
4634                         arg_no_legend = true;
4635                         break;
4636
4637                 case ARG_NO_PAGER:
4638                         arg_no_pager = true;
4639                         break;
4640
4641                 case ARG_NO_WALL:
4642                         arg_no_wall = true;
4643                         break;
4644
4645                 case ARG_ORDER:
4646                         arg_dot = DOT_ORDER;
4647                         break;
4648
4649                 case ARG_REQUIRE:
4650                         arg_dot = DOT_REQUIRE;
4651                         break;
4652
4653                 case ARG_ROOT:
4654                         arg_root = optarg;
4655                         break;
4656
4657                 case ARG_FULL:
4658                         arg_full = true;
4659                         break;
4660
4661                 case ARG_FAILED:
4662                         arg_failed = true;
4663                         break;
4664
4665                 case 'q':
4666                         arg_quiet = true;
4667                         break;
4668
4669                 case ARG_FORCE:
4670                         arg_force ++;
4671                         break;
4672
4673                 case 'f':
4674                         arg_force ++;
4675                         break;
4676
4677                 case ARG_NO_RELOAD:
4678                         arg_no_reload = true;
4679                         break;
4680
4681                 case ARG_KILL_WHO:
4682                         arg_kill_who = optarg;
4683                         break;
4684
4685                 case 's':
4686                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4687                                 log_error("Failed to parse signal string %s.", optarg);
4688                                 return -EINVAL;
4689                         }
4690                         break;
4691
4692                 case ARG_NO_ASK_PASSWORD:
4693                         arg_ask_password = false;
4694                         break;
4695
4696                 case 'P':
4697                         arg_transport = TRANSPORT_POLKIT;
4698                         break;
4699
4700                 case 'H':
4701                         arg_transport = TRANSPORT_SSH;
4702                         arg_host = optarg;
4703                         break;
4704
4705                 case ARG_RUNTIME:
4706                         arg_runtime = true;
4707                         break;
4708
4709                 case 'n':
4710                         if (safe_atou(optarg, &arg_lines) < 0) {
4711                                 log_error("Failed to parse lines '%s'", optarg);
4712                                 return -EINVAL;
4713                         }
4714                         break;
4715
4716                 case 'o':
4717                         arg_output = output_mode_from_string(optarg);
4718                         if (arg_output < 0) {
4719                                 log_error("Unknown output '%s'.", optarg);
4720                                 return -EINVAL;
4721                         }
4722                         break;
4723
4724                 case 'i':
4725                         arg_ignore_inhibitors = true;
4726                         break;
4727
4728                 case '?':
4729                         return -EINVAL;
4730
4731                 default:
4732                         log_error("Unknown option code '%c'.", c);
4733                         return -EINVAL;
4734                 }
4735         }
4736
4737         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4738                 log_error("Cannot access user instance remotely.");
4739                 return -EINVAL;
4740         }
4741
4742         return 1;
4743 }
4744
4745 static int halt_parse_argv(int argc, char *argv[]) {
4746
4747         enum {
4748                 ARG_HELP = 0x100,
4749                 ARG_HALT,
4750                 ARG_REBOOT,
4751                 ARG_NO_WALL
4752         };
4753
4754         static const struct option options[] = {
4755                 { "help",      no_argument,       NULL, ARG_HELP    },
4756                 { "halt",      no_argument,       NULL, ARG_HALT    },
4757                 { "poweroff",  no_argument,       NULL, 'p'         },
4758                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4759                 { "force",     no_argument,       NULL, 'f'         },
4760                 { "wtmp-only", no_argument,       NULL, 'w'         },
4761                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4762                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4763                 { NULL,        0,                 NULL, 0           }
4764         };
4765
4766         int c, runlevel;
4767
4768         assert(argc >= 0);
4769         assert(argv);
4770
4771         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4772                 if (runlevel == '0' || runlevel == '6')
4773                         arg_force = 2;
4774
4775         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4776                 switch (c) {
4777
4778                 case ARG_HELP:
4779                         halt_help();
4780                         return 0;
4781
4782                 case ARG_HALT:
4783                         arg_action = ACTION_HALT;
4784                         break;
4785
4786                 case 'p':
4787                         if (arg_action != ACTION_REBOOT)
4788                                 arg_action = ACTION_POWEROFF;
4789                         break;
4790
4791                 case ARG_REBOOT:
4792                         arg_action = ACTION_REBOOT;
4793                         break;
4794
4795                 case 'f':
4796                         arg_force = 2;
4797                         break;
4798
4799                 case 'w':
4800                         arg_dry = true;
4801                         break;
4802
4803                 case 'd':
4804                         arg_no_wtmp = true;
4805                         break;
4806
4807                 case ARG_NO_WALL:
4808                         arg_no_wall = true;
4809                         break;
4810
4811                 case 'i':
4812                 case 'h':
4813                 case 'n':
4814                         /* Compatibility nops */
4815                         break;
4816
4817                 case '?':
4818                         return -EINVAL;
4819
4820                 default:
4821                         log_error("Unknown option code '%c'.", c);
4822                         return -EINVAL;
4823                 }
4824         }
4825
4826         if (optind < argc) {
4827                 log_error("Too many arguments.");
4828                 return -EINVAL;
4829         }
4830
4831         return 1;
4832 }
4833
4834 static int parse_time_spec(const char *t, usec_t *_u) {
4835         assert(t);
4836         assert(_u);
4837
4838         if (streq(t, "now"))
4839                 *_u = 0;
4840         else if (!strchr(t, ':')) {
4841                 uint64_t u;
4842
4843                 if (safe_atou64(t, &u) < 0)
4844                         return -EINVAL;
4845
4846                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4847         } else {
4848                 char *e = NULL;
4849                 long hour, minute;
4850                 struct tm tm;
4851                 time_t s;
4852                 usec_t n;
4853
4854                 errno = 0;
4855                 hour = strtol(t, &e, 10);
4856                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4857                         return -EINVAL;
4858
4859                 minute = strtol(e+1, &e, 10);
4860                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4861                         return -EINVAL;
4862
4863                 n = now(CLOCK_REALTIME);
4864                 s = (time_t) (n / USEC_PER_SEC);
4865
4866                 zero(tm);
4867                 assert_se(localtime_r(&s, &tm));
4868
4869                 tm.tm_hour = (int) hour;
4870                 tm.tm_min = (int) minute;
4871                 tm.tm_sec = 0;
4872
4873                 assert_se(s = mktime(&tm));
4874
4875                 *_u = (usec_t) s * USEC_PER_SEC;
4876
4877                 while (*_u <= n)
4878                         *_u += USEC_PER_DAY;
4879         }
4880
4881         return 0;
4882 }
4883
4884 static int shutdown_parse_argv(int argc, char *argv[]) {
4885
4886         enum {
4887                 ARG_HELP = 0x100,
4888                 ARG_NO_WALL
4889         };
4890
4891         static const struct option options[] = {
4892                 { "help",      no_argument,       NULL, ARG_HELP    },
4893                 { "halt",      no_argument,       NULL, 'H'         },
4894                 { "poweroff",  no_argument,       NULL, 'P'         },
4895                 { "reboot",    no_argument,       NULL, 'r'         },
4896                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4897                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4898                 { NULL,        0,                 NULL, 0           }
4899         };
4900
4901         int c, r;
4902
4903         assert(argc >= 0);
4904         assert(argv);
4905
4906         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4907                 switch (c) {
4908
4909                 case ARG_HELP:
4910                         shutdown_help();
4911                         return 0;
4912
4913                 case 'H':
4914                         arg_action = ACTION_HALT;
4915                         break;
4916
4917                 case 'P':
4918                         arg_action = ACTION_POWEROFF;
4919                         break;
4920
4921                 case 'r':
4922                         if (kexec_loaded())
4923                                 arg_action = ACTION_KEXEC;
4924                         else
4925                                 arg_action = ACTION_REBOOT;
4926                         break;
4927
4928                 case 'K':
4929                         arg_action = ACTION_KEXEC;
4930                         break;
4931
4932                 case 'h':
4933                         if (arg_action != ACTION_HALT)
4934                                 arg_action = ACTION_POWEROFF;
4935                         break;
4936
4937                 case 'k':
4938                         arg_dry = true;
4939                         break;
4940
4941                 case ARG_NO_WALL:
4942                         arg_no_wall = true;
4943                         break;
4944
4945                 case 't':
4946                 case 'a':
4947                         /* Compatibility nops */
4948                         break;
4949
4950                 case 'c':
4951                         arg_action = ACTION_CANCEL_SHUTDOWN;
4952                         break;
4953
4954                 case '?':
4955                         return -EINVAL;
4956
4957                 default:
4958                         log_error("Unknown option code '%c'.", c);
4959                         return -EINVAL;
4960                 }
4961         }
4962
4963         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4964                 r = parse_time_spec(argv[optind], &arg_when);
4965                 if (r < 0) {
4966                         log_error("Failed to parse time specification: %s", argv[optind]);
4967                         return r;
4968                 }
4969         } else
4970                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4971
4972         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4973                 /* No time argument for shutdown cancel */
4974                 arg_wall = argv + optind;
4975         else if (argc > optind + 1)
4976                 /* We skip the time argument */
4977                 arg_wall = argv + optind + 1;
4978
4979         optind = argc;
4980
4981         return 1;
4982 }
4983
4984 static int telinit_parse_argv(int argc, char *argv[]) {
4985
4986         enum {
4987                 ARG_HELP = 0x100,
4988                 ARG_NO_WALL
4989         };
4990
4991         static const struct option options[] = {
4992                 { "help",      no_argument,       NULL, ARG_HELP    },
4993                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4994                 { NULL,        0,                 NULL, 0           }
4995         };
4996
4997         static const struct {
4998                 char from;
4999                 enum action to;
5000         } table[] = {
5001                 { '0', ACTION_POWEROFF },
5002                 { '6', ACTION_REBOOT },
5003                 { '1', ACTION_RESCUE },
5004                 { '2', ACTION_RUNLEVEL2 },
5005                 { '3', ACTION_RUNLEVEL3 },
5006                 { '4', ACTION_RUNLEVEL4 },
5007                 { '5', ACTION_RUNLEVEL5 },
5008                 { 's', ACTION_RESCUE },
5009                 { 'S', ACTION_RESCUE },
5010                 { 'q', ACTION_RELOAD },
5011                 { 'Q', ACTION_RELOAD },
5012                 { 'u', ACTION_REEXEC },
5013                 { 'U', ACTION_REEXEC }
5014         };
5015
5016         unsigned i;
5017         int c;
5018
5019         assert(argc >= 0);
5020         assert(argv);
5021
5022         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5023                 switch (c) {
5024
5025                 case ARG_HELP:
5026                         telinit_help();
5027                         return 0;
5028
5029                 case ARG_NO_WALL:
5030                         arg_no_wall = true;
5031                         break;
5032
5033                 case '?':
5034                         return -EINVAL;
5035
5036                 default:
5037                         log_error("Unknown option code '%c'.", c);
5038                         return -EINVAL;
5039                 }
5040         }
5041
5042         if (optind >= argc) {
5043                 telinit_help();
5044                 return -EINVAL;
5045         }
5046
5047         if (optind + 1 < argc) {
5048                 log_error("Too many arguments.");
5049                 return -EINVAL;
5050         }
5051
5052         if (strlen(argv[optind]) != 1) {
5053                 log_error("Expected single character argument.");
5054                 return -EINVAL;
5055         }
5056
5057         for (i = 0; i < ELEMENTSOF(table); i++)
5058                 if (table[i].from == argv[optind][0])
5059                         break;
5060
5061         if (i >= ELEMENTSOF(table)) {
5062                 log_error("Unknown command '%s'.", argv[optind]);
5063                 return -EINVAL;
5064         }
5065
5066         arg_action = table[i].to;
5067
5068         optind ++;
5069
5070         return 1;
5071 }
5072
5073 static int runlevel_parse_argv(int argc, char *argv[]) {
5074
5075         enum {
5076                 ARG_HELP = 0x100,
5077         };
5078
5079         static const struct option options[] = {
5080                 { "help",      no_argument,       NULL, ARG_HELP    },
5081                 { NULL,        0,                 NULL, 0           }
5082         };
5083
5084         int c;
5085
5086         assert(argc >= 0);
5087         assert(argv);
5088
5089         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5090                 switch (c) {
5091
5092                 case ARG_HELP:
5093                         runlevel_help();
5094                         return 0;
5095
5096                 case '?':
5097                         return -EINVAL;
5098
5099                 default:
5100                         log_error("Unknown option code '%c'.", c);
5101                         return -EINVAL;
5102                 }
5103         }
5104
5105         if (optind < argc) {
5106                 log_error("Too many arguments.");
5107                 return -EINVAL;
5108         }
5109
5110         return 1;
5111 }
5112
5113 static int parse_argv(int argc, char *argv[]) {
5114         assert(argc >= 0);
5115         assert(argv);
5116
5117         if (program_invocation_short_name) {
5118
5119                 if (strstr(program_invocation_short_name, "halt")) {
5120                         arg_action = ACTION_HALT;
5121                         return halt_parse_argv(argc, argv);
5122                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5123                         arg_action = ACTION_POWEROFF;
5124                         return halt_parse_argv(argc, argv);
5125                 } else if (strstr(program_invocation_short_name, "reboot")) {
5126                         if (kexec_loaded())
5127                                 arg_action = ACTION_KEXEC;
5128                         else
5129                                 arg_action = ACTION_REBOOT;
5130                         return halt_parse_argv(argc, argv);
5131                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5132                         arg_action = ACTION_POWEROFF;
5133                         return shutdown_parse_argv(argc, argv);
5134                 } else if (strstr(program_invocation_short_name, "init")) {
5135
5136                         if (sd_booted() > 0) {
5137                                 arg_action = ACTION_INVALID;
5138                                 return telinit_parse_argv(argc, argv);
5139                         } else {
5140                                 /* Hmm, so some other init system is
5141                                  * running, we need to forward this
5142                                  * request to it. For now we simply
5143                                  * guess that it is Upstart. */
5144
5145                                 execv("/lib/upstart/telinit", argv);
5146
5147                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5148                                 return -EIO;
5149                         }
5150
5151                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5152                         arg_action = ACTION_RUNLEVEL;
5153                         return runlevel_parse_argv(argc, argv);
5154                 }
5155         }
5156
5157         arg_action = ACTION_SYSTEMCTL;
5158         return systemctl_parse_argv(argc, argv);
5159 }
5160
5161 static int action_to_runlevel(void) {
5162
5163         static const char table[_ACTION_MAX] = {
5164                 [ACTION_HALT] =      '0',
5165                 [ACTION_POWEROFF] =  '0',
5166                 [ACTION_REBOOT] =    '6',
5167                 [ACTION_RUNLEVEL2] = '2',
5168                 [ACTION_RUNLEVEL3] = '3',
5169                 [ACTION_RUNLEVEL4] = '4',
5170                 [ACTION_RUNLEVEL5] = '5',
5171                 [ACTION_RESCUE] =    '1'
5172         };
5173
5174         assert(arg_action < _ACTION_MAX);
5175
5176         return table[arg_action];
5177 }
5178
5179 static int talk_upstart(void) {
5180         DBusMessage *m = NULL, *reply = NULL;
5181         DBusError error;
5182         int previous, rl, r;
5183         char
5184                 env1_buf[] = "RUNLEVEL=X",
5185                 env2_buf[] = "PREVLEVEL=X";
5186         char *env1 = env1_buf, *env2 = env2_buf;
5187         const char *emit = "runlevel";
5188         dbus_bool_t b_false = FALSE;
5189         DBusMessageIter iter, sub;
5190         DBusConnection *bus;
5191
5192         dbus_error_init(&error);
5193
5194         if (!(rl = action_to_runlevel()))
5195                 return 0;
5196
5197         if (utmp_get_runlevel(&previous, NULL) < 0)
5198                 previous = 'N';
5199
5200         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5201                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5202                         r = 0;
5203                         goto finish;
5204                 }
5205
5206                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5207                 r = -EIO;
5208                 goto finish;
5209         }
5210
5211         if ((r = bus_check_peercred(bus)) < 0) {
5212                 log_error("Failed to verify owner of bus.");
5213                 goto finish;
5214         }
5215
5216         if (!(m = dbus_message_new_method_call(
5217                               "com.ubuntu.Upstart",
5218                               "/com/ubuntu/Upstart",
5219                               "com.ubuntu.Upstart0_6",
5220                               "EmitEvent"))) {
5221
5222                 log_error("Could not allocate message.");
5223                 r = -ENOMEM;
5224                 goto finish;
5225         }
5226
5227         dbus_message_iter_init_append(m, &iter);
5228
5229         env1_buf[sizeof(env1_buf)-2] = rl;
5230         env2_buf[sizeof(env2_buf)-2] = previous;
5231
5232         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5233             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5234             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5235             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5236             !dbus_message_iter_close_container(&iter, &sub) ||
5237             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5238                 log_error("Could not append arguments to message.");
5239                 r = -ENOMEM;
5240                 goto finish;
5241         }
5242
5243         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5244
5245                 if (bus_error_is_no_service(&error)) {
5246                         r = -EADDRNOTAVAIL;
5247                         goto finish;
5248                 }
5249
5250                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5251                 r = -EIO;
5252                 goto finish;
5253         }
5254
5255         r = 1;
5256
5257 finish:
5258         if (m)
5259                 dbus_message_unref(m);
5260
5261         if (reply)
5262                 dbus_message_unref(reply);
5263
5264         if (bus) {
5265                 dbus_connection_flush(bus);
5266                 dbus_connection_close(bus);
5267                 dbus_connection_unref(bus);
5268         }
5269
5270         dbus_error_free(&error);
5271
5272         return r;
5273 }
5274
5275 static int talk_initctl(void) {
5276         struct init_request request;
5277         int r, fd;
5278         char rl;
5279
5280         if (!(rl = action_to_runlevel()))
5281                 return 0;
5282
5283         zero(request);
5284         request.magic = INIT_MAGIC;
5285         request.sleeptime = 0;
5286         request.cmd = INIT_CMD_RUNLVL;
5287         request.runlevel = rl;
5288
5289         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5290
5291                 if (errno == ENOENT)
5292                         return 0;
5293
5294                 log_error("Failed to open "INIT_FIFO": %m");
5295                 return -errno;
5296         }
5297
5298         errno = 0;
5299         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5300         close_nointr_nofail(fd);
5301
5302         if (r < 0) {
5303                 log_error("Failed to write to "INIT_FIFO": %m");
5304                 return errno ? -errno : -EIO;
5305         }
5306
5307         return 1;
5308 }
5309
5310 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5311
5312         static const struct {
5313                 const char* verb;
5314                 const enum {
5315                         MORE,
5316                         LESS,
5317                         EQUAL
5318                 } argc_cmp;
5319                 const int argc;
5320                 int (* const dispatch)(DBusConnection *bus, char **args);
5321         } verbs[] = {
5322                 { "list-units",            LESS,  1, list_units        },
5323                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5324                 { "list-jobs",             EQUAL, 1, list_jobs         },
5325                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5326                 { "load",                  MORE,  2, load_unit         },
5327                 { "cancel",                MORE,  2, cancel_job        },
5328                 { "start",                 MORE,  2, start_unit        },
5329                 { "stop",                  MORE,  2, start_unit        },
5330                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5331                 { "reload",                MORE,  2, start_unit        },
5332                 { "restart",               MORE,  2, start_unit        },
5333                 { "try-restart",           MORE,  2, start_unit        },
5334                 { "reload-or-restart",     MORE,  2, start_unit        },
5335                 { "reload-or-try-restart", MORE,  2, start_unit        },
5336                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5337                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5338                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5339                 { "isolate",               EQUAL, 2, start_unit        },
5340                 { "set-cgroup",            MORE,  2, set_cgroup        },
5341                 { "unset-cgroup",          MORE,  2, set_cgroup        },
5342                 { "get-cgroup-attr",       MORE,  2, get_cgroup_attr   },
5343                 { "set-cgroup-attr",       MORE,  2, set_cgroup_attr   },
5344                 { "unset-cgroup-attr",     MORE,  2, set_cgroup        },
5345                 { "kill",                  MORE,  2, kill_unit         },
5346                 { "is-active",             MORE,  2, check_unit_active },
5347                 { "check",                 MORE,  2, check_unit_active },
5348                 { "is-failed",             MORE,  2, check_unit_failed },
5349                 { "show",                  MORE,  1, show              },
5350                 { "status",                MORE,  2, show              },
5351                 { "help",                  MORE,  2, show              },
5352                 { "dump",                  EQUAL, 1, dump              },
5353                 { "dot",                   EQUAL, 1, dot               },
5354                 { "snapshot",              LESS,  2, snapshot          },
5355                 { "delete",                MORE,  2, delete_snapshot   },
5356                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5357                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5358                 { "show-environment",      EQUAL, 1, show_enviroment   },
5359                 { "set-environment",       MORE,  2, set_environment   },
5360                 { "unset-environment",     MORE,  2, set_environment   },
5361                 { "halt",                  EQUAL, 1, start_special     },
5362                 { "poweroff",              EQUAL, 1, start_special     },
5363                 { "reboot",                EQUAL, 1, start_special     },
5364                 { "kexec",                 EQUAL, 1, start_special     },
5365                 { "suspend",               EQUAL, 1, start_special     },
5366                 { "hibernate",             EQUAL, 1, start_special     },
5367                 { "hybrid-sleep",          EQUAL, 1, start_special     },
5368                 { "default",               EQUAL, 1, start_special     },
5369                 { "rescue",                EQUAL, 1, start_special     },
5370                 { "emergency",             EQUAL, 1, start_special     },
5371                 { "exit",                  EQUAL, 1, start_special     },
5372                 { "reset-failed",          MORE,  1, reset_failed      },
5373                 { "enable",                MORE,  2, enable_unit       },
5374                 { "disable",               MORE,  2, enable_unit       },
5375                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5376                 { "reenable",              MORE,  2, enable_unit       },
5377                 { "preset",                MORE,  2, enable_unit       },
5378                 { "mask",                  MORE,  2, enable_unit       },
5379                 { "unmask",                MORE,  2, enable_unit       },
5380                 { "link",                  MORE,  2, enable_unit       },
5381                 { "switch-root",           MORE,  2, switch_root       },
5382                 { "list-dependencies",     LESS,  2, list_dependencies },
5383         };
5384
5385         int left;
5386         unsigned i;
5387
5388         assert(argc >= 0);
5389         assert(argv);
5390         assert(error);
5391
5392         left = argc - optind;
5393
5394         if (left <= 0)
5395                 /* Special rule: no arguments means "list-units" */
5396                 i = 0;
5397         else {
5398                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5399                         log_error("This command expects one or more "
5400                                   "unit names. Did you mean --help?");
5401                         return -EINVAL;
5402                 }
5403
5404                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5405                         if (streq(argv[optind], verbs[i].verb))
5406                                 break;
5407
5408                 if (i >= ELEMENTSOF(verbs)) {
5409                         log_error("Unknown operation '%s'.", argv[optind]);
5410                         return -EINVAL;
5411                 }
5412         }
5413
5414         switch (verbs[i].argc_cmp) {
5415
5416         case EQUAL:
5417                 if (left != verbs[i].argc) {
5418                         log_error("Invalid number of arguments.");
5419                         return -EINVAL;
5420                 }
5421
5422                 break;
5423
5424         case MORE:
5425                 if (left < verbs[i].argc) {
5426                         log_error("Too few arguments.");
5427                         return -EINVAL;
5428                 }
5429
5430                 break;
5431
5432         case LESS:
5433                 if (left > verbs[i].argc) {
5434                         log_error("Too many arguments.");
5435                         return -EINVAL;
5436                 }
5437
5438                 break;
5439
5440         default:
5441                 assert_not_reached("Unknown comparison operator.");
5442         }
5443
5444         /* Require a bus connection for all operations but
5445          * enable/disable */
5446         if (!streq(verbs[i].verb, "enable") &&
5447             !streq(verbs[i].verb, "disable") &&
5448             !streq(verbs[i].verb, "is-enabled") &&
5449             !streq(verbs[i].verb, "list-unit-files") &&
5450             !streq(verbs[i].verb, "reenable") &&
5451             !streq(verbs[i].verb, "preset") &&
5452             !streq(verbs[i].verb, "mask") &&
5453             !streq(verbs[i].verb, "unmask") &&
5454             !streq(verbs[i].verb, "link")) {
5455
5456                 if (running_in_chroot() > 0) {
5457                         log_info("Running in chroot, ignoring request.");
5458                         return 0;
5459                 }
5460
5461                 if (((!streq(verbs[i].verb, "reboot") &&
5462                       !streq(verbs[i].verb, "halt") &&
5463                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !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         } else {
5470
5471                 if (!bus && !avoid_bus()) {
5472                         log_error("Failed to get D-Bus connection: %s",
5473                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5474                         return -EIO;
5475                 }
5476         }
5477
5478         return verbs[i].dispatch(bus, argv + optind);
5479 }
5480
5481 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5482         int fd;
5483         struct msghdr msghdr;
5484         struct iovec iovec[2];
5485         union sockaddr_union sockaddr;
5486         struct sd_shutdown_command c;
5487
5488         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5489         if (fd < 0)
5490                 return -errno;
5491
5492         zero(c);
5493         c.usec = t;
5494         c.mode = mode;
5495         c.dry_run = dry_run;
5496         c.warn_wall = warn;
5497
5498         zero(sockaddr);
5499         sockaddr.sa.sa_family = AF_UNIX;
5500         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5501
5502         zero(msghdr);
5503         msghdr.msg_name = &sockaddr;
5504         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5505
5506         zero(iovec);
5507         iovec[0].iov_base = (char*) &c;
5508         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5509
5510         if (isempty(message))
5511                 msghdr.msg_iovlen = 1;
5512         else {
5513                 iovec[1].iov_base = (char*) message;
5514                 iovec[1].iov_len = strlen(message);
5515                 msghdr.msg_iovlen = 2;
5516         }
5517         msghdr.msg_iov = iovec;
5518
5519         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5520                 close_nointr_nofail(fd);
5521                 return -errno;
5522         }
5523
5524         close_nointr_nofail(fd);
5525         return 0;
5526 }
5527
5528 static int reload_with_fallback(DBusConnection *bus) {
5529
5530         if (bus) {
5531                 /* First, try systemd via D-Bus. */
5532                 if (daemon_reload(bus, NULL) >= 0)
5533                         return 0;
5534         }
5535
5536         /* Nothing else worked, so let's try signals */
5537         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5538
5539         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5540                 log_error("kill() failed: %m");
5541                 return -errno;
5542         }
5543
5544         return 0;
5545 }
5546
5547 static int start_with_fallback(DBusConnection *bus) {
5548
5549         if (bus) {
5550                 /* First, try systemd via D-Bus. */
5551                 if (start_unit(bus, NULL) >= 0)
5552                         goto done;
5553         }
5554
5555         /* Hmm, talking to systemd via D-Bus didn't work. Then
5556          * let's try to talk to Upstart via D-Bus. */
5557         if (talk_upstart() > 0)
5558                 goto done;
5559
5560         /* Nothing else worked, so let's try
5561          * /dev/initctl */
5562         if (talk_initctl() > 0)
5563                 goto done;
5564
5565         log_error("Failed to talk to init daemon.");
5566         return -EIO;
5567
5568 done:
5569         warn_wall(arg_action);
5570         return 0;
5571 }
5572
5573 static _noreturn_ void halt_now(enum action a) {
5574
5575        /* Make sure C-A-D is handled by the kernel from this
5576          * point on... */
5577         reboot(RB_ENABLE_CAD);
5578
5579         switch (a) {
5580
5581         case ACTION_HALT:
5582                 log_info("Halting.");
5583                 reboot(RB_HALT_SYSTEM);
5584                 break;
5585
5586         case ACTION_POWEROFF:
5587                 log_info("Powering off.");
5588                 reboot(RB_POWER_OFF);
5589                 break;
5590
5591         case ACTION_REBOOT:
5592                 log_info("Rebooting.");
5593                 reboot(RB_AUTOBOOT);
5594                 break;
5595
5596         default:
5597                 assert_not_reached("Unknown halt action.");
5598         }
5599
5600         assert_not_reached("Uh? This shouldn't happen.");
5601 }
5602
5603 static int halt_main(DBusConnection *bus) {
5604         int r;
5605
5606         r = check_inhibitors(bus, arg_action);
5607         if (r < 0)
5608                 return r;
5609
5610         if (geteuid() != 0) {
5611                 /* Try logind if we are a normal user and no special
5612                  * mode applies. Maybe PolicyKit allows us to shutdown
5613                  * the machine. */
5614
5615                 if (arg_when <= 0 &&
5616                     !arg_dry &&
5617                     arg_force <= 0 &&
5618                     (arg_action == ACTION_POWEROFF ||
5619                      arg_action == ACTION_REBOOT)) {
5620                         r = reboot_with_logind(bus, arg_action);
5621                         if (r >= 0)
5622                                 return r;
5623                 }
5624
5625                 log_error("Must be root.");
5626                 return -EPERM;
5627         }
5628
5629         if (arg_when > 0) {
5630                 char *m;
5631
5632                 m = strv_join(arg_wall, " ");
5633                 r = send_shutdownd(arg_when,
5634                                    arg_action == ACTION_HALT     ? 'H' :
5635                                    arg_action == ACTION_POWEROFF ? 'P' :
5636                                    arg_action == ACTION_KEXEC    ? 'K' :
5637                                                                    'r',
5638                                    arg_dry,
5639                                    !arg_no_wall,
5640                                    m);
5641                 free(m);
5642
5643                 if (r < 0)
5644                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5645                 else {
5646                         char date[FORMAT_TIMESTAMP_MAX];
5647
5648                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5649                                  format_timestamp(date, sizeof(date), arg_when));
5650                         return 0;
5651                 }
5652         }
5653
5654         if (!arg_dry && !arg_force)
5655                 return start_with_fallback(bus);
5656
5657         if (!arg_no_wtmp) {
5658                 if (sd_booted() > 0)
5659                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5660                 else {
5661                         r = utmp_put_shutdown();
5662                         if (r < 0)
5663                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5664                 }
5665         }
5666
5667         if (arg_dry)
5668                 return 0;
5669
5670         halt_now(arg_action);
5671         /* We should never reach this. */
5672         return -ENOSYS;
5673 }
5674
5675 static int runlevel_main(void) {
5676         int r, runlevel, previous;
5677
5678         r = utmp_get_runlevel(&runlevel, &previous);
5679         if (r < 0) {
5680                 puts("unknown");
5681                 return r;
5682         }
5683
5684         printf("%c %c\n",
5685                previous <= 0 ? 'N' : previous,
5686                runlevel <= 0 ? 'N' : runlevel);
5687
5688         return 0;
5689 }
5690
5691 int main(int argc, char*argv[]) {
5692         int r, retval = EXIT_FAILURE;
5693         DBusConnection *bus = NULL;
5694         DBusError error;
5695
5696         dbus_error_init(&error);
5697
5698         setlocale(LC_ALL, "");
5699         log_parse_environment();
5700         log_open();
5701
5702         r = parse_argv(argc, argv);
5703         if (r < 0)
5704                 goto finish;
5705         else if (r == 0) {
5706                 retval = EXIT_SUCCESS;
5707                 goto finish;
5708         }
5709
5710         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5711          * let's shortcut this */
5712         if (arg_action == ACTION_RUNLEVEL) {
5713                 r = runlevel_main();
5714                 retval = r < 0 ? EXIT_FAILURE : r;
5715                 goto finish;
5716         }
5717
5718         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5719                 log_info("Running in chroot, ignoring request.");
5720                 retval = 0;
5721                 goto finish;
5722         }
5723
5724         if (!avoid_bus()) {
5725                 if (arg_transport == TRANSPORT_NORMAL)
5726                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5727                 else if (arg_transport == TRANSPORT_POLKIT) {
5728                         bus_connect_system_polkit(&bus, &error);
5729                         private_bus = false;
5730                 } else if (arg_transport == TRANSPORT_SSH) {
5731                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5732                         private_bus = false;
5733                 } else
5734                         assert_not_reached("Uh, invalid transport...");
5735         }
5736
5737         switch (arg_action) {
5738
5739         case ACTION_SYSTEMCTL:
5740                 r = systemctl_main(bus, argc, argv, &error);
5741                 break;
5742
5743         case ACTION_HALT:
5744         case ACTION_POWEROFF:
5745         case ACTION_REBOOT:
5746         case ACTION_KEXEC:
5747                 r = halt_main(bus);
5748                 break;
5749
5750         case ACTION_RUNLEVEL2:
5751         case ACTION_RUNLEVEL3:
5752         case ACTION_RUNLEVEL4:
5753         case ACTION_RUNLEVEL5:
5754         case ACTION_RESCUE:
5755         case ACTION_EMERGENCY:
5756         case ACTION_DEFAULT:
5757                 r = start_with_fallback(bus);
5758                 break;
5759
5760         case ACTION_RELOAD:
5761         case ACTION_REEXEC:
5762                 r = reload_with_fallback(bus);
5763                 break;
5764
5765         case ACTION_CANCEL_SHUTDOWN: {
5766                 char *m = NULL;
5767
5768                 if (arg_wall) {
5769                         m = strv_join(arg_wall, " ");
5770                         if (!m) {
5771                                 retval = EXIT_FAILURE;
5772                                 goto finish;
5773                         }
5774                 }
5775                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5776                 if (r < 0)
5777                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5778                 free(m);
5779                 break;
5780         }
5781
5782         case ACTION_INVALID:
5783         case ACTION_RUNLEVEL:
5784         default:
5785                 assert_not_reached("Unknown action");
5786         }
5787
5788         retval = r < 0 ? EXIT_FAILURE : r;
5789
5790 finish:
5791         if (bus) {
5792                 dbus_connection_flush(bus);
5793                 dbus_connection_close(bus);
5794                 dbus_connection_unref(bus);
5795         }
5796
5797         dbus_error_free(&error);
5798
5799         dbus_shutdown();
5800
5801         strv_free(arg_property);
5802
5803         pager_close();
5804         ask_password_agent_close();
5805         polkit_agent_close();
5806
5807         return retval;
5808 }