chiark / gitweb /
a7c2eef5d4adabe74cff97cead0241ca3404c11c
[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         const char *load_error;
2229         const char *result;
2230
2231         usec_t inactive_exit_timestamp;
2232         usec_t inactive_exit_timestamp_monotonic;
2233         usec_t active_enter_timestamp;
2234         usec_t active_exit_timestamp;
2235         usec_t inactive_enter_timestamp;
2236
2237         bool need_daemon_reload;
2238
2239         /* Service */
2240         pid_t main_pid;
2241         pid_t control_pid;
2242         const char *status_text;
2243         bool running:1;
2244
2245         usec_t start_timestamp;
2246         usec_t exit_timestamp;
2247
2248         int exit_code, exit_status;
2249
2250         usec_t condition_timestamp;
2251         bool condition_result;
2252
2253         /* Socket */
2254         unsigned n_accepted;
2255         unsigned n_connections;
2256         bool accept;
2257
2258         /* Pairs of type, path */
2259         char **listen;
2260
2261         /* Device */
2262         const char *sysfs_path;
2263
2264         /* Mount, Automount */
2265         const char *where;
2266
2267         /* Swap */
2268         const char *what;
2269
2270         LIST_HEAD(ExecStatusInfo, exec);
2271 } UnitStatusInfo;
2272
2273 static void print_status_info(UnitStatusInfo *i) {
2274         ExecStatusInfo *p;
2275         const char *on, *off, *ss;
2276         usec_t timestamp;
2277         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2278         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2279         const char *path;
2280         int flags =
2281                 arg_all * OUTPUT_SHOW_ALL |
2282                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2283                 on_tty() * OUTPUT_COLOR |
2284                 !arg_quiet * OUTPUT_WARN_CUTOFF |
2285                 arg_full * OUTPUT_FULL_WIDTH;
2286         int maxlen = 8; /* a value that'll suffice most of the time */
2287         char **t, **t2;
2288
2289         assert(i);
2290
2291         STRV_FOREACH_PAIR(t, t2, i->listen)
2292                 maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
2293         if (i->accept)
2294                 maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
2295         if (i->main_pid > 0)
2296                 maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
2297         else if (i->control_pid > 0)
2298                 maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
2299
2300         /* This shows pretty information about a unit. See
2301          * print_property() for a low-level property printer */
2302
2303         printf("%s", strna(i->id));
2304
2305         if (i->description && !streq_ptr(i->id, i->description))
2306                 printf(" - %s", i->description);
2307
2308         printf("\n");
2309
2310         if (i->following)
2311                 printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
2312
2313         if (streq_ptr(i->load_state, "error")) {
2314                 on = ansi_highlight_red(true);
2315                 off = ansi_highlight_red(false);
2316         } else
2317                 on = off = "";
2318
2319         path = i->source_path ? i->source_path : i->fragment_path;
2320
2321         if (i->load_error)
2322                 printf(" %*s: %s%s%s (Reason: %s)\n",
2323                        maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
2324         else if (path && i->unit_file_state)
2325                 printf(" %*s: %s%s%s (%s; %s)\n",
2326                        maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
2327         else if (path)
2328                 printf(" %*s: %s%s%s (%s)\n",
2329                        maxlen, "Loaded", on, strna(i->load_state), off, path);
2330         else
2331                 printf(" %*s: %s%s%s\n",
2332                        maxlen, "Loaded", on, strna(i->load_state), off);
2333
2334         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2335
2336         if (streq_ptr(i->active_state, "failed")) {
2337                 on = ansi_highlight_red(true);
2338                 off = ansi_highlight_red(false);
2339         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2340                 on = ansi_highlight_green(true);
2341                 off = ansi_highlight_green(false);
2342         } else
2343                 on = off = "";
2344
2345         if (ss)
2346                 printf(" %*s: %s%s (%s)%s",
2347                        maxlen, "Active",  on, strna(i->active_state), ss, off);
2348         else
2349                 printf(" %*s: %s%s%s",
2350                        maxlen, "Active", on, strna(i->active_state), off);
2351
2352         if (!isempty(i->result) && !streq(i->result, "success"))
2353                 printf(" (Result: %s)", i->result);
2354
2355         timestamp = (streq_ptr(i->active_state, "active")      ||
2356                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2357                     (streq_ptr(i->active_state, "inactive")    ||
2358                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2359                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2360                                                                   i->active_exit_timestamp;
2361
2362         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2363         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2364
2365         if (s1)
2366                 printf(" since %s; %s\n", s2, s1);
2367         else if (s2)
2368                 printf(" since %s\n", s2);
2369         else
2370                 printf("\n");
2371
2372         if (!i->condition_result && i->condition_timestamp > 0) {
2373                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2374                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2375
2376                 if (s1)
2377                         printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
2378                 else if (s2)
2379                         printf(" %*s start condition failed at %s\n", maxlen, "", s2);
2380         }
2381
2382         if (i->sysfs_path)
2383                 printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
2384         if (i->where)
2385                 printf(" %*s: %s\n", maxlen, "Where", i->where);
2386         if (i->what)
2387                 printf(" %*s: %s\n", maxlen, "What", i->what);
2388
2389         STRV_FOREACH(t, i->documentation)
2390                 printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
2391
2392         STRV_FOREACH_PAIR(t, t2, i->listen)
2393                 printf(" %*s%s: %s\n", maxlen - (int)strlen(*t), "Listen", *t, *t2);
2394
2395         if (i->accept)
2396                 printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
2397
2398         LIST_FOREACH(exec, p, i->exec) {
2399                 _cleanup_free_ char *argv = NULL;
2400                 bool good;
2401
2402                 /* Only show exited processes here */
2403                 if (p->code == 0)
2404                         continue;
2405
2406                 argv = strv_join(p->argv, " ");
2407                 printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
2408
2409                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2410                 if (!good) {
2411                         on = ansi_highlight_red(true);
2412                         off = ansi_highlight_red(false);
2413                 } else
2414                         on = off = "";
2415
2416                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2417
2418                 if (p->code == CLD_EXITED) {
2419                         const char *c;
2420
2421                         printf("status=%i", p->status);
2422
2423                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2424                         if (c)
2425                                 printf("/%s", c);
2426
2427                 } else
2428                         printf("signal=%s", signal_to_string(p->status));
2429
2430                 printf(")%s\n", off);
2431
2432                 if (i->main_pid == p->pid &&
2433                     i->start_timestamp == p->start_timestamp &&
2434                     i->exit_timestamp == p->start_timestamp)
2435                         /* Let's not show this twice */
2436                         i->main_pid = 0;
2437
2438                 if (p->pid == i->control_pid)
2439                         i->control_pid = 0;
2440         }
2441
2442         if (i->main_pid > 0 || i->control_pid > 0) {
2443                 if (i->main_pid > 0) {
2444                         printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
2445
2446                         if (i->running) {
2447                                 _cleanup_free_ char *comm = NULL;
2448                                 get_process_comm(i->main_pid, &comm);
2449                                 if (comm)
2450                                         printf(" (%s)", comm);
2451                         } else if (i->exit_code > 0) {
2452                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2453
2454                                 if (i->exit_code == CLD_EXITED) {
2455                                         const char *c;
2456
2457                                         printf("status=%i", i->exit_status);
2458
2459                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2460                                         if (c)
2461                                                 printf("/%s", c);
2462
2463                                 } else
2464                                         printf("signal=%s", signal_to_string(i->exit_status));
2465                                 printf(")");
2466                         }
2467
2468                         if (i->control_pid > 0)
2469                                 printf(";");
2470                 }
2471
2472                 if (i->control_pid > 0) {
2473                         _cleanup_free_ char *c = NULL;
2474
2475                         printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
2476
2477                         get_process_comm(i->control_pid, &c);
2478                         if (c)
2479                                 printf(" (%s)", c);
2480                 }
2481
2482                 printf("\n");
2483         }
2484
2485         if (i->status_text)
2486                 printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
2487
2488         if (i->default_control_group &&
2489             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2490                 unsigned c;
2491
2492                 printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
2493
2494                 if (arg_transport != TRANSPORT_SSH) {
2495                         unsigned k = 0;
2496                         pid_t extra[2];
2497                         char prefix[maxlen + 4];
2498                         memset(prefix, ' ', sizeof(prefix) - 1);
2499                         prefix[sizeof(prefix) - 1] = '\0';
2500
2501                         c = columns();
2502                         if (c > sizeof(prefix) - 1)
2503                                 c -= sizeof(prefix) - 1;
2504                         else
2505                                 c = 0;
2506
2507                         if (i->main_pid > 0)
2508                                 extra[k++] = i->main_pid;
2509
2510                         if (i->control_pid > 0)
2511                                 extra[k++] = i->control_pid;
2512
2513                         show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
2514                                                       c, false, extra, k, flags);
2515                 }
2516         }
2517
2518         if (i->id && arg_transport != TRANSPORT_SSH) {
2519                 printf("\n");
2520                 show_journal_by_unit(stdout,
2521                                      i->id,
2522                                      arg_output,
2523                                      0,
2524                                      i->inactive_exit_timestamp_monotonic,
2525                                      arg_lines,
2526                                      getuid(),
2527                                      flags,
2528                                      arg_scope == UNIT_FILE_SYSTEM);
2529         }
2530
2531         if (i->need_daemon_reload)
2532                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2533                        ansi_highlight_red(true),
2534                        ansi_highlight_red(false),
2535                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2536 }
2537
2538 static void show_unit_help(UnitStatusInfo *i) {
2539         char **p;
2540
2541         assert(i);
2542
2543         if (!i->documentation) {
2544                 log_info("Documentation for %s not known.", i->id);
2545                 return;
2546         }
2547
2548         STRV_FOREACH(p, i->documentation) {
2549
2550                 if (startswith(*p, "man:")) {
2551                         size_t k;
2552                         char *e = NULL;
2553                         char _cleanup_free_ *page = NULL, *section = NULL;
2554                         const char *args[4] = { "man", NULL, NULL, NULL };
2555                         pid_t pid;
2556
2557                         k = strlen(*p);
2558
2559                         if ((*p)[k-1] == ')')
2560                                 e = strrchr(*p, '(');
2561
2562                         if (e) {
2563                                 page = strndup((*p) + 4, e - *p - 4);
2564                                 section = strndup(e + 1, *p + k - e - 2);
2565                                 if (!page || !section) {
2566                                         log_oom();
2567                                         return;
2568                                 }
2569
2570                                 args[1] = section;
2571                                 args[2] = page;
2572                         } else
2573                                 args[1] = *p + 4;
2574
2575                         pid = fork();
2576                         if (pid < 0) {
2577                                 log_error("Failed to fork: %m");
2578                                 continue;
2579                         }
2580
2581                         if (pid == 0) {
2582                                 /* Child */
2583                                 execvp(args[0], (char**) args);
2584                                 log_error("Failed to execute man: %m");
2585                                 _exit(EXIT_FAILURE);
2586                         }
2587
2588                         wait_for_terminate(pid, NULL);
2589                 } else
2590                         log_info("Can't show: %s", *p);
2591         }
2592 }
2593
2594 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2595
2596         assert(name);
2597         assert(iter);
2598         assert(i);
2599
2600         switch (dbus_message_iter_get_arg_type(iter)) {
2601
2602         case DBUS_TYPE_STRING: {
2603                 const char *s;
2604
2605                 dbus_message_iter_get_basic(iter, &s);
2606
2607                 if (!isempty(s)) {
2608                         if (streq(name, "Id"))
2609                                 i->id = s;
2610                         else if (streq(name, "LoadState"))
2611                                 i->load_state = s;
2612                         else if (streq(name, "ActiveState"))
2613                                 i->active_state = s;
2614                         else if (streq(name, "SubState"))
2615                                 i->sub_state = s;
2616                         else if (streq(name, "Description"))
2617                                 i->description = s;
2618                         else if (streq(name, "FragmentPath"))
2619                                 i->fragment_path = s;
2620                         else if (streq(name, "SourcePath"))
2621                                 i->source_path = s;
2622                         else if (streq(name, "DefaultControlGroup"))
2623                                 i->default_control_group = s;
2624                         else if (streq(name, "StatusText"))
2625                                 i->status_text = s;
2626                         else if (streq(name, "SysFSPath"))
2627                                 i->sysfs_path = s;
2628                         else if (streq(name, "Where"))
2629                                 i->where = s;
2630                         else if (streq(name, "What"))
2631                                 i->what = s;
2632                         else if (streq(name, "Following"))
2633                                 i->following = s;
2634                         else if (streq(name, "UnitFileState"))
2635                                 i->unit_file_state = s;
2636                         else if (streq(name, "Result"))
2637                                 i->result = s;
2638                 }
2639
2640                 break;
2641         }
2642
2643         case DBUS_TYPE_BOOLEAN: {
2644                 dbus_bool_t b;
2645
2646                 dbus_message_iter_get_basic(iter, &b);
2647
2648                 if (streq(name, "Accept"))
2649                         i->accept = b;
2650                 else if (streq(name, "NeedDaemonReload"))
2651                         i->need_daemon_reload = b;
2652                 else if (streq(name, "ConditionResult"))
2653                         i->condition_result = b;
2654
2655                 break;
2656         }
2657
2658         case DBUS_TYPE_UINT32: {
2659                 uint32_t u;
2660
2661                 dbus_message_iter_get_basic(iter, &u);
2662
2663                 if (streq(name, "MainPID")) {
2664                         if (u > 0) {
2665                                 i->main_pid = (pid_t) u;
2666                                 i->running = true;
2667                         }
2668                 } else if (streq(name, "ControlPID"))
2669                         i->control_pid = (pid_t) u;
2670                 else if (streq(name, "ExecMainPID")) {
2671                         if (u > 0)
2672                                 i->main_pid = (pid_t) u;
2673                 } else if (streq(name, "NAccepted"))
2674                         i->n_accepted = u;
2675                 else if (streq(name, "NConnections"))
2676                         i->n_connections = u;
2677
2678                 break;
2679         }
2680
2681         case DBUS_TYPE_INT32: {
2682                 int32_t j;
2683
2684                 dbus_message_iter_get_basic(iter, &j);
2685
2686                 if (streq(name, "ExecMainCode"))
2687                         i->exit_code = (int) j;
2688                 else if (streq(name, "ExecMainStatus"))
2689                         i->exit_status = (int) j;
2690
2691                 break;
2692         }
2693
2694         case DBUS_TYPE_UINT64: {
2695                 uint64_t u;
2696
2697                 dbus_message_iter_get_basic(iter, &u);
2698
2699                 if (streq(name, "ExecMainStartTimestamp"))
2700                         i->start_timestamp = (usec_t) u;
2701                 else if (streq(name, "ExecMainExitTimestamp"))
2702                         i->exit_timestamp = (usec_t) u;
2703                 else if (streq(name, "ActiveEnterTimestamp"))
2704                         i->active_enter_timestamp = (usec_t) u;
2705                 else if (streq(name, "InactiveEnterTimestamp"))
2706                         i->inactive_enter_timestamp = (usec_t) u;
2707                 else if (streq(name, "InactiveExitTimestamp"))
2708                         i->inactive_exit_timestamp = (usec_t) u;
2709                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2710                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2711                 else if (streq(name, "ActiveExitTimestamp"))
2712                         i->active_exit_timestamp = (usec_t) u;
2713                 else if (streq(name, "ConditionTimestamp"))
2714                         i->condition_timestamp = (usec_t) u;
2715
2716                 break;
2717         }
2718
2719         case DBUS_TYPE_ARRAY: {
2720
2721                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2722                     startswith(name, "Exec")) {
2723                         DBusMessageIter sub;
2724
2725                         dbus_message_iter_recurse(iter, &sub);
2726                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2727                                 ExecStatusInfo *info;
2728                                 int r;
2729
2730                                 if (!(info = new0(ExecStatusInfo, 1)))
2731                                         return -ENOMEM;
2732
2733                                 if (!(info->name = strdup(name))) {
2734                                         free(info);
2735                                         return -ENOMEM;
2736                                 }
2737
2738                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2739                                         free(info);
2740                                         return r;
2741                                 }
2742
2743                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2744
2745                                 dbus_message_iter_next(&sub);
2746                         }
2747
2748                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2749                         DBusMessageIter sub, sub2;
2750
2751                         dbus_message_iter_recurse(iter, &sub);
2752                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2753                                 const char *type, *path;
2754
2755                                 dbus_message_iter_recurse(&sub, &sub2);
2756
2757                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2758                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
2759                                         int r;
2760
2761                                         r = strv_extend(&i->listen, type);
2762                                         if (r < 0)
2763                                                 return r;
2764                                         r = strv_extend(&i->listen, path);
2765                                         if (r < 0)
2766                                                 return r;
2767                                 }
2768
2769                                 dbus_message_iter_next(&sub);
2770                         }
2771
2772                         return 0;
2773
2774                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2775                            streq(name, "Documentation")) {
2776
2777                         DBusMessageIter sub;
2778
2779                         dbus_message_iter_recurse(iter, &sub);
2780                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2781                                 const char *s;
2782                                 int r;
2783
2784                                 dbus_message_iter_get_basic(&sub, &s);
2785
2786                                 r = strv_extend(&i->documentation, s);
2787                                 if (r < 0)
2788                                         return r;
2789
2790                                 dbus_message_iter_next(&sub);
2791                         }
2792                 }
2793
2794                 break;
2795         }
2796
2797         case DBUS_TYPE_STRUCT: {
2798
2799                 if (streq(name, "LoadError")) {
2800                         DBusMessageIter sub;
2801                         const char *n, *message;
2802                         int r;
2803
2804                         dbus_message_iter_recurse(iter, &sub);
2805
2806                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2807                         if (r < 0)
2808                                 return r;
2809
2810                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2811                         if (r < 0)
2812                                 return r;
2813
2814                         if (!isempty(message))
2815                                 i->load_error = message;
2816                 }
2817
2818                 break;
2819         }
2820         }
2821
2822         return 0;
2823 }
2824
2825 static int print_property(const char *name, DBusMessageIter *iter) {
2826         assert(name);
2827         assert(iter);
2828
2829         /* This is a low-level property printer, see
2830          * print_status_info() for the nicer output */
2831
2832         if (arg_property && !strv_find(arg_property, name))
2833                 return 0;
2834
2835         switch (dbus_message_iter_get_arg_type(iter)) {
2836
2837         case DBUS_TYPE_STRUCT: {
2838                 DBusMessageIter sub;
2839                 dbus_message_iter_recurse(iter, &sub);
2840
2841                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2842                         uint32_t u;
2843
2844                         dbus_message_iter_get_basic(&sub, &u);
2845
2846                         if (u)
2847                                 printf("%s=%u\n", name, (unsigned) u);
2848                         else if (arg_all)
2849                                 printf("%s=\n", name);
2850
2851                         return 0;
2852                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2853                         const char *s;
2854
2855                         dbus_message_iter_get_basic(&sub, &s);
2856
2857                         if (arg_all || s[0])
2858                                 printf("%s=%s\n", name, s);
2859
2860                         return 0;
2861                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2862                         const char *a = NULL, *b = NULL;
2863
2864                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2865                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2866
2867                         if (arg_all || !isempty(a) || !isempty(b))
2868                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2869
2870                         return 0;
2871                 }
2872
2873                 break;
2874         }
2875
2876         case DBUS_TYPE_ARRAY:
2877
2878                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2879                         DBusMessageIter sub, sub2;
2880
2881                         dbus_message_iter_recurse(iter, &sub);
2882                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2883                                 const char *path;
2884                                 dbus_bool_t ignore;
2885
2886                                 dbus_message_iter_recurse(&sub, &sub2);
2887
2888                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2889                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2890                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2891
2892                                 dbus_message_iter_next(&sub);
2893                         }
2894
2895                         return 0;
2896
2897                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2898                         DBusMessageIter sub, sub2;
2899
2900                         dbus_message_iter_recurse(iter, &sub);
2901
2902                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2903                                 const char *type, *path;
2904
2905                                 dbus_message_iter_recurse(&sub, &sub2);
2906
2907                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2908                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2909                                         printf("%s=%s\n", type, path);
2910
2911                                 dbus_message_iter_next(&sub);
2912                         }
2913
2914                         return 0;
2915
2916                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
2917                         DBusMessageIter sub, sub2;
2918
2919                         dbus_message_iter_recurse(iter, &sub);
2920                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2921                                 const char *type, *path;
2922
2923                                 dbus_message_iter_recurse(&sub, &sub2);
2924
2925                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2926                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2927                                         printf("Listen%s=%s\n", type, path);
2928
2929                                 dbus_message_iter_next(&sub);
2930                         }
2931
2932                         return 0;
2933
2934                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2935                         DBusMessageIter sub, sub2;
2936
2937                         dbus_message_iter_recurse(iter, &sub);
2938                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2939                                 const char *base;
2940                                 uint64_t value, next_elapse;
2941
2942                                 dbus_message_iter_recurse(&sub, &sub2);
2943
2944                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2945                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2946                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2947                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2948
2949                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2950                                                base,
2951                                                format_timespan(timespan1, sizeof(timespan1), value, 0),
2952                                                format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
2953                                 }
2954
2955                                 dbus_message_iter_next(&sub);
2956                         }
2957
2958                         return 0;
2959
2960                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2961                         DBusMessageIter sub, sub2;
2962
2963                         dbus_message_iter_recurse(iter, &sub);
2964                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2965                                 const char *controller, *attr, *value;
2966
2967                                 dbus_message_iter_recurse(&sub, &sub2);
2968
2969                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2970                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2971                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2972
2973                                         printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2974                                                controller,
2975                                                attr,
2976                                                value);
2977                                 }
2978
2979                                 dbus_message_iter_next(&sub);
2980                         }
2981
2982                         return 0;
2983
2984                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2985                         DBusMessageIter sub;
2986
2987                         dbus_message_iter_recurse(iter, &sub);
2988                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2989                                 ExecStatusInfo info;
2990
2991                                 zero(info);
2992                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2993                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2994                                         char _cleanup_free_ *t;
2995
2996                                         t = strv_join(info.argv, " ");
2997
2998                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2999                                                name,
3000                                                strna(info.path),
3001                                                strna(t),
3002                                                yes_no(info.ignore),
3003                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3004                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3005                                                (unsigned) info. pid,
3006                                                sigchld_code_to_string(info.code),
3007                                                info.status,
3008                                                info.code == CLD_EXITED ? "" : "/",
3009                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3010                                 }
3011
3012                                 free(info.path);
3013                                 strv_free(info.argv);
3014
3015                                 dbus_message_iter_next(&sub);
3016                         }
3017
3018                         return 0;
3019                 }
3020
3021                 break;
3022         }
3023
3024         if (generic_print_property(name, iter, arg_all) > 0)
3025                 return 0;
3026
3027         if (arg_all)
3028                 printf("%s=[unprintable]\n", name);
3029
3030         return 0;
3031 }
3032
3033 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3034         DBusMessage _cleanup_free_ *reply = NULL;
3035         const char *interface = "";
3036         int r;
3037         DBusMessageIter iter, sub, sub2, sub3;
3038         UnitStatusInfo info;
3039         ExecStatusInfo *p;
3040
3041         assert(path);
3042         assert(new_line);
3043
3044         zero(info);
3045
3046         r = bus_method_call_with_reply(
3047                         bus,
3048                         "org.freedesktop.systemd1",
3049                         path,
3050                         "org.freedesktop.DBus.Properties",
3051                         "GetAll",
3052                         &reply,
3053                         NULL,
3054                         DBUS_TYPE_STRING, &interface,
3055                         DBUS_TYPE_INVALID);
3056         if (r < 0)
3057                 return r;
3058
3059         if (!dbus_message_iter_init(reply, &iter) ||
3060             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3061             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3062                 log_error("Failed to parse reply.");
3063                 return -EIO;
3064         }
3065
3066         dbus_message_iter_recurse(&iter, &sub);
3067
3068         if (*new_line)
3069                 printf("\n");
3070
3071         *new_line = true;
3072
3073         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3074                 const char *name;
3075
3076                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
3077                 dbus_message_iter_recurse(&sub, &sub2);
3078
3079                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
3080                     dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
3081                         log_error("Failed to parse reply.");
3082                         return -EIO;
3083                 }
3084
3085                 dbus_message_iter_recurse(&sub2, &sub3);
3086
3087                 if (show_properties)
3088                         r = print_property(name, &sub3);
3089                 else
3090                         r = status_property(name, &sub3, &info);
3091                 if (r < 0) {
3092                         log_error("Failed to parse reply.");
3093                         return -EIO;
3094                 }
3095
3096                 dbus_message_iter_next(&sub);
3097         }
3098
3099         r = 0;
3100
3101         if (!show_properties) {
3102                 if (streq(verb, "help"))
3103                         show_unit_help(&info);
3104                 else
3105                         print_status_info(&info);
3106         }
3107
3108         strv_free(info.documentation);
3109         strv_free(info.listen);
3110
3111         if (!streq_ptr(info.active_state, "active") &&
3112             !streq_ptr(info.active_state, "reloading") &&
3113             streq(verb, "status"))
3114                 /* According to LSB: "program not running" */
3115                 r = 3;
3116
3117         while ((p = info.exec)) {
3118                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3119                 exec_status_info_free(p);
3120         }
3121
3122         return r;
3123 }
3124
3125 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3126         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3127         const char *path = NULL;
3128         DBusError _cleanup_dbus_error_free_ error;
3129         int r;
3130
3131         dbus_error_init(&error);
3132
3133         r = bus_method_call_with_reply(
3134                         bus,
3135                         "org.freedesktop.systemd1",
3136                         "/org/freedesktop/systemd1",
3137                         "org.freedesktop.systemd1.Manager",
3138                         "GetUnitByPID",
3139                         &reply,
3140                         NULL,
3141                         DBUS_TYPE_UINT32, &pid,
3142                         DBUS_TYPE_INVALID);
3143         if (r < 0)
3144                 return r;
3145
3146         if (!dbus_message_get_args(reply, &error,
3147                                    DBUS_TYPE_OBJECT_PATH, &path,
3148                                    DBUS_TYPE_INVALID)) {
3149                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3150                 return -EIO;
3151         }
3152
3153         r = show_one(verb, bus, path, false, new_line);
3154         return r;
3155 }
3156
3157 static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) {
3158         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3159         _cleanup_free_ struct unit_info *unit_infos = NULL;
3160         unsigned c = 0;
3161         const struct unit_info *u;
3162         int r;
3163
3164         r = get_unit_list(bus, &reply, &unit_infos, &c);
3165         if (r < 0)
3166                 return r;
3167
3168         for (u = unit_infos; u < unit_infos + c; u++) {
3169                 char _cleanup_free_ *p = NULL;
3170
3171                 if (!output_show_unit(u))
3172                         continue;
3173
3174                 p = unit_dbus_path_from_name(u->id);
3175                 if (!p)
3176                         return log_oom();
3177
3178                 printf("%s -> '%s'\n", u->id, p);
3179
3180                 r = show_one(verb, bus, p, show_properties, new_line);
3181                 if (r != 0)
3182                         return r;
3183         }
3184
3185         return 0;
3186 }
3187
3188 static int show(DBusConnection *bus, char **args) {
3189         int r, ret = 0;
3190         bool show_properties, show_status, new_line = false;
3191         char **name;
3192
3193         assert(bus);
3194         assert(args);
3195
3196         show_properties = streq(args[0], "show");
3197         show_status = streq(args[0], "status");
3198
3199         if (show_properties)
3200                 pager_open_if_enabled();
3201
3202         /* If no argument is specified inspect the manager itself */
3203
3204         if (show_properties && strv_length(args) <= 1)
3205                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3206
3207         if (show_status && strv_length(args) <= 1)
3208                 return show_all(args[0], bus, false, &new_line);
3209
3210         STRV_FOREACH(name, args+1) {
3211                 uint32_t id;
3212
3213                 if (safe_atou32(*name, &id) < 0) {
3214                         _cleanup_free_ char *p = NULL, *n = NULL;
3215                         /* Interpret as unit name */
3216
3217                         n = unit_name_mangle(*name);
3218                         if (!n)
3219                                 return log_oom();
3220
3221                         p = unit_dbus_path_from_name(n);
3222                         if (!p)
3223                                 return log_oom();
3224
3225                         r = show_one(args[0], bus, p, show_properties, &new_line);
3226                         if (r != 0)
3227                                 ret = r;
3228
3229                 } else if (show_properties) {
3230                         _cleanup_free_ char *p = NULL;
3231
3232                         /* Interpret as job id */
3233                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3234                                 return log_oom();
3235
3236                         r = show_one(args[0], bus, p, show_properties, &new_line);
3237                         if (r != 0)
3238                                 ret = r;
3239
3240                 } else {
3241                         /* Interpret as PID */
3242                         r = show_one_by_pid(args[0], bus, id, &new_line);
3243                         if (r != 0)
3244                                 ret = r;
3245                 }
3246         }
3247
3248         return ret;
3249 }
3250
3251 static int dump(DBusConnection *bus, char **args) {
3252         _cleanup_free_ DBusMessage *reply = NULL;
3253         DBusError error;
3254         int r;
3255         const char *text;
3256
3257         dbus_error_init(&error);
3258
3259         pager_open_if_enabled();
3260
3261         r = bus_method_call_with_reply(
3262                         bus,
3263                         "org.freedesktop.systemd1",
3264                         "/org/freedesktop/systemd1",
3265                         "org.freedesktop.systemd1.Manager",
3266                         "Dump",
3267                         &reply,
3268                         NULL,
3269                         DBUS_TYPE_INVALID);
3270         if (r < 0)
3271                 return r;
3272
3273         if (!dbus_message_get_args(reply, &error,
3274                                    DBUS_TYPE_STRING, &text,
3275                                    DBUS_TYPE_INVALID)) {
3276                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3277                 dbus_error_free(&error);
3278                 return  -EIO;
3279         }
3280
3281         fputs(text, stdout);
3282         return 0;
3283 }
3284
3285 static int snapshot(DBusConnection *bus, char **args) {
3286         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3287         DBusError error;
3288         int r;
3289         dbus_bool_t cleanup = FALSE;
3290         DBusMessageIter iter, sub;
3291         const char
3292                 *path, *id,
3293                 *interface = "org.freedesktop.systemd1.Unit",
3294                 *property = "Id";
3295         _cleanup_free_ char *n = NULL;
3296
3297         dbus_error_init(&error);
3298
3299         if (strv_length(args) > 1)
3300                 n = snapshot_name_mangle(args[1]);
3301         else
3302                 n = strdup("");
3303         if (!n)
3304                 return log_oom();
3305
3306         r = bus_method_call_with_reply (
3307                         bus,
3308                         "org.freedesktop.systemd1",
3309                         "/org/freedesktop/systemd1",
3310                         "org.freedesktop.systemd1.Manager",
3311                         "CreateSnapshot",
3312                         &reply,
3313                         NULL,
3314                         DBUS_TYPE_STRING, &n,
3315                         DBUS_TYPE_BOOLEAN, &cleanup,
3316                         DBUS_TYPE_INVALID);
3317         if (r < 0)
3318                 return r;
3319
3320         if (!dbus_message_get_args(reply, &error,
3321                                    DBUS_TYPE_OBJECT_PATH, &path,
3322                                    DBUS_TYPE_INVALID)) {
3323                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3324                 dbus_error_free(&error);
3325                 return -EIO;
3326         }
3327
3328         dbus_message_unref(reply);
3329         reply = NULL;
3330
3331         r = bus_method_call_with_reply (
3332                         bus,
3333                         "org.freedesktop.systemd1",
3334                         path,
3335                         "org.freedesktop.DBus.Properties",
3336                         "Get",
3337                         &reply,
3338                         NULL,
3339                         DBUS_TYPE_STRING, &interface,
3340                         DBUS_TYPE_STRING, &property,
3341                         DBUS_TYPE_INVALID);
3342         if (r < 0)
3343                 return r;
3344
3345         if (!dbus_message_iter_init(reply, &iter) ||
3346             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3347                 log_error("Failed to parse reply.");
3348                 return -EIO;
3349         }
3350
3351         dbus_message_iter_recurse(&iter, &sub);
3352
3353         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3354                 log_error("Failed to parse reply.");
3355                 return -EIO;
3356         }
3357
3358         dbus_message_iter_get_basic(&sub, &id);
3359
3360         if (!arg_quiet)
3361                 puts(id);
3362
3363         return 0;
3364 }
3365
3366 static int delete_snapshot(DBusConnection *bus, char **args) {
3367         char **name;
3368
3369         assert(args);
3370
3371         STRV_FOREACH(name, args+1) {
3372                 _cleanup_free_ char *n = NULL;
3373                 int r;
3374
3375                 n = snapshot_name_mangle(*name);
3376                 if (!n)
3377                         return log_oom();
3378
3379                 r = bus_method_call_with_reply(
3380                                 bus,
3381                                 "org.freedesktop.systemd1",
3382                                 "/org/freedesktop/systemd1",
3383                                 "org.freedesktop.systemd1.Manager",
3384                                 "RemoveSnapshot",
3385                                 NULL,
3386                                 NULL,
3387                                 DBUS_TYPE_STRING, &n,
3388                                 DBUS_TYPE_INVALID);
3389                 if (r < 0)
3390                         return r;
3391         }
3392
3393         return 0;
3394 }
3395
3396 static int daemon_reload(DBusConnection *bus, char **args) {
3397         int r;
3398         const char *method;
3399         DBusError error;
3400
3401         if (arg_action == ACTION_RELOAD)
3402                 method = "Reload";
3403         else if (arg_action == ACTION_REEXEC)
3404                 method = "Reexecute";
3405         else {
3406                 assert(arg_action == ACTION_SYSTEMCTL);
3407
3408                 method =
3409                         streq(args[0], "clear-jobs")    ||
3410                         streq(args[0], "cancel")        ? "ClearJobs" :
3411                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3412                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3413                         streq(args[0], "halt")          ? "Halt" :
3414                         streq(args[0], "poweroff")      ? "PowerOff" :
3415                         streq(args[0], "reboot")        ? "Reboot" :
3416                         streq(args[0], "kexec")         ? "KExec" :
3417                         streq(args[0], "exit")          ? "Exit" :
3418                                     /* "daemon-reload" */ "Reload";
3419         }
3420
3421         r = bus_method_call_with_reply(
3422                         bus,
3423                         "org.freedesktop.systemd1",
3424                         "/org/freedesktop/systemd1",
3425                         "org.freedesktop.systemd1.Manager",
3426                         method,
3427                         NULL,
3428                         &error,
3429                         DBUS_TYPE_INVALID);
3430
3431         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3432                 /* There's always a fallback possible for
3433                  * legacy actions. */
3434                 r = -EADDRNOTAVAIL;
3435         else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3436                 /* On reexecution, we expect a disconnect, not
3437                  * a reply */
3438                 r = 0;
3439         else if (r < 0)
3440                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3441
3442         dbus_error_free(&error);
3443         return r;
3444 }
3445
3446 static int reset_failed(DBusConnection *bus, char **args) {
3447         int r = 0;
3448         char **name;
3449
3450         if (strv_length(args) <= 1)
3451                 return daemon_reload(bus, args);
3452
3453         STRV_FOREACH(name, args+1) {
3454                 _cleanup_free_ char *n;
3455
3456                 n = unit_name_mangle(*name);
3457                 if (!n)
3458                         return log_oom();
3459
3460                 r = bus_method_call_with_reply(
3461                                 bus,
3462                                 "org.freedesktop.systemd1",
3463                                 "/org/freedesktop/systemd1",
3464                                 "org.freedesktop.systemd1.Manager",
3465                                 "ResetFailedUnit",
3466                                 NULL,
3467                                 NULL,
3468                                 DBUS_TYPE_STRING, &n,
3469                                 DBUS_TYPE_INVALID);
3470                 if (r < 0)
3471                         return r;
3472         }
3473
3474         return 0;
3475 }
3476
3477 static int show_enviroment(DBusConnection *bus, char **args) {
3478         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3479         DBusMessageIter iter, sub, sub2;
3480         int r;
3481         const char
3482                 *interface = "org.freedesktop.systemd1.Manager",
3483                 *property = "Environment";
3484
3485         pager_open_if_enabled();
3486
3487         r = bus_method_call_with_reply(
3488                         bus,
3489                         "org.freedesktop.systemd1",
3490                         "/org/freedesktop/systemd1",
3491                         "org.freedesktop.DBus.Properties",
3492                         "Get",
3493                         &reply,
3494                         NULL,
3495                         DBUS_TYPE_STRING, &interface,
3496                         DBUS_TYPE_STRING, &property,
3497                         DBUS_TYPE_INVALID);
3498         if (r < 0)
3499                 return r;
3500
3501         if (!dbus_message_iter_init(reply, &iter) ||
3502             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3503                 log_error("Failed to parse reply.");
3504                 return -EIO;
3505         }
3506
3507         dbus_message_iter_recurse(&iter, &sub);
3508
3509         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3510             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3511                 log_error("Failed to parse reply.");
3512                 return -EIO;
3513         }
3514
3515         dbus_message_iter_recurse(&sub, &sub2);
3516
3517         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3518                 const char *text;
3519
3520                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3521                         log_error("Failed to parse reply.");
3522                         return -EIO;
3523                 }
3524
3525                 dbus_message_iter_get_basic(&sub2, &text);
3526                 puts(text);
3527
3528                 dbus_message_iter_next(&sub2);
3529         }
3530
3531         return 0;
3532 }
3533
3534 static int switch_root(DBusConnection *bus, char **args) {
3535         unsigned l;
3536         const char *root;
3537         _cleanup_free_ char *init = NULL;
3538
3539         l = strv_length(args);
3540         if (l < 2 || l > 3) {
3541                 log_error("Wrong number of arguments.");
3542                 return -EINVAL;
3543         }
3544
3545         root = args[1];
3546
3547         if (l >= 3)
3548                 init = strdup(args[2]);
3549         else {
3550                 parse_env_file("/proc/cmdline", WHITESPACE,
3551                                "init", &init,
3552                                NULL);
3553
3554                 if (!init)
3555                         init = strdup("");
3556         }
3557         if (!init)
3558                 return log_oom();
3559
3560         log_debug("switching root - root: %s; init: %s", root, init);
3561
3562         return bus_method_call_with_reply(
3563                         bus,
3564                         "org.freedesktop.systemd1",
3565                         "/org/freedesktop/systemd1",
3566                         "org.freedesktop.systemd1.Manager",
3567                         "SwitchRoot",
3568                         NULL,
3569                         NULL,
3570                         DBUS_TYPE_STRING, &root,
3571                         DBUS_TYPE_STRING, &init,
3572                         DBUS_TYPE_INVALID);
3573 }
3574
3575 static int set_environment(DBusConnection *bus, char **args) {
3576         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
3577         DBusError error;
3578         const char *method;
3579         DBusMessageIter iter;
3580         int r;
3581
3582         assert(bus);
3583         assert(args);
3584
3585         dbus_error_init(&error);
3586
3587         method = streq(args[0], "set-environment")
3588                 ? "SetEnvironment"
3589                 : "UnsetEnvironment";
3590
3591         m = dbus_message_new_method_call(
3592                         "org.freedesktop.systemd1",
3593                         "/org/freedesktop/systemd1",
3594                         "org.freedesktop.systemd1.Manager",
3595                         method);
3596         if (!m)
3597                 return log_oom();
3598
3599         dbus_message_iter_init_append(m, &iter);
3600
3601         r = bus_append_strv_iter(&iter, args + 1);
3602         if (r < 0)
3603                 return log_oom();
3604
3605         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3606         if (!reply) {
3607                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3608                 dbus_error_free(&error);
3609                 return -EIO;
3610         }
3611
3612         return 0;
3613 }
3614
3615 static int enable_sysv_units(char **args) {
3616         int r = 0;
3617
3618 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
3619         const char *verb = args[0];
3620         unsigned f = 1, t = 1;
3621         LookupPaths paths;
3622
3623         if (arg_scope != UNIT_FILE_SYSTEM)
3624                 return 0;
3625
3626         if (!streq(verb, "enable") &&
3627             !streq(verb, "disable") &&
3628             !streq(verb, "is-enabled"))
3629                 return 0;
3630
3631         /* Processes all SysV units, and reshuffles the array so that
3632          * afterwards only the native units remain */
3633
3634         zero(paths);
3635         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
3636         if (r < 0)
3637                 return r;
3638
3639         r = 0;
3640         for (f = 1; args[f]; f++) {
3641                 const char *name;
3642                 char *p;
3643                 bool found_native = false, found_sysv;
3644                 unsigned c = 1;
3645                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3646                 char **k, *l, *q = NULL;
3647                 int j;
3648                 pid_t pid;
3649                 siginfo_t status;
3650
3651                 name = args[f];
3652
3653                 if (!endswith(name, ".service"))
3654                         continue;
3655
3656                 if (path_is_absolute(name))
3657                         continue;
3658
3659                 STRV_FOREACH(k, paths.unit_path) {
3660                         p = NULL;
3661
3662                         if (!isempty(arg_root))
3663                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3664                         else
3665                                 asprintf(&p, "%s/%s", *k, name);
3666
3667                         if (!p) {
3668                                 r = log_oom();
3669                                 goto finish;
3670                         }
3671
3672                         found_native = access(p, F_OK) >= 0;
3673                         free(p);
3674
3675                         if (found_native)
3676                                 break;
3677                 }
3678
3679                 if (found_native)
3680                         continue;
3681
3682                 p = NULL;
3683                 if (!isempty(arg_root))
3684                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3685                 else
3686                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3687                 if (!p) {
3688                         r = log_oom();
3689                         goto finish;
3690                 }
3691
3692                 p[strlen(p) - sizeof(".service") + 1] = 0;
3693                 found_sysv = access(p, F_OK) >= 0;
3694
3695                 if (!found_sysv) {
3696                         free(p);
3697                         continue;
3698                 }
3699
3700                 /* Mark this entry, so that we don't try enabling it as native unit */
3701                 args[f] = (char*) "";
3702
3703                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3704
3705                 if (!isempty(arg_root))
3706                         argv[c++] = q = strappend("--root=", arg_root);
3707
3708                 argv[c++] = path_get_file_name(p);
3709                 argv[c++] =
3710                         streq(verb, "enable") ? "on" :
3711                         streq(verb, "disable") ? "off" : "--level=5";
3712                 argv[c] = NULL;
3713
3714                 l = strv_join((char**)argv, " ");
3715                 if (!l) {
3716                         free(q);
3717                         free(p);
3718                         r = log_oom();
3719                         goto finish;
3720                 }
3721
3722                 log_info("Executing %s", l);
3723                 free(l);
3724
3725                 pid = fork();
3726                 if (pid < 0) {
3727                         log_error("Failed to fork: %m");
3728                         free(p);
3729                         free(q);
3730                         r = -errno;
3731                         goto finish;
3732                 } else if (pid == 0) {
3733                         /* Child */
3734
3735                         execv(argv[0], (char**) argv);
3736                         _exit(EXIT_FAILURE);
3737                 }
3738
3739                 free(p);
3740                 free(q);
3741
3742                 j = wait_for_terminate(pid, &status);
3743                 if (j < 0) {
3744                         log_error("Failed to wait for child: %s", strerror(-r));
3745                         r = j;
3746                         goto finish;
3747                 }
3748
3749                 if (status.si_code == CLD_EXITED) {
3750                         if (streq(verb, "is-enabled")) {
3751                                 if (status.si_status == 0) {
3752                                         if (!arg_quiet)
3753                                                 puts("enabled");
3754                                         r = 1;
3755                                 } else {
3756                                         if (!arg_quiet)
3757                                                 puts("disabled");
3758                                 }
3759
3760                         } else if (status.si_status != 0) {
3761                                 r = -EINVAL;
3762                                 goto finish;
3763                         }
3764                 } else {
3765                         r = -EPROTO;
3766                         goto finish;
3767                 }
3768         }
3769
3770 finish:
3771         lookup_paths_free(&paths);
3772
3773         /* Drop all SysV units */
3774         for (f = 1, t = 1; args[f]; f++) {
3775
3776                 if (isempty(args[f]))
3777                         continue;
3778
3779                 args[t++] = args[f];
3780         }
3781
3782         args[t] = NULL;
3783
3784 #endif
3785         return r;
3786 }
3787
3788 static int mangle_names(char **original_names, char ***mangled_names) {
3789         char **i, **l, **name;
3790
3791         l = new(char*, strv_length(original_names) + 1);
3792         if (!l)
3793                 return log_oom();
3794
3795         i = l;
3796         STRV_FOREACH(name, original_names) {
3797
3798                 /* When enabling units qualified path names are OK,
3799                  * too, hence allow them explicitly. */
3800
3801                 if (is_path(*name))
3802                         *i = strdup(*name);
3803                 else
3804                         *i = unit_name_mangle(*name);
3805
3806                 if (!*i) {
3807                         strv_free(l);
3808                         return log_oom();
3809                 }
3810
3811                 i++;
3812         }
3813
3814         *i = NULL;
3815         *mangled_names = l;
3816
3817         return 0;
3818 }
3819
3820 static int enable_unit(DBusConnection *bus, char **args) {
3821         const char *verb = args[0];
3822         UnitFileChange *changes = NULL;
3823         unsigned n_changes = 0, i;
3824         int carries_install_info = -1;
3825         DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
3826         int r;
3827         DBusError _cleanup_dbus_error_free_ error;
3828         char _cleanup_strv_free_ **mangled_names = NULL;
3829
3830         dbus_error_init(&error);
3831
3832         r = enable_sysv_units(args);
3833         if (r < 0)
3834                 return r;
3835
3836         if (!args[1])
3837                 return 0;
3838
3839         if (!bus || avoid_bus()) {
3840                 if (streq(verb, "enable")) {
3841                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3842                         carries_install_info = r;
3843                 } else if (streq(verb, "disable"))
3844                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3845                 else if (streq(verb, "reenable")) {
3846                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3847                         carries_install_info = r;
3848                 } else if (streq(verb, "link"))
3849                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3850                 else if (streq(verb, "preset")) {
3851                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3852                         carries_install_info = r;
3853                 } else if (streq(verb, "mask"))
3854                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3855                 else if (streq(verb, "unmask"))
3856                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3857                 else
3858                         assert_not_reached("Unknown verb");
3859
3860                 if (r < 0) {
3861                         log_error("Operation failed: %s", strerror(-r));
3862                         goto finish;
3863                 }
3864
3865                 if (!arg_quiet) {
3866                         for (i = 0; i < n_changes; i++) {
3867                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3868                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3869                                 else
3870                                         log_info("rm '%s'", changes[i].path);
3871                         }
3872                 }
3873
3874                 r = 0;
3875         } else {
3876                 const char *method;
3877                 bool send_force = true, expect_carries_install_info = false;
3878                 dbus_bool_t a, b;
3879                 DBusMessageIter iter, sub, sub2;
3880
3881                 if (streq(verb, "enable")) {
3882                         method = "EnableUnitFiles";
3883                         expect_carries_install_info = true;
3884                 } else if (streq(verb, "disable")) {
3885                         method = "DisableUnitFiles";
3886                         send_force = false;
3887                 } else if (streq(verb, "reenable")) {
3888                         method = "ReenableUnitFiles";
3889                         expect_carries_install_info = true;
3890                 } else if (streq(verb, "link"))
3891                         method = "LinkUnitFiles";
3892                 else if (streq(verb, "preset")) {
3893                         method = "PresetUnitFiles";
3894                         expect_carries_install_info = true;
3895                 } else if (streq(verb, "mask"))
3896                         method = "MaskUnitFiles";
3897                 else if (streq(verb, "unmask")) {
3898                         method = "UnmaskUnitFiles";
3899                         send_force = false;
3900                 } else
3901                         assert_not_reached("Unknown verb");
3902
3903                 m = dbus_message_new_method_call(
3904                                 "org.freedesktop.systemd1",
3905                                 "/org/freedesktop/systemd1",
3906                                 "org.freedesktop.systemd1.Manager",
3907                                 method);
3908                 if (!m) {
3909                         r = log_oom();
3910                         goto finish;
3911                 }
3912
3913                 dbus_message_iter_init_append(m, &iter);
3914
3915                 r = mangle_names(args+1, &mangled_names);
3916                 if(r < 0)
3917                         goto finish;
3918
3919                 r = bus_append_strv_iter(&iter, mangled_names);
3920                 if (r < 0) {
3921                         log_error("Failed to append unit files.");
3922                         goto finish;
3923                 }
3924
3925                 a = arg_runtime;
3926                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3927                         log_error("Failed to append runtime boolean.");
3928                         r = -ENOMEM;
3929                         goto finish;
3930                 }
3931
3932                 if (send_force) {
3933                         b = arg_force;
3934
3935                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3936                                 log_error("Failed to append force boolean.");
3937                                 r = -ENOMEM;
3938                                 goto finish;
3939                         }
3940                 }
3941
3942                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3943                 if (!reply) {
3944                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3945                         r = -EIO;
3946                         goto finish;
3947                 }
3948
3949                 if (!dbus_message_iter_init(reply, &iter)) {
3950                         log_error("Failed to initialize iterator.");
3951                         goto finish;
3952                 }
3953
3954                 if (expect_carries_install_info) {
3955                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3956                         if (r < 0) {
3957                                 log_error("Failed to parse reply.");
3958                                 goto finish;
3959                         }
3960
3961                         carries_install_info = b;
3962                 }
3963
3964                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3965                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3966                         log_error("Failed to parse reply.");
3967                         r = -EIO;
3968                         goto finish;
3969                 }
3970
3971                 dbus_message_iter_recurse(&iter, &sub);
3972                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3973                         const char *type, *path, *source;
3974
3975                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3976                                 log_error("Failed to parse reply.");
3977                                 r = -EIO;
3978                                 goto finish;
3979                         }
3980
3981                         dbus_message_iter_recurse(&sub, &sub2);
3982
3983                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3984                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3985                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3986                                 log_error("Failed to parse reply.");
3987                                 r = -EIO;
3988                                 goto finish;
3989                         }
3990
3991                         if (!arg_quiet) {
3992                                 if (streq(type, "symlink"))
3993                                         log_info("ln -s '%s' '%s'", source, path);
3994                                 else
3995                                         log_info("rm '%s'", path);
3996                         }
3997
3998                         dbus_message_iter_next(&sub);
3999                 }
4000
4001                 /* Try to reload if enabeld */
4002                 if (!arg_no_reload)
4003                         r = daemon_reload(bus, args);
4004         }
4005
4006         if (carries_install_info == 0)
4007                 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4008                             "using systemctl.\n"
4009                             "Possible reasons for having this kind of units are:\n"
4010                             "1) A unit may be statically enabled by being symlinked from another unit's\n"
4011                             "   .wants/ or .requires/ directory.\n"
4012                             "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4013                             "   a requirement dependency on it.\n"
4014                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
4015                             "   D-Bus, udev, scripted systemctl call, ...).\n");
4016
4017 finish:
4018         unit_file_changes_free(changes, n_changes);
4019
4020         return r;
4021 }
4022
4023 static int unit_is_enabled(DBusConnection *bus, char **args) {
4024         DBusError _cleanup_dbus_error_free_ error;
4025         int r;
4026         DBusMessage _cleanup_dbus_message_unref_ *reply = NULL;
4027         bool enabled;
4028         char **name;
4029         char *n;
4030
4031         dbus_error_init(&error);
4032
4033         r = enable_sysv_units(args);
4034         if (r < 0)
4035                 return r;
4036
4037         enabled = r > 0;
4038
4039         if (!bus || avoid_bus()) {
4040
4041                 STRV_FOREACH(name, args+1) {
4042                         UnitFileState state;
4043
4044                         n = unit_name_mangle(*name);
4045                         if (!n)
4046                                 return log_oom();
4047
4048                         state = unit_file_get_state(arg_scope, arg_root, n);
4049
4050                         free(n);
4051
4052                         if (state < 0)
4053                                 return state;
4054
4055                         if (state == UNIT_FILE_ENABLED ||
4056                             state == UNIT_FILE_ENABLED_RUNTIME ||
4057                             state == UNIT_FILE_STATIC)
4058                                 enabled = true;
4059
4060                         if (!arg_quiet)
4061                                 puts(unit_file_state_to_string(state));
4062                 }
4063
4064         } else {
4065                 STRV_FOREACH(name, args+1) {
4066                         const char *s;
4067
4068                         n = unit_name_mangle(*name);
4069                         if (!n)
4070                                 return log_oom();
4071
4072                         r = bus_method_call_with_reply (
4073                                         bus,
4074                                         "org.freedesktop.systemd1",
4075                                         "/org/freedesktop/systemd1",
4076                                         "org.freedesktop.systemd1.Manager",
4077                                         "GetUnitFileState",
4078                                         &reply,
4079                                         NULL,
4080                                         DBUS_TYPE_STRING, &n,
4081                                         DBUS_TYPE_INVALID);
4082
4083                         free(n);
4084
4085                         if (r)
4086                                 return r;
4087
4088                         if (!dbus_message_get_args(reply, &error,
4089                                                    DBUS_TYPE_STRING, &s,
4090                                                    DBUS_TYPE_INVALID)) {
4091                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4092                                 return -EIO;
4093                         }
4094
4095                         dbus_message_unref(reply);
4096                         reply = NULL;
4097
4098                         if (streq(s, "enabled") ||
4099                             streq(s, "enabled-runtime") ||
4100                             streq(s, "static"))
4101                                 enabled = true;
4102
4103                         if (!arg_quiet)
4104                                 puts(s);
4105                 }
4106         }
4107
4108         return enabled ? 0 : 1;
4109 }
4110
4111 static int systemctl_help(void) {
4112
4113         pager_open_if_enabled();
4114
4115         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4116                "Query or send control commands to the systemd manager.\n\n"
4117                "  -h --help           Show this help\n"
4118                "     --version        Show package version\n"
4119                "  -t --type=TYPE      List only units of a particular type\n"
4120                "  -p --property=NAME  Show only properties by this name\n"
4121                "  -a --all            Show all units/properties, including dead/empty ones\n"
4122                "     --failed         Show only failed units\n"
4123                "     --full           Don't ellipsize unit names on output\n"
4124                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4125                "                      pending\n"
4126                "     --ignore-dependencies\n"
4127                "                      When queueing a new job, ignore all its dependencies\n"
4128                "  -i --ignore-inhibitors\n"
4129                "                      When shutting down or sleeping, ignore inhibitors\n"
4130                "     --kill-who=WHO   Who to send signal to\n"
4131                "  -s --signal=SIGNAL  Which signal to send\n"
4132                "  -H --host=[USER@]HOST\n"
4133                "                      Show information for remote host\n"
4134                "  -P --privileged     Acquire privileges before execution\n"
4135                "  -q --quiet          Suppress output\n"
4136                "     --no-block       Do not wait until operation finished\n"
4137                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4138                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4139                "                      configuration\n"
4140                "     --no-legend      Do not print a legend (column headers and hints)\n"
4141                "     --no-pager       Do not pipe output into a pager\n"
4142                "     --no-ask-password\n"
4143                "                      Do not ask for system passwords\n"
4144                "     --system         Connect to system manager\n"
4145                "     --user           Connect to user service manager\n"
4146                "     --global         Enable/disable unit files globally\n"
4147                "  -f --force          When enabling unit files, override existing symlinks\n"
4148                "                      When shutting down, execute action immediately\n"
4149                "     --root=PATH      Enable unit files in the specified root directory\n"
4150                "     --runtime        Enable unit files only temporarily until next reboot\n"
4151                "  -n --lines=INTEGER  Journal entries to show\n"
4152                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4153                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
4154                "Unit Commands:\n"
4155                "  list-units                      List loaded units\n"
4156                "  start [NAME...]                 Start (activate) one or more units\n"
4157                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4158                "  reload [NAME...]                Reload one or more units\n"
4159                "  restart [NAME...]               Start or restart one or more units\n"
4160                "  try-restart [NAME...]           Restart one or more units if active\n"
4161                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
4162                "                                  otherwise start or restart\n"
4163                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
4164                "                                  otherwise restart if active\n"
4165                "  isolate [NAME]                  Start one unit and stop all others\n"
4166                "  kill [NAME...]                  Send signal to processes of a unit\n"
4167                "  is-active [NAME...]             Check whether units are active\n"
4168                "  is-failed [NAME...]             Check whether units are failed\n"
4169                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4170                "  show [NAME...|JOB...]           Show properties of one or more\n"
4171                "                                  units/jobs or the manager\n"
4172                "  help [NAME...|PID...]           Show manual for one or more units\n"
4173                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4174                "                                  units\n"
4175                "  get-cgroup-attr [NAME] [ATTR] ...\n"
4176                "                                  Get control group attrubute\n"
4177                "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
4178                "                                  Set control group attribute\n"
4179                "  unset-cgroup-attr [NAME] [ATTR...]\n"
4180                "                                  Unset control group attribute\n"
4181                "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
4182                "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
4183                "  load [NAME...]                  Load one or more units\n"
4184                "  list-dependencies [NAME]        Recursively show units which are required\n"
4185                "                                  or wanted by this unit\n\n"
4186                "Unit File Commands:\n"
4187                "  list-unit-files                 List installed unit files\n"
4188                "  enable [NAME...]                Enable one or more unit files\n"
4189                "  disable [NAME...]               Disable one or more unit files\n"
4190                "  reenable [NAME...]              Reenable one or more unit files\n"
4191                "  preset [NAME...]                Enable/disable one or more unit files\n"
4192                "                                  based on preset configuration\n"
4193                "  mask [NAME...]                  Mask one or more units\n"
4194                "  unmask [NAME...]                Unmask one or more units\n"
4195                "  link [PATH...]                  Link one or more units files into\n"
4196                "                                  the search path\n"
4197                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4198                "Job Commands:\n"
4199                "  list-jobs                       List jobs\n"
4200                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4201                "Status Commands:\n"
4202                "  dump                            Dump server status\n"
4203                "Snapshot Commands:\n"
4204                "  snapshot [NAME]                 Create a snapshot\n"
4205                "  delete [NAME...]                Remove one or more snapshots\n\n"
4206                "Environment Commands:\n"
4207                "  show-environment                Dump environment\n"
4208                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4209                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4210                "Manager Lifecycle Commands:\n"
4211                "  daemon-reload                   Reload systemd manager configuration\n"
4212                "  daemon-reexec                   Reexecute systemd manager\n\n"
4213                "System Commands:\n"
4214                "  default                         Enter system default mode\n"
4215                "  rescue                          Enter system rescue mode\n"
4216                "  emergency                       Enter system emergency mode\n"
4217                "  halt                            Shut down and halt the system\n"
4218                "  poweroff                        Shut down and power-off the system\n"
4219                "  reboot                          Shut down and reboot the system\n"
4220                "  kexec                           Shut down and reboot the system with kexec\n"
4221                "  exit                            Request user instance exit\n"
4222                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4223                "  suspend                         Suspend the system\n"
4224                "  hibernate                       Hibernate the system\n"
4225                "  hybrid-sleep                    Hibernate and suspend the system\n",
4226                program_invocation_short_name);
4227
4228         return 0;
4229 }
4230
4231 static int halt_help(void) {
4232
4233         printf("%s [OPTIONS...]\n\n"
4234                "%s the system.\n\n"
4235                "     --help      Show this help\n"
4236                "     --halt      Halt the machine\n"
4237                "  -p --poweroff  Switch off the machine\n"
4238                "     --reboot    Reboot the machine\n"
4239                "  -f --force     Force immediate halt/power-off/reboot\n"
4240                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4241                "  -d --no-wtmp   Don't write wtmp record\n"
4242                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4243                program_invocation_short_name,
4244                arg_action == ACTION_REBOOT   ? "Reboot" :
4245                arg_action == ACTION_POWEROFF ? "Power off" :
4246                                                "Halt");
4247
4248         return 0;
4249 }
4250
4251 static int shutdown_help(void) {
4252
4253         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4254                "Shut down the system.\n\n"
4255                "     --help      Show this help\n"
4256                "  -H --halt      Halt the machine\n"
4257                "  -P --poweroff  Power-off the machine\n"
4258                "  -r --reboot    Reboot the machine\n"
4259                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4260                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4261                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4262                "  -c             Cancel a pending shutdown\n",
4263                program_invocation_short_name);
4264
4265         return 0;
4266 }
4267
4268 static int telinit_help(void) {
4269
4270         printf("%s [OPTIONS...] {COMMAND}\n\n"
4271                "Send control commands to the init daemon.\n\n"
4272                "     --help      Show this help\n"
4273                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4274                "Commands:\n"
4275                "  0              Power-off the machine\n"
4276                "  6              Reboot the machine\n"
4277                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4278                "  1, s, S        Enter rescue mode\n"
4279                "  q, Q           Reload init daemon configuration\n"
4280                "  u, U           Reexecute init daemon\n",
4281                program_invocation_short_name);
4282
4283         return 0;
4284 }
4285
4286 static int runlevel_help(void) {
4287
4288         printf("%s [OPTIONS...]\n\n"
4289                "Prints the previous and current runlevel of the init system.\n\n"
4290                "     --help      Show this help\n",
4291                program_invocation_short_name);
4292
4293         return 0;
4294 }
4295
4296 static int help_types(void) {
4297         int i;
4298         const char *t;
4299
4300         puts("Available unit types:");
4301         for(i = 0; i < _UNIT_TYPE_MAX; i++) {
4302                 t = unit_type_to_string(i);
4303                 if (t)
4304                         puts(t);
4305         }
4306
4307         puts("\nAvailable unit load states: ");
4308         for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) {
4309                 t = unit_load_state_to_string(i);
4310                 if (t)
4311                         puts(t);
4312         }
4313
4314         return 0;
4315 }
4316
4317 static int systemctl_parse_argv(int argc, char *argv[]) {
4318
4319         enum {
4320                 ARG_FAIL = 0x100,
4321                 ARG_IRREVERSIBLE,
4322                 ARG_IGNORE_DEPENDENCIES,
4323                 ARG_VERSION,
4324                 ARG_USER,
4325                 ARG_SYSTEM,
4326                 ARG_GLOBAL,
4327                 ARG_NO_BLOCK,
4328                 ARG_NO_LEGEND,
4329                 ARG_NO_PAGER,
4330                 ARG_NO_WALL,
4331                 ARG_ROOT,
4332                 ARG_FULL,
4333                 ARG_NO_RELOAD,
4334                 ARG_KILL_WHO,
4335                 ARG_NO_ASK_PASSWORD,
4336                 ARG_FAILED,
4337                 ARG_RUNTIME,
4338                 ARG_FORCE
4339         };
4340
4341         static const struct option options[] = {
4342                 { "help",      no_argument,       NULL, 'h'           },
4343                 { "version",   no_argument,       NULL, ARG_VERSION   },
4344                 { "type",      required_argument, NULL, 't'           },
4345                 { "property",  required_argument, NULL, 'p'           },
4346                 { "all",       no_argument,       NULL, 'a'           },
4347                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4348                 { "full",      no_argument,       NULL, ARG_FULL      },
4349                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4350                 { "irreversible", no_argument,    NULL, ARG_IRREVERSIBLE },
4351                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4352                 { "ignore-inhibitors", no_argument, NULL, 'i'         },
4353                 { "user",      no_argument,       NULL, ARG_USER      },
4354                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4355                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4356                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4357                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4358                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4359                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4360                 { "quiet",     no_argument,       NULL, 'q'           },
4361                 { "root",      required_argument, NULL, ARG_ROOT      },
4362                 { "force",     no_argument,       NULL, ARG_FORCE     },
4363                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4364                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4365                 { "signal",    required_argument, NULL, 's'           },
4366                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4367                 { "host",      required_argument, NULL, 'H'           },
4368                 { "privileged",no_argument,       NULL, 'P'           },
4369                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4370                 { "lines",     required_argument, NULL, 'n'           },
4371                 { "output",    required_argument, NULL, 'o'           },
4372                 { NULL,        0,                 NULL, 0             }
4373         };
4374
4375         int c;
4376
4377         assert(argc >= 0);
4378         assert(argv);
4379
4380         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) {
4381
4382                 switch (c) {
4383
4384                 case 'h':
4385                         systemctl_help();
4386                         return 0;
4387
4388                 case ARG_VERSION:
4389                         puts(PACKAGE_STRING);
4390                         puts(SYSTEMD_FEATURES);
4391                         return 0;
4392
4393                 case 't':
4394                         if (streq(optarg, "help")) {
4395                                 help_types();
4396                                 return 0;
4397                         }
4398
4399                         if (unit_type_from_string(optarg) >= 0) {
4400                                 arg_type = optarg;
4401                                 break;
4402                         }
4403                         if (unit_load_state_from_string(optarg) >= 0) {
4404                                 arg_load_state = optarg;
4405                                 break;
4406                         }
4407                         log_error("Unkown unit type or load state '%s'.",
4408                                   optarg);
4409                         log_info("Use -t help to see a list of allowed values.");
4410                         return -EINVAL;
4411                 case 'p': {
4412                         char *word, *state;
4413                         size_t size;
4414                         /* Make sure that if the empty property list
4415                            was specified, we won't show any properties. */
4416                         const char *source = isempty(optarg) ? " " : optarg;
4417
4418                         FOREACH_WORD_SEPARATOR(word, size, source, ",", state) {
4419                                 char _cleanup_free_ *prop;
4420                                 char **tmp;
4421
4422                                 prop = strndup(word, size);
4423                                 if (!prop)
4424                                         return -ENOMEM;
4425
4426                                 tmp = strv_append(arg_property, prop);
4427                                 if (!tmp)
4428                                         return -ENOMEM;
4429
4430                                 strv_free(arg_property);
4431                                 arg_property = tmp;
4432                         }
4433
4434                         /* If the user asked for a particular
4435                          * property, show it to him, even if it is
4436                          * empty. */
4437                         arg_all = true;
4438
4439                         break;
4440                 }
4441
4442                 case 'a':
4443                         arg_all = true;
4444                         break;
4445
4446                 case ARG_FAIL:
4447                         arg_job_mode = "fail";
4448                         break;
4449
4450                 case ARG_IRREVERSIBLE:
4451                         arg_job_mode = "replace-irreversibly";
4452                         break;
4453
4454                 case ARG_IGNORE_DEPENDENCIES:
4455                         arg_job_mode = "ignore-dependencies";
4456                         break;
4457
4458                 case ARG_USER:
4459                         arg_scope = UNIT_FILE_USER;
4460                         break;
4461
4462                 case ARG_SYSTEM:
4463                         arg_scope = UNIT_FILE_SYSTEM;
4464                         break;
4465
4466                 case ARG_GLOBAL:
4467                         arg_scope = UNIT_FILE_GLOBAL;
4468                         break;
4469
4470                 case ARG_NO_BLOCK:
4471                         arg_no_block = true;
4472                         break;
4473
4474                 case ARG_NO_LEGEND:
4475                         arg_no_legend = true;
4476                         break;
4477
4478                 case ARG_NO_PAGER:
4479                         arg_no_pager = true;
4480                         break;
4481
4482                 case ARG_NO_WALL:
4483                         arg_no_wall = true;
4484                         break;
4485
4486                 case ARG_ROOT:
4487                         arg_root = optarg;
4488                         break;
4489
4490                 case ARG_FULL:
4491                         arg_full = true;
4492                         break;
4493
4494                 case ARG_FAILED:
4495                         arg_failed = true;
4496                         break;
4497
4498                 case 'q':
4499                         arg_quiet = true;
4500                         break;
4501
4502                 case ARG_FORCE:
4503                         arg_force ++;
4504                         break;
4505
4506                 case 'f':
4507                         arg_force ++;
4508                         break;
4509
4510                 case ARG_NO_RELOAD:
4511                         arg_no_reload = true;
4512                         break;
4513
4514                 case ARG_KILL_WHO:
4515                         arg_kill_who = optarg;
4516                         break;
4517
4518                 case 's':
4519                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4520                                 log_error("Failed to parse signal string %s.", optarg);
4521                                 return -EINVAL;
4522                         }
4523                         break;
4524
4525                 case ARG_NO_ASK_PASSWORD:
4526                         arg_ask_password = false;
4527                         break;
4528
4529                 case 'P':
4530                         arg_transport = TRANSPORT_POLKIT;
4531                         break;
4532
4533                 case 'H':
4534                         arg_transport = TRANSPORT_SSH;
4535                         arg_host = optarg;
4536                         break;
4537
4538                 case ARG_RUNTIME:
4539                         arg_runtime = true;
4540                         break;
4541
4542                 case 'n':
4543                         if (safe_atou(optarg, &arg_lines) < 0) {
4544                                 log_error("Failed to parse lines '%s'", optarg);
4545                                 return -EINVAL;
4546                         }
4547                         break;
4548
4549                 case 'o':
4550                         arg_output = output_mode_from_string(optarg);
4551                         if (arg_output < 0) {
4552                                 log_error("Unknown output '%s'.", optarg);
4553                                 return -EINVAL;
4554                         }
4555                         break;
4556
4557                 case 'i':
4558                         arg_ignore_inhibitors = true;
4559                         break;
4560
4561                 case '?':
4562                         return -EINVAL;
4563
4564                 default:
4565                         log_error("Unknown option code '%c'.", c);
4566                         return -EINVAL;
4567                 }
4568         }
4569
4570         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4571                 log_error("Cannot access user instance remotely.");
4572                 return -EINVAL;
4573         }
4574
4575         return 1;
4576 }
4577
4578 static int halt_parse_argv(int argc, char *argv[]) {
4579
4580         enum {
4581                 ARG_HELP = 0x100,
4582                 ARG_HALT,
4583                 ARG_REBOOT,
4584                 ARG_NO_WALL
4585         };
4586
4587         static const struct option options[] = {
4588                 { "help",      no_argument,       NULL, ARG_HELP    },
4589                 { "halt",      no_argument,       NULL, ARG_HALT    },
4590                 { "poweroff",  no_argument,       NULL, 'p'         },
4591                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4592                 { "force",     no_argument,       NULL, 'f'         },
4593                 { "wtmp-only", no_argument,       NULL, 'w'         },
4594                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4595                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4596                 { NULL,        0,                 NULL, 0           }
4597         };
4598
4599         int c, runlevel;
4600
4601         assert(argc >= 0);
4602         assert(argv);
4603
4604         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4605                 if (runlevel == '0' || runlevel == '6')
4606                         arg_force = 2;
4607
4608         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4609                 switch (c) {
4610
4611                 case ARG_HELP:
4612                         halt_help();
4613                         return 0;
4614
4615                 case ARG_HALT:
4616                         arg_action = ACTION_HALT;
4617                         break;
4618
4619                 case 'p':
4620                         if (arg_action != ACTION_REBOOT)
4621                                 arg_action = ACTION_POWEROFF;
4622                         break;
4623
4624                 case ARG_REBOOT:
4625                         arg_action = ACTION_REBOOT;
4626                         break;
4627
4628                 case 'f':
4629                         arg_force = 2;
4630                         break;
4631
4632                 case 'w':
4633                         arg_dry = true;
4634                         break;
4635
4636                 case 'd':
4637                         arg_no_wtmp = true;
4638                         break;
4639
4640                 case ARG_NO_WALL:
4641                         arg_no_wall = true;
4642                         break;
4643
4644                 case 'i':
4645                 case 'h':
4646                 case 'n':
4647                         /* Compatibility nops */
4648                         break;
4649
4650                 case '?':
4651                         return -EINVAL;
4652
4653                 default:
4654                         log_error("Unknown option code '%c'.", c);
4655                         return -EINVAL;
4656                 }
4657         }
4658
4659         if (optind < argc) {
4660                 log_error("Too many arguments.");
4661                 return -EINVAL;
4662         }
4663
4664         return 1;
4665 }
4666
4667 static int parse_time_spec(const char *t, usec_t *_u) {
4668         assert(t);
4669         assert(_u);
4670
4671         if (streq(t, "now"))
4672                 *_u = 0;
4673         else if (!strchr(t, ':')) {
4674                 uint64_t u;
4675
4676                 if (safe_atou64(t, &u) < 0)
4677                         return -EINVAL;
4678
4679                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4680         } else {
4681                 char *e = NULL;
4682                 long hour, minute;
4683                 struct tm tm;
4684                 time_t s;
4685                 usec_t n;
4686
4687                 errno = 0;
4688                 hour = strtol(t, &e, 10);
4689                 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
4690                         return -EINVAL;
4691
4692                 minute = strtol(e+1, &e, 10);
4693                 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
4694                         return -EINVAL;
4695
4696                 n = now(CLOCK_REALTIME);
4697                 s = (time_t) (n / USEC_PER_SEC);
4698
4699                 zero(tm);
4700                 assert_se(localtime_r(&s, &tm));
4701
4702                 tm.tm_hour = (int) hour;
4703                 tm.tm_min = (int) minute;
4704                 tm.tm_sec = 0;
4705
4706                 assert_se(s = mktime(&tm));
4707
4708                 *_u = (usec_t) s * USEC_PER_SEC;
4709
4710                 while (*_u <= n)
4711                         *_u += USEC_PER_DAY;
4712         }
4713
4714         return 0;
4715 }
4716
4717 static int shutdown_parse_argv(int argc, char *argv[]) {
4718
4719         enum {
4720                 ARG_HELP = 0x100,
4721                 ARG_NO_WALL
4722         };
4723
4724         static const struct option options[] = {
4725                 { "help",      no_argument,       NULL, ARG_HELP    },
4726                 { "halt",      no_argument,       NULL, 'H'         },
4727                 { "poweroff",  no_argument,       NULL, 'P'         },
4728                 { "reboot",    no_argument,       NULL, 'r'         },
4729                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4730                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4731                 { NULL,        0,                 NULL, 0           }
4732         };
4733
4734         int c, r;
4735
4736         assert(argc >= 0);
4737         assert(argv);
4738
4739         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4740                 switch (c) {
4741
4742                 case ARG_HELP:
4743                         shutdown_help();
4744                         return 0;
4745
4746                 case 'H':
4747                         arg_action = ACTION_HALT;
4748                         break;
4749
4750                 case 'P':
4751                         arg_action = ACTION_POWEROFF;
4752                         break;
4753
4754                 case 'r':
4755                         if (kexec_loaded())
4756                                 arg_action = ACTION_KEXEC;
4757                         else
4758                                 arg_action = ACTION_REBOOT;
4759                         break;
4760
4761                 case 'K':
4762                         arg_action = ACTION_KEXEC;
4763                         break;
4764
4765                 case 'h':
4766                         if (arg_action != ACTION_HALT)
4767                                 arg_action = ACTION_POWEROFF;
4768                         break;
4769
4770                 case 'k':
4771                         arg_dry = true;
4772                         break;
4773
4774                 case ARG_NO_WALL:
4775                         arg_no_wall = true;
4776                         break;
4777
4778                 case 't':
4779                 case 'a':
4780                         /* Compatibility nops */
4781                         break;
4782
4783                 case 'c':
4784                         arg_action = ACTION_CANCEL_SHUTDOWN;
4785                         break;
4786
4787                 case '?':
4788                         return -EINVAL;
4789
4790                 default:
4791                         log_error("Unknown option code '%c'.", c);
4792                         return -EINVAL;
4793                 }
4794         }
4795
4796         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4797                 r = parse_time_spec(argv[optind], &arg_when);
4798                 if (r < 0) {
4799                         log_error("Failed to parse time specification: %s", argv[optind]);
4800                         return r;
4801                 }
4802         } else
4803                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4804
4805         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4806                 /* No time argument for shutdown cancel */
4807                 arg_wall = argv + optind;
4808         else if (argc > optind + 1)
4809                 /* We skip the time argument */
4810                 arg_wall = argv + optind + 1;
4811
4812         optind = argc;
4813
4814         return 1;
4815 }
4816
4817 static int telinit_parse_argv(int argc, char *argv[]) {
4818
4819         enum {
4820                 ARG_HELP = 0x100,
4821                 ARG_NO_WALL
4822         };
4823
4824         static const struct option options[] = {
4825                 { "help",      no_argument,       NULL, ARG_HELP    },
4826                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4827                 { NULL,        0,                 NULL, 0           }
4828         };
4829
4830         static const struct {
4831                 char from;
4832                 enum action to;
4833         } table[] = {
4834                 { '0', ACTION_POWEROFF },
4835                 { '6', ACTION_REBOOT },
4836                 { '1', ACTION_RESCUE },
4837                 { '2', ACTION_RUNLEVEL2 },
4838                 { '3', ACTION_RUNLEVEL3 },
4839                 { '4', ACTION_RUNLEVEL4 },
4840                 { '5', ACTION_RUNLEVEL5 },
4841                 { 's', ACTION_RESCUE },
4842                 { 'S', ACTION_RESCUE },
4843                 { 'q', ACTION_RELOAD },
4844                 { 'Q', ACTION_RELOAD },
4845                 { 'u', ACTION_REEXEC },
4846                 { 'U', ACTION_REEXEC }
4847         };
4848
4849         unsigned i;
4850         int c;
4851
4852         assert(argc >= 0);
4853         assert(argv);
4854
4855         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4856                 switch (c) {
4857
4858                 case ARG_HELP:
4859                         telinit_help();
4860                         return 0;
4861
4862                 case ARG_NO_WALL:
4863                         arg_no_wall = true;
4864                         break;
4865
4866                 case '?':
4867                         return -EINVAL;
4868
4869                 default:
4870                         log_error("Unknown option code '%c'.", c);
4871                         return -EINVAL;
4872                 }
4873         }
4874
4875         if (optind >= argc) {
4876                 telinit_help();
4877                 return -EINVAL;
4878         }
4879
4880         if (optind + 1 < argc) {
4881                 log_error("Too many arguments.");
4882                 return -EINVAL;
4883         }
4884
4885         if (strlen(argv[optind]) != 1) {
4886                 log_error("Expected single character argument.");
4887                 return -EINVAL;
4888         }
4889
4890         for (i = 0; i < ELEMENTSOF(table); i++)
4891                 if (table[i].from == argv[optind][0])
4892                         break;
4893
4894         if (i >= ELEMENTSOF(table)) {
4895                 log_error("Unknown command '%s'.", argv[optind]);
4896                 return -EINVAL;
4897         }
4898
4899         arg_action = table[i].to;
4900
4901         optind ++;
4902
4903         return 1;
4904 }
4905
4906 static int runlevel_parse_argv(int argc, char *argv[]) {
4907
4908         enum {
4909                 ARG_HELP = 0x100,
4910         };
4911
4912         static const struct option options[] = {
4913                 { "help",      no_argument,       NULL, ARG_HELP    },
4914                 { NULL,        0,                 NULL, 0           }
4915         };
4916
4917         int c;
4918
4919         assert(argc >= 0);
4920         assert(argv);
4921
4922         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4923                 switch (c) {
4924
4925                 case ARG_HELP:
4926                         runlevel_help();
4927                         return 0;
4928
4929                 case '?':
4930                         return -EINVAL;
4931
4932                 default:
4933                         log_error("Unknown option code '%c'.", c);
4934                         return -EINVAL;
4935                 }
4936         }
4937
4938         if (optind < argc) {
4939                 log_error("Too many arguments.");
4940                 return -EINVAL;
4941         }
4942
4943         return 1;
4944 }
4945
4946 static int parse_argv(int argc, char *argv[]) {
4947         assert(argc >= 0);
4948         assert(argv);
4949
4950         if (program_invocation_short_name) {
4951
4952                 if (strstr(program_invocation_short_name, "halt")) {
4953                         arg_action = ACTION_HALT;
4954                         return halt_parse_argv(argc, argv);
4955                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4956                         arg_action = ACTION_POWEROFF;
4957                         return halt_parse_argv(argc, argv);
4958                 } else if (strstr(program_invocation_short_name, "reboot")) {
4959                         if (kexec_loaded())
4960                                 arg_action = ACTION_KEXEC;
4961                         else
4962                                 arg_action = ACTION_REBOOT;
4963                         return halt_parse_argv(argc, argv);
4964                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4965                         arg_action = ACTION_POWEROFF;
4966                         return shutdown_parse_argv(argc, argv);
4967                 } else if (strstr(program_invocation_short_name, "init")) {
4968
4969                         if (sd_booted() > 0) {
4970                                 arg_action = ACTION_INVALID;
4971                                 return telinit_parse_argv(argc, argv);
4972                         } else {
4973                                 /* Hmm, so some other init system is
4974                                  * running, we need to forward this
4975                                  * request to it. For now we simply
4976                                  * guess that it is Upstart. */
4977
4978                                 execv(TELINIT, argv);
4979
4980                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4981                                 return -EIO;
4982                         }
4983
4984                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4985                         arg_action = ACTION_RUNLEVEL;
4986                         return runlevel_parse_argv(argc, argv);
4987                 }
4988         }
4989
4990         arg_action = ACTION_SYSTEMCTL;
4991         return systemctl_parse_argv(argc, argv);
4992 }
4993
4994 static int action_to_runlevel(void) {
4995
4996         static const char table[_ACTION_MAX] = {
4997                 [ACTION_HALT] =      '0',
4998                 [ACTION_POWEROFF] =  '0',
4999                 [ACTION_REBOOT] =    '6',
5000                 [ACTION_RUNLEVEL2] = '2',
5001                 [ACTION_RUNLEVEL3] = '3',
5002                 [ACTION_RUNLEVEL4] = '4',
5003                 [ACTION_RUNLEVEL5] = '5',
5004                 [ACTION_RESCUE] =    '1'
5005         };
5006
5007         assert(arg_action < _ACTION_MAX);
5008
5009         return table[arg_action];
5010 }
5011
5012 static int talk_upstart(void) {
5013         DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
5014         DBusError _cleanup_dbus_error_free_ error;
5015         int previous, rl, r;
5016         char
5017                 env1_buf[] = "RUNLEVEL=X",
5018                 env2_buf[] = "PREVLEVEL=X";
5019         char *env1 = env1_buf, *env2 = env2_buf;
5020         const char *emit = "runlevel";
5021         dbus_bool_t b_false = FALSE;
5022         DBusMessageIter iter, sub;
5023         DBusConnection *bus;
5024
5025         dbus_error_init(&error);
5026
5027         if (!(rl = action_to_runlevel()))
5028                 return 0;
5029
5030         if (utmp_get_runlevel(&previous, NULL) < 0)
5031                 previous = 'N';
5032
5033         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5034                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5035                         r = 0;
5036                         goto finish;
5037                 }
5038
5039                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5040                 r = -EIO;
5041                 goto finish;
5042         }
5043
5044         if ((r = bus_check_peercred(bus)) < 0) {
5045                 log_error("Failed to verify owner of bus.");
5046                 goto finish;
5047         }
5048
5049         if (!(m = dbus_message_new_method_call(
5050                               "com.ubuntu.Upstart",
5051                               "/com/ubuntu/Upstart",
5052                               "com.ubuntu.Upstart0_6",
5053                               "EmitEvent"))) {
5054
5055                 log_error("Could not allocate message.");
5056                 r = -ENOMEM;
5057                 goto finish;
5058         }
5059
5060         dbus_message_iter_init_append(m, &iter);
5061
5062         env1_buf[sizeof(env1_buf)-2] = rl;
5063         env2_buf[sizeof(env2_buf)-2] = previous;
5064
5065         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5066             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5067             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5068             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5069             !dbus_message_iter_close_container(&iter, &sub) ||
5070             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5071                 log_error("Could not append arguments to message.");
5072                 r = -ENOMEM;
5073                 goto finish;
5074         }
5075
5076         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5077
5078                 if (bus_error_is_no_service(&error)) {
5079                         r = -EADDRNOTAVAIL;
5080                         goto finish;
5081                 }
5082
5083                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5084                 r = -EIO;
5085                 goto finish;
5086         }
5087
5088         r = 1;
5089
5090 finish:
5091         if (bus) {
5092                 dbus_connection_flush(bus);
5093                 dbus_connection_close(bus);
5094                 dbus_connection_unref(bus);
5095         }
5096
5097         return r;
5098 }
5099
5100 static int talk_initctl(void) {
5101         struct init_request request = {0};
5102         int r;
5103         int _cleanup_close_ fd = -1;
5104         char rl;
5105
5106         rl = action_to_runlevel();
5107         if (!rl)
5108                 return 0;
5109
5110         request.magic = INIT_MAGIC;
5111         request.sleeptime = 0;
5112         request.cmd = INIT_CMD_RUNLVL;
5113         request.runlevel = rl;
5114
5115         fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5116         if (fd < 0) {
5117                 if (errno == ENOENT)
5118                         return 0;
5119
5120                 log_error("Failed to open "INIT_FIFO": %m");
5121                 return -errno;
5122         }
5123
5124         errno = 0;
5125         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5126         if (r) {
5127                 log_error("Failed to write to "INIT_FIFO": %m");
5128                 return errno ? -errno : -EIO;
5129         }
5130
5131         return 1;
5132 }
5133
5134 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5135
5136         static const struct {
5137                 const char* verb;
5138                 const enum {
5139                         MORE,
5140                         LESS,
5141                         EQUAL
5142                 } argc_cmp;
5143                 const int argc;
5144                 int (* const dispatch)(DBusConnection *bus, char **args);
5145         } verbs[] = {
5146                 { "list-units",            LESS,  1, list_units        },
5147                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5148                 { "list-jobs",             EQUAL, 1, list_jobs         },
5149                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5150                 { "load",                  MORE,  2, load_unit         },
5151                 { "cancel",                MORE,  2, cancel_job        },
5152                 { "start",                 MORE,  2, start_unit        },
5153                 { "stop",                  MORE,  2, start_unit        },
5154                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5155                 { "reload",                MORE,  2, start_unit        },
5156                 { "restart",               MORE,  2, start_unit        },
5157                 { "try-restart",           MORE,  2, start_unit        },
5158                 { "reload-or-restart",     MORE,  2, start_unit        },
5159                 { "reload-or-try-restart", MORE,  2, start_unit        },
5160                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5161                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5162                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5163                 { "isolate",               EQUAL, 2, start_unit        },
5164                 { "set-cgroup",            MORE,  3, set_cgroup        },
5165                 { "unset-cgroup",          MORE,  3, set_cgroup        },
5166                 { "get-cgroup-attr",       MORE,  3, get_cgroup_attr   },
5167                 { "set-cgroup-attr",       MORE,  4, set_cgroup_attr   },
5168                 { "unset-cgroup-attr",     MORE,  3, set_cgroup        },
5169                 { "kill",                  MORE,  2, kill_unit         },
5170                 { "is-active",             MORE,  2, check_unit_active },
5171                 { "check",                 MORE,  2, check_unit_active },
5172                 { "is-failed",             MORE,  2, check_unit_failed },
5173                 { "show",                  MORE,  1, show              },
5174                 { "status",                MORE,  1, show              },
5175                 { "help",                  MORE,  2, show              },
5176                 { "dump",                  EQUAL, 1, dump              },
5177                 { "snapshot",              LESS,  2, snapshot          },
5178                 { "delete",                MORE,  2, delete_snapshot   },
5179                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5180                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5181                 { "show-environment",      EQUAL, 1, show_enviroment   },
5182                 { "set-environment",       MORE,  2, set_environment   },
5183                 { "unset-environment",     MORE,  2, set_environment   },
5184                 { "halt",                  EQUAL, 1, start_special     },
5185                 { "poweroff",              EQUAL, 1, start_special     },
5186                 { "reboot",                EQUAL, 1, start_special     },
5187                 { "kexec",                 EQUAL, 1, start_special     },
5188                 { "suspend",               EQUAL, 1, start_special     },
5189                 { "hibernate",             EQUAL, 1, start_special     },
5190                 { "hybrid-sleep",          EQUAL, 1, start_special     },
5191                 { "default",               EQUAL, 1, start_special     },
5192                 { "rescue",                EQUAL, 1, start_special     },
5193                 { "emergency",             EQUAL, 1, start_special     },
5194                 { "exit",                  EQUAL, 1, start_special     },
5195                 { "reset-failed",          MORE,  1, reset_failed      },
5196                 { "enable",                MORE,  2, enable_unit       },
5197                 { "disable",               MORE,  2, enable_unit       },
5198                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5199                 { "reenable",              MORE,  2, enable_unit       },
5200                 { "preset",                MORE,  2, enable_unit       },
5201                 { "mask",                  MORE,  2, enable_unit       },
5202                 { "unmask",                MORE,  2, enable_unit       },
5203                 { "link",                  MORE,  2, enable_unit       },
5204                 { "switch-root",           MORE,  2, switch_root       },
5205                 { "list-dependencies",     LESS,  2, list_dependencies },
5206         };
5207
5208         int left;
5209         unsigned i;
5210
5211         assert(argc >= 0);
5212         assert(argv);
5213         assert(error);
5214
5215         left = argc - optind;
5216
5217         if (left <= 0)
5218                 /* Special rule: no arguments means "list-units" */
5219                 i = 0;
5220         else {
5221                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5222                         log_error("This command expects one or more "
5223                                   "unit names. Did you mean --help?");
5224                         return -EINVAL;
5225                 }
5226
5227                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5228                         if (streq(argv[optind], verbs[i].verb))
5229                                 break;
5230
5231                 if (i >= ELEMENTSOF(verbs)) {
5232                         log_error("Unknown operation '%s'.", argv[optind]);
5233                         return -EINVAL;
5234                 }
5235         }
5236
5237         switch (verbs[i].argc_cmp) {
5238
5239         case EQUAL:
5240                 if (left != verbs[i].argc) {
5241                         log_error("Invalid number of arguments.");
5242                         return -EINVAL;
5243                 }
5244
5245                 break;
5246
5247         case MORE:
5248                 if (left < verbs[i].argc) {
5249                         log_error("Too few arguments.");
5250                         return -EINVAL;
5251                 }
5252
5253                 break;
5254
5255         case LESS:
5256                 if (left > verbs[i].argc) {
5257                         log_error("Too many arguments.");
5258                         return -EINVAL;
5259                 }
5260
5261                 break;
5262
5263         default:
5264                 assert_not_reached("Unknown comparison operator.");
5265         }
5266
5267         /* Require a bus connection for all operations but
5268          * enable/disable */
5269         if (!streq(verbs[i].verb, "enable") &&
5270             !streq(verbs[i].verb, "disable") &&
5271             !streq(verbs[i].verb, "is-enabled") &&
5272             !streq(verbs[i].verb, "list-unit-files") &&
5273             !streq(verbs[i].verb, "reenable") &&
5274             !streq(verbs[i].verb, "preset") &&
5275             !streq(verbs[i].verb, "mask") &&
5276             !streq(verbs[i].verb, "unmask") &&
5277             !streq(verbs[i].verb, "link")) {
5278
5279                 if (running_in_chroot() > 0) {
5280                         log_info("Running in chroot, ignoring request.");
5281                         return 0;
5282                 }
5283
5284                 if (((!streq(verbs[i].verb, "reboot") &&
5285                       !streq(verbs[i].verb, "halt") &&
5286                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5287                         log_error("Failed to get D-Bus connection: %s",
5288                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5289                         return -EIO;
5290                 }
5291
5292         } else {
5293
5294                 if (!bus && !avoid_bus()) {
5295                         log_error("Failed to get D-Bus connection: %s",
5296                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5297                         return -EIO;
5298                 }
5299         }
5300
5301         return verbs[i].dispatch(bus, argv + optind);
5302 }
5303
5304 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5305         int _cleanup_close_ fd;
5306         struct msghdr msghdr;
5307         struct iovec iovec[2];
5308         union sockaddr_union sockaddr;
5309         struct sd_shutdown_command c;
5310
5311         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5312         if (fd < 0)
5313                 return -errno;
5314
5315         zero(c);
5316         c.usec = t;
5317         c.mode = mode;
5318         c.dry_run = dry_run;
5319         c.warn_wall = warn;
5320
5321         zero(sockaddr);
5322         sockaddr.sa.sa_family = AF_UNIX;
5323         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5324
5325         zero(msghdr);
5326         msghdr.msg_name = &sockaddr;
5327         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5328
5329         zero(iovec);
5330         iovec[0].iov_base = (char*) &c;
5331         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5332
5333         if (isempty(message))
5334                 msghdr.msg_iovlen = 1;
5335         else {
5336                 iovec[1].iov_base = (char*) message;
5337                 iovec[1].iov_len = strlen(message);
5338                 msghdr.msg_iovlen = 2;
5339         }
5340         msghdr.msg_iov = iovec;
5341
5342         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
5343                 return -errno;
5344
5345         return 0;
5346 }
5347
5348 static int reload_with_fallback(DBusConnection *bus) {
5349
5350         if (bus) {
5351                 /* First, try systemd via D-Bus. */
5352                 if (daemon_reload(bus, NULL) >= 0)
5353                         return 0;
5354         }
5355
5356         /* Nothing else worked, so let's try signals */
5357         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5358
5359         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5360                 log_error("kill() failed: %m");
5361                 return -errno;
5362         }
5363
5364         return 0;
5365 }
5366
5367 static int start_with_fallback(DBusConnection *bus) {
5368
5369         if (bus) {
5370                 /* First, try systemd via D-Bus. */
5371                 if (start_unit(bus, NULL) >= 0)
5372                         goto done;
5373         }
5374
5375         /* Hmm, talking to systemd via D-Bus didn't work. Then
5376          * let's try to talk to Upstart via D-Bus. */
5377         if (talk_upstart() > 0)
5378                 goto done;
5379
5380         /* Nothing else worked, so let's try
5381          * /dev/initctl */
5382         if (talk_initctl() > 0)
5383                 goto done;
5384
5385         log_error("Failed to talk to init daemon.");
5386         return -EIO;
5387
5388 done:
5389         warn_wall(arg_action);
5390         return 0;
5391 }
5392
5393 static _noreturn_ void halt_now(enum action a) {
5394
5395        /* Make sure C-A-D is handled by the kernel from this
5396          * point on... */
5397         reboot(RB_ENABLE_CAD);
5398
5399         switch (a) {
5400
5401         case ACTION_HALT:
5402                 log_info("Halting.");
5403                 reboot(RB_HALT_SYSTEM);
5404                 break;
5405
5406         case ACTION_POWEROFF:
5407                 log_info("Powering off.");
5408                 reboot(RB_POWER_OFF);
5409                 break;
5410
5411         case ACTION_REBOOT:
5412                 log_info("Rebooting.");
5413                 reboot(RB_AUTOBOOT);
5414                 break;
5415
5416         default:
5417                 assert_not_reached("Unknown halt action.");
5418         }
5419
5420         assert_not_reached("Uh? This shouldn't happen.");
5421 }
5422
5423 static int halt_main(DBusConnection *bus) {
5424         int r;
5425
5426         r = check_inhibitors(bus, arg_action);
5427         if (r < 0)
5428                 return r;
5429
5430         if (geteuid() != 0) {
5431                 /* Try logind if we are a normal user and no special
5432                  * mode applies. Maybe PolicyKit allows us to shutdown
5433                  * the machine. */
5434
5435                 if (arg_when <= 0 &&
5436                     !arg_dry &&
5437                     arg_force <= 0 &&
5438                     (arg_action == ACTION_POWEROFF ||
5439                      arg_action == ACTION_REBOOT)) {
5440                         r = reboot_with_logind(bus, arg_action);
5441                         if (r >= 0)
5442                                 return r;
5443                 }
5444
5445                 log_error("Must be root.");
5446                 return -EPERM;
5447         }
5448
5449         if (arg_when > 0) {
5450                 char _cleanup_free_ *m;
5451
5452                 m = strv_join(arg_wall, " ");
5453                 r = send_shutdownd(arg_when,
5454                                    arg_action == ACTION_HALT     ? 'H' :
5455                                    arg_action == ACTION_POWEROFF ? 'P' :
5456                                    arg_action == ACTION_KEXEC    ? 'K' :
5457                                                                    'r',
5458                                    arg_dry,
5459                                    !arg_no_wall,
5460                                    m);
5461
5462                 if (r < 0)
5463                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5464                 else {
5465                         char date[FORMAT_TIMESTAMP_MAX];
5466
5467                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5468                                  format_timestamp(date, sizeof(date), arg_when));
5469                         return 0;
5470                 }
5471         }
5472
5473         if (!arg_dry && !arg_force)
5474                 return start_with_fallback(bus);
5475
5476         if (!arg_no_wtmp) {
5477                 if (sd_booted() > 0)
5478                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5479                 else {
5480                         r = utmp_put_shutdown();
5481                         if (r < 0)
5482                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5483                 }
5484         }
5485
5486         if (arg_dry)
5487                 return 0;
5488
5489         halt_now(arg_action);
5490         /* We should never reach this. */
5491         return -ENOSYS;
5492 }
5493
5494 static int runlevel_main(void) {
5495         int r, runlevel, previous;
5496
5497         r = utmp_get_runlevel(&runlevel, &previous);
5498         if (r < 0) {
5499                 puts("unknown");
5500                 return r;
5501         }
5502
5503         printf("%c %c\n",
5504                previous <= 0 ? 'N' : previous,
5505                runlevel <= 0 ? 'N' : runlevel);
5506
5507         return 0;
5508 }
5509
5510 int main(int argc, char*argv[]) {
5511         int r, retval = EXIT_FAILURE;
5512         DBusConnection *bus = NULL;
5513         DBusError _cleanup_dbus_error_free_ error;
5514
5515         dbus_error_init(&error);
5516
5517         setlocale(LC_ALL, "");
5518         log_parse_environment();
5519         log_open();
5520
5521         r = parse_argv(argc, argv);
5522         if (r < 0)
5523                 goto finish;
5524         else if (r == 0) {
5525                 retval = EXIT_SUCCESS;
5526                 goto finish;
5527         }
5528
5529         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5530          * let's shortcut this */
5531         if (arg_action == ACTION_RUNLEVEL) {
5532                 r = runlevel_main();
5533                 retval = r < 0 ? EXIT_FAILURE : r;
5534                 goto finish;
5535         }
5536
5537         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5538                 log_info("Running in chroot, ignoring request.");
5539                 retval = 0;
5540                 goto finish;
5541         }
5542
5543         if (!avoid_bus()) {
5544                 if (arg_transport == TRANSPORT_NORMAL)
5545                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5546                 else if (arg_transport == TRANSPORT_POLKIT) {
5547                         bus_connect_system_polkit(&bus, &error);
5548                         private_bus = false;
5549                 } else if (arg_transport == TRANSPORT_SSH) {
5550                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5551                         private_bus = false;
5552                 } else
5553                         assert_not_reached("Uh, invalid transport...");
5554         }
5555
5556         switch (arg_action) {
5557
5558         case ACTION_SYSTEMCTL:
5559                 r = systemctl_main(bus, argc, argv, &error);
5560                 break;
5561
5562         case ACTION_HALT:
5563         case ACTION_POWEROFF:
5564         case ACTION_REBOOT:
5565         case ACTION_KEXEC:
5566                 r = halt_main(bus);
5567                 break;
5568
5569         case ACTION_RUNLEVEL2:
5570         case ACTION_RUNLEVEL3:
5571         case ACTION_RUNLEVEL4:
5572         case ACTION_RUNLEVEL5:
5573         case ACTION_RESCUE:
5574         case ACTION_EMERGENCY:
5575         case ACTION_DEFAULT:
5576                 r = start_with_fallback(bus);
5577                 break;
5578
5579         case ACTION_RELOAD:
5580         case ACTION_REEXEC:
5581                 r = reload_with_fallback(bus);
5582                 break;
5583
5584         case ACTION_CANCEL_SHUTDOWN: {
5585                 char *m = NULL;
5586
5587                 if (arg_wall) {
5588                         m = strv_join(arg_wall, " ");
5589                         if (!m) {
5590                                 retval = EXIT_FAILURE;
5591                                 goto finish;
5592                         }
5593                 }
5594                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5595                 if (r < 0)
5596                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5597                 free(m);
5598                 break;
5599         }
5600
5601         case ACTION_INVALID:
5602         case ACTION_RUNLEVEL:
5603         default:
5604                 assert_not_reached("Unknown action");
5605         }
5606
5607         retval = r < 0 ? EXIT_FAILURE : r;
5608
5609 finish:
5610         if (bus) {
5611                 dbus_connection_flush(bus);
5612                 dbus_connection_close(bus);
5613                 dbus_connection_unref(bus);
5614         }
5615
5616         dbus_shutdown();
5617
5618         strv_free(arg_property);
5619
5620         pager_close();
5621         ask_password_agent_close();
5622         polkit_agent_close();
5623
5624         return retval;
5625 }