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