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