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