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