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