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