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