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