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