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