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