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