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