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