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