chiark / gitweb /
4e33a4182f219e1bc9cdf7972da0b516faacf231
[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 snapshot(DBusConnection *bus, char **args) {
3801         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3802         DBusError error;
3803         int r;
3804         dbus_bool_t cleanup = FALSE;
3805         DBusMessageIter iter, sub;
3806         const char
3807                 *path, *id,
3808                 *interface = "org.freedesktop.systemd1.Unit",
3809                 *property = "Id";
3810         _cleanup_free_ char *n = NULL;
3811
3812         dbus_error_init(&error);
3813
3814         if (strv_length(args) > 1)
3815                 n = unit_name_mangle_with_suffix(args[1], ".snapshot");
3816         else
3817                 n = strdup("");
3818         if (!n)
3819                 return log_oom();
3820
3821         r = bus_method_call_with_reply(
3822                         bus,
3823                         "org.freedesktop.systemd1",
3824                         "/org/freedesktop/systemd1",
3825                         "org.freedesktop.systemd1.Manager",
3826                         "CreateSnapshot",
3827                         &reply,
3828                         NULL,
3829                         DBUS_TYPE_STRING, &n,
3830                         DBUS_TYPE_BOOLEAN, &cleanup,
3831                         DBUS_TYPE_INVALID);
3832         if (r < 0)
3833                 return r;
3834
3835         if (!dbus_message_get_args(reply, &error,
3836                                    DBUS_TYPE_OBJECT_PATH, &path,
3837                                    DBUS_TYPE_INVALID)) {
3838                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3839                 dbus_error_free(&error);
3840                 return -EIO;
3841         }
3842
3843         dbus_message_unref(reply);
3844         reply = NULL;
3845
3846         r = bus_method_call_with_reply (
3847                         bus,
3848                         "org.freedesktop.systemd1",
3849                         path,
3850                         "org.freedesktop.DBus.Properties",
3851                         "Get",
3852                         &reply,
3853                         NULL,
3854                         DBUS_TYPE_STRING, &interface,
3855                         DBUS_TYPE_STRING, &property,
3856                         DBUS_TYPE_INVALID);
3857         if (r < 0)
3858                 return r;
3859
3860         if (!dbus_message_iter_init(reply, &iter) ||
3861             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3862                 log_error("Failed to parse reply.");
3863                 return -EIO;
3864         }
3865
3866         dbus_message_iter_recurse(&iter, &sub);
3867
3868         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3869                 log_error("Failed to parse reply.");
3870                 return -EIO;
3871         }
3872
3873         dbus_message_iter_get_basic(&sub, &id);
3874
3875         if (!arg_quiet)
3876                 puts(id);
3877
3878         return 0;
3879 }
3880
3881 static int delete_snapshot(DBusConnection *bus, char **args) {
3882         char **name;
3883
3884         assert(args);
3885
3886         STRV_FOREACH(name, args+1) {
3887                 _cleanup_free_ char *n = NULL;
3888                 int r;
3889
3890                 n = unit_name_mangle_with_suffix(*name, ".snapshot");
3891                 if (!n)
3892                         return log_oom();
3893
3894                 r = bus_method_call_with_reply(
3895                                 bus,
3896                                 "org.freedesktop.systemd1",
3897                                 "/org/freedesktop/systemd1",
3898                                 "org.freedesktop.systemd1.Manager",
3899                                 "RemoveSnapshot",
3900                                 NULL,
3901                                 NULL,
3902                                 DBUS_TYPE_STRING, &n,
3903                                 DBUS_TYPE_INVALID);
3904                 if (r < 0)
3905                         return r;
3906         }
3907
3908         return 0;
3909 }
3910
3911 static int daemon_reload(DBusConnection *bus, char **args) {
3912         int r;
3913         const char *method;
3914         DBusError error;
3915
3916         if (arg_action == ACTION_RELOAD)
3917                 method = "Reload";
3918         else if (arg_action == ACTION_REEXEC)
3919                 method = "Reexecute";
3920         else {
3921                 assert(arg_action == ACTION_SYSTEMCTL);
3922
3923                 method =
3924                         streq(args[0], "clear-jobs")    ||
3925                         streq(args[0], "cancel")        ? "ClearJobs" :
3926                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3927                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3928                         streq(args[0], "halt")          ? "Halt" :
3929                         streq(args[0], "poweroff")      ? "PowerOff" :
3930                         streq(args[0], "reboot")        ? "Reboot" :
3931                         streq(args[0], "kexec")         ? "KExec" :
3932                         streq(args[0], "exit")          ? "Exit" :
3933                                     /* "daemon-reload" */ "Reload";
3934         }
3935
3936         r = bus_method_call_with_reply(
3937                         bus,
3938                         "org.freedesktop.systemd1",
3939                         "/org/freedesktop/systemd1",
3940                         "org.freedesktop.systemd1.Manager",
3941                         method,
3942                         NULL,
3943                         &error,
3944                         DBUS_TYPE_INVALID);
3945
3946         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3947                 /* There's always a fallback possible for
3948                  * legacy actions. */
3949                 r = -EADDRNOTAVAIL;
3950         else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
3951                 /* On reexecution, we expect a disconnect, not a
3952                  * reply */
3953                 r = 0;
3954         else if (r < 0)
3955                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3956
3957         dbus_error_free(&error);
3958         return r;
3959 }
3960
3961 static int reset_failed(DBusConnection *bus, char **args) {
3962         int r = 0;
3963         char **name;
3964
3965         if (strv_length(args) <= 1)
3966                 return daemon_reload(bus, args);
3967
3968         STRV_FOREACH(name, args+1) {
3969                 _cleanup_free_ char *n;
3970
3971                 n = unit_name_mangle(*name);
3972                 if (!n)
3973                         return log_oom();
3974
3975                 r = bus_method_call_with_reply(
3976                                 bus,
3977                                 "org.freedesktop.systemd1",
3978                                 "/org/freedesktop/systemd1",
3979                                 "org.freedesktop.systemd1.Manager",
3980                                 "ResetFailedUnit",
3981                                 NULL,
3982                                 NULL,
3983                                 DBUS_TYPE_STRING, &n,
3984                                 DBUS_TYPE_INVALID);
3985                 if (r < 0)
3986                         return r;
3987         }
3988
3989         return 0;
3990 }
3991
3992 static int show_enviroment(DBusConnection *bus, char **args) {
3993         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3994         DBusMessageIter iter, sub, sub2;
3995         int r;
3996         const char
3997                 *interface = "org.freedesktop.systemd1.Manager",
3998                 *property = "Environment";
3999
4000         pager_open_if_enabled();
4001
4002         r = bus_method_call_with_reply(
4003                         bus,
4004                         "org.freedesktop.systemd1",
4005                         "/org/freedesktop/systemd1",
4006                         "org.freedesktop.DBus.Properties",
4007                         "Get",
4008                         &reply,
4009                         NULL,
4010                         DBUS_TYPE_STRING, &interface,
4011                         DBUS_TYPE_STRING, &property,
4012                         DBUS_TYPE_INVALID);
4013         if (r < 0)
4014                 return r;
4015
4016         if (!dbus_message_iter_init(reply, &iter) ||
4017             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
4018                 log_error("Failed to parse reply.");
4019                 return -EIO;
4020         }
4021
4022         dbus_message_iter_recurse(&iter, &sub);
4023
4024         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
4025             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
4026                 log_error("Failed to parse reply.");
4027                 return -EIO;
4028         }
4029
4030         dbus_message_iter_recurse(&sub, &sub2);
4031
4032         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
4033                 const char *text;
4034
4035                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
4036                         log_error("Failed to parse reply.");
4037                         return -EIO;
4038                 }
4039
4040                 dbus_message_iter_get_basic(&sub2, &text);
4041                 puts(text);
4042
4043                 dbus_message_iter_next(&sub2);
4044         }
4045
4046         return 0;
4047 }
4048
4049 static int switch_root(DBusConnection *bus, char **args) {
4050         unsigned l;
4051         const char *root;
4052         _cleanup_free_ char *init = NULL;
4053
4054         l = strv_length(args);
4055         if (l < 2 || l > 3) {
4056                 log_error("Wrong number of arguments.");
4057                 return -EINVAL;
4058         }
4059
4060         root = args[1];
4061
4062         if (l >= 3)
4063                 init = strdup(args[2]);
4064         else {
4065                 parse_env_file("/proc/cmdline", WHITESPACE,
4066                                "init", &init,
4067                                NULL);
4068
4069                 if (!init)
4070                         init = strdup("");
4071         }
4072         if (!init)
4073                 return log_oom();
4074
4075         log_debug("switching root - root: %s; init: %s", root, init);
4076
4077         return bus_method_call_with_reply(
4078                         bus,
4079                         "org.freedesktop.systemd1",
4080                         "/org/freedesktop/systemd1",
4081                         "org.freedesktop.systemd1.Manager",
4082                         "SwitchRoot",
4083                         NULL,
4084                         NULL,
4085                         DBUS_TYPE_STRING, &root,
4086                         DBUS_TYPE_STRING, &init,
4087                         DBUS_TYPE_INVALID);
4088 }
4089
4090 static int set_environment(DBusConnection *bus, char **args) {
4091         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4092         DBusError error;
4093         const char *method;
4094         DBusMessageIter iter;
4095         int r;
4096
4097         assert(bus);
4098         assert(args);
4099
4100         dbus_error_init(&error);
4101
4102         method = streq(args[0], "set-environment")
4103                 ? "SetEnvironment"
4104                 : "UnsetEnvironment";
4105
4106         m = dbus_message_new_method_call(
4107                         "org.freedesktop.systemd1",
4108                         "/org/freedesktop/systemd1",
4109                         "org.freedesktop.systemd1.Manager",
4110                         method);
4111         if (!m)
4112                 return log_oom();
4113
4114         dbus_message_iter_init_append(m, &iter);
4115
4116         r = bus_append_strv_iter(&iter, args + 1);
4117         if (r < 0)
4118                 return log_oom();
4119
4120         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4121         if (!reply) {
4122                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4123                 dbus_error_free(&error);
4124                 return -EIO;
4125         }
4126
4127         return 0;
4128 }
4129
4130 static int enable_sysv_units(char **args) {
4131         int r = 0;
4132
4133 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
4134         const char *verb = args[0];
4135         unsigned f = 1, t = 1;
4136         LookupPaths paths = {};
4137
4138         if (arg_scope != UNIT_FILE_SYSTEM)
4139                 return 0;
4140
4141         if (!streq(verb, "enable") &&
4142             !streq(verb, "disable") &&
4143             !streq(verb, "is-enabled"))
4144                 return 0;
4145
4146         /* Processes all SysV units, and reshuffles the array so that
4147          * afterwards only the native units remain */
4148
4149         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
4150         if (r < 0)
4151                 return r;
4152
4153         r = 0;
4154         for (f = 1; args[f]; f++) {
4155                 const char *name;
4156                 _cleanup_free_ char *p = NULL, *q = NULL;
4157                 bool found_native = false, found_sysv;
4158                 unsigned c = 1;
4159                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4160                 char **k, *l;
4161                 int j;
4162                 pid_t pid;
4163                 siginfo_t status;
4164
4165                 name = args[f];
4166
4167                 if (!endswith(name, ".service"))
4168                         continue;
4169
4170                 if (path_is_absolute(name))
4171                         continue;
4172
4173                 STRV_FOREACH(k, paths.unit_path) {
4174                         if (!isempty(arg_root))
4175                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4176                         else
4177                                 asprintf(&p, "%s/%s", *k, name);
4178
4179                         if (!p) {
4180                                 r = log_oom();
4181                                 goto finish;
4182                         }
4183
4184                         found_native = access(p, F_OK) >= 0;
4185                         free(p);
4186                         p = NULL;
4187
4188                         if (found_native)
4189                                 break;
4190                 }
4191
4192                 if (found_native)
4193                         continue;
4194
4195                 if (!isempty(arg_root))
4196                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4197                 else
4198                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4199                 if (!p) {
4200                         r = log_oom();
4201                         goto finish;
4202                 }
4203
4204                 p[strlen(p) - sizeof(".service") + 1] = 0;
4205                 found_sysv = access(p, F_OK) >= 0;
4206
4207                 if (!found_sysv)
4208                         continue;
4209
4210                 /* Mark this entry, so that we don't try enabling it as native unit */
4211                 args[f] = (char*) "";
4212
4213                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
4214
4215                 if (!isempty(arg_root))
4216                         argv[c++] = q = strappend("--root=", arg_root);
4217
4218                 argv[c++] = path_get_file_name(p);
4219                 argv[c++] =
4220                         streq(verb, "enable") ? "on" :
4221                         streq(verb, "disable") ? "off" : "--level=5";
4222                 argv[c] = NULL;
4223
4224                 l = strv_join((char**)argv, " ");
4225                 if (!l) {
4226                         r = log_oom();
4227                         goto finish;
4228                 }
4229
4230                 log_info("Executing %s", l);
4231                 free(l);
4232
4233                 pid = fork();
4234                 if (pid < 0) {
4235                         log_error("Failed to fork: %m");
4236                         r = -errno;
4237                         goto finish;
4238                 } else if (pid == 0) {
4239                         /* Child */
4240
4241                         execv(argv[0], (char**) argv);
4242                         _exit(EXIT_FAILURE);
4243                 }
4244
4245                 j = wait_for_terminate(pid, &status);
4246                 if (j < 0) {
4247                         log_error("Failed to wait for child: %s", strerror(-r));
4248                         r = j;
4249                         goto finish;
4250                 }
4251
4252                 if (status.si_code == CLD_EXITED) {
4253                         if (streq(verb, "is-enabled")) {
4254                                 if (status.si_status == 0) {
4255                                         if (!arg_quiet)
4256                                                 puts("enabled");
4257                                         r = 1;
4258                                 } else {
4259                                         if (!arg_quiet)
4260                                                 puts("disabled");
4261                                 }
4262
4263                         } else if (status.si_status != 0) {
4264                                 r = -EINVAL;
4265                                 goto finish;
4266                         }
4267                 } else {
4268                         r = -EPROTO;
4269                         goto finish;
4270                 }
4271         }
4272
4273 finish:
4274         lookup_paths_free(&paths);
4275
4276         /* Drop all SysV units */
4277         for (f = 1, t = 1; args[f]; f++) {
4278
4279                 if (isempty(args[f]))
4280                         continue;
4281
4282                 args[t++] = args[f];
4283         }
4284
4285         args[t] = NULL;
4286
4287 #endif
4288         return r;
4289 }
4290
4291 static int mangle_names(char **original_names, char ***mangled_names) {
4292         char **i, **l, **name;
4293
4294         l = new(char*, strv_length(original_names) + 1);
4295         if (!l)
4296                 return log_oom();
4297
4298         i = l;
4299         STRV_FOREACH(name, original_names) {
4300
4301                 /* When enabling units qualified path names are OK,
4302                  * too, hence allow them explicitly. */
4303
4304                 if (is_path(*name))
4305                         *i = strdup(*name);
4306                 else
4307                         *i = unit_name_mangle(*name);
4308
4309                 if (!*i) {
4310                         strv_free(l);
4311                         return log_oom();
4312                 }
4313
4314                 i++;
4315         }
4316
4317         *i = NULL;
4318         *mangled_names = l;
4319
4320         return 0;
4321 }
4322
4323 static int enable_unit(DBusConnection *bus, char **args) {
4324         const char *verb = args[0];
4325         UnitFileChange *changes = NULL;
4326         unsigned n_changes = 0, i;
4327         int carries_install_info = -1;
4328         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4329         int r;
4330         _cleanup_dbus_error_free_ DBusError error;
4331         _cleanup_strv_free_ char **mangled_names = NULL;
4332
4333         dbus_error_init(&error);
4334
4335         r = enable_sysv_units(args);
4336         if (r < 0)
4337                 return r;
4338
4339         if (!args[1])
4340                 return 0;
4341
4342         r = mangle_names(args+1, &mangled_names);
4343         if (r < 0)
4344                 goto finish;
4345
4346         if (!bus || avoid_bus()) {
4347                 if (streq(verb, "enable")) {
4348                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4349                         carries_install_info = r;
4350                 } else if (streq(verb, "disable"))
4351                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
4352                 else if (streq(verb, "reenable")) {
4353                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4354                         carries_install_info = r;
4355                 } else if (streq(verb, "link"))
4356                         r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4357                 else if (streq(verb, "preset")) {
4358                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4359                         carries_install_info = r;
4360                 } else if (streq(verb, "mask"))
4361                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
4362                 else if (streq(verb, "unmask"))
4363                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
4364                 else if (streq(verb, "set-default"))
4365                         r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
4366                 else
4367                         assert_not_reached("Unknown verb");
4368
4369                 if (r < 0) {
4370                         log_error("Operation failed: %s", strerror(-r));
4371                         goto finish;
4372                 }
4373
4374                 if (!arg_quiet) {
4375                         for (i = 0; i < n_changes; i++) {
4376                                 if (changes[i].type == UNIT_FILE_SYMLINK)
4377                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4378                                 else
4379                                         log_info("rm '%s'", changes[i].path);
4380                         }
4381                 }
4382
4383                 r = 0;
4384         } else {
4385                 const char *method;
4386                 bool send_force = true, expect_carries_install_info = false;
4387                 dbus_bool_t a, b;
4388                 DBusMessageIter iter, sub, sub2;
4389
4390                 if (streq(verb, "enable")) {
4391                         method = "EnableUnitFiles";
4392                         expect_carries_install_info = true;
4393                 } else if (streq(verb, "disable")) {
4394                         method = "DisableUnitFiles";
4395                         send_force = false;
4396                 } else if (streq(verb, "reenable")) {
4397                         method = "ReenableUnitFiles";
4398                         expect_carries_install_info = true;
4399                 } else if (streq(verb, "link"))
4400                         method = "LinkUnitFiles";
4401                 else if (streq(verb, "preset")) {
4402                         method = "PresetUnitFiles";
4403                         expect_carries_install_info = true;
4404                 } else if (streq(verb, "mask"))
4405                         method = "MaskUnitFiles";
4406                 else if (streq(verb, "unmask")) {
4407                         method = "UnmaskUnitFiles";
4408                         send_force = false;
4409                 } else if (streq(verb, "set-default")) {
4410                         method = "SetDefaultTarget";
4411                 } else
4412                         assert_not_reached("Unknown verb");
4413
4414                 m = dbus_message_new_method_call(
4415                                 "org.freedesktop.systemd1",
4416                                 "/org/freedesktop/systemd1",
4417                                 "org.freedesktop.systemd1.Manager",
4418                                 method);
4419                 if (!m) {
4420                         r = log_oom();
4421                         goto finish;
4422                 }
4423
4424                 dbus_message_iter_init_append(m, &iter);
4425
4426                 r = bus_append_strv_iter(&iter, mangled_names);
4427                 if (r < 0) {
4428                         log_error("Failed to append unit files.");
4429                         goto finish;
4430                 }
4431
4432                 a = arg_runtime;
4433                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4434                         log_error("Failed to append runtime boolean.");
4435                         r = -ENOMEM;
4436                         goto finish;
4437                 }
4438
4439                 if (send_force) {
4440                         b = arg_force;
4441
4442                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4443                                 log_error("Failed to append force boolean.");
4444                                 r = -ENOMEM;
4445                                 goto finish;
4446                         }
4447                 }
4448
4449                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4450                 if (!reply) {
4451                         log_error("Failed to issue method call: %s", bus_error_message(&error));
4452                         r = -EIO;
4453                         goto finish;
4454                 }
4455
4456                 if (!dbus_message_iter_init(reply, &iter)) {
4457                         log_error("Failed to initialize iterator.");
4458                         goto finish;
4459                 }
4460
4461                 if (expect_carries_install_info) {
4462                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4463                         if (r < 0) {
4464                                 log_error("Failed to parse reply.");
4465                                 goto finish;
4466                         }
4467
4468                         carries_install_info = b;
4469                 }
4470
4471                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4472                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4473                         log_error("Failed to parse reply.");
4474                         r = -EIO;
4475                         goto finish;
4476                 }
4477
4478                 dbus_message_iter_recurse(&iter, &sub);
4479                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4480                         const char *type, *path, *source;
4481
4482                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4483                                 log_error("Failed to parse reply.");
4484                                 r = -EIO;
4485                                 goto finish;
4486                         }
4487
4488                         dbus_message_iter_recurse(&sub, &sub2);
4489
4490                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4491                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4492                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4493                                 log_error("Failed to parse reply.");
4494                                 r = -EIO;
4495                                 goto finish;
4496                         }
4497
4498                         if (!arg_quiet) {
4499                                 if (streq(type, "symlink"))
4500                                         log_info("ln -s '%s' '%s'", source, path);
4501                                 else
4502                                         log_info("rm '%s'", path);
4503                         }
4504
4505                         dbus_message_iter_next(&sub);
4506                 }
4507
4508                 /* Try to reload if enabeld */
4509                 if (!arg_no_reload)
4510                         r = daemon_reload(bus, args);
4511         }
4512
4513         if (carries_install_info == 0)
4514                 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4515                             "using systemctl.\n"
4516                             "Possible reasons for having this kind of units are:\n"
4517                             "1) A unit may be statically enabled by being symlinked from another unit's\n"
4518                             "   .wants/ or .requires/ directory.\n"
4519                             "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4520                             "   a requirement dependency on it.\n"
4521                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
4522                             "   D-Bus, udev, scripted systemctl call, ...).\n");
4523
4524 finish:
4525         unit_file_changes_free(changes, n_changes);
4526
4527         return r;
4528 }
4529
4530 static int set_log_level(DBusConnection *bus, char **args) {
4531         _cleanup_dbus_error_free_ DBusError error;
4532         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
4533         DBusMessageIter iter, sub;
4534         const char* property = "LogLevel";
4535         const char* interface = "org.freedesktop.systemd1.Manager";
4536         const char* value;
4537
4538         assert(bus);
4539         assert(args);
4540
4541         value = args[1];
4542         dbus_error_init(&error);
4543
4544         m = dbus_message_new_method_call("org.freedesktop.systemd1",
4545                                          "/org/freedesktop/systemd1",
4546                                          "org.freedesktop.DBus.Properties",
4547                                          "Set");
4548         if (!m)
4549                 return log_oom();
4550
4551         dbus_message_iter_init_append(m, &iter);
4552
4553         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
4554             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property) ||
4555             !dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub))
4556                 return log_oom();
4557
4558         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &value)) {
4559                 dbus_message_iter_abandon_container(&iter, &sub);
4560                 return log_oom();
4561         }
4562
4563         if (!dbus_message_iter_close_container(&iter, &sub))
4564                 return log_oom();
4565
4566         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4567         if (!reply) {
4568                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4569                 return -EIO;
4570         }
4571
4572         return 0;
4573 }
4574
4575 static int unit_is_enabled(DBusConnection *bus, char **args) {
4576         _cleanup_dbus_error_free_ DBusError error;
4577         int r;
4578         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
4579         bool enabled;
4580         char **name;
4581         char *n;
4582
4583         dbus_error_init(&error);
4584
4585         r = enable_sysv_units(args);
4586         if (r < 0)
4587                 return r;
4588
4589         enabled = r > 0;
4590
4591         if (!bus || avoid_bus()) {
4592
4593                 STRV_FOREACH(name, args+1) {
4594                         UnitFileState state;
4595
4596                         n = unit_name_mangle(*name);
4597                         if (!n)
4598                                 return log_oom();
4599
4600                         state = unit_file_get_state(arg_scope, arg_root, n);
4601
4602                         free(n);
4603
4604                         if (state < 0)
4605                                 return state;
4606
4607                         if (state == UNIT_FILE_ENABLED ||
4608                             state == UNIT_FILE_ENABLED_RUNTIME ||
4609                             state == UNIT_FILE_STATIC)
4610                                 enabled = true;
4611
4612                         if (!arg_quiet)
4613                                 puts(unit_file_state_to_string(state));
4614                 }
4615
4616         } else {
4617                 STRV_FOREACH(name, args+1) {
4618                         const char *s;
4619
4620                         n = unit_name_mangle(*name);
4621                         if (!n)
4622                                 return log_oom();
4623
4624                         r = bus_method_call_with_reply (
4625                                         bus,
4626                                         "org.freedesktop.systemd1",
4627                                         "/org/freedesktop/systemd1",
4628                                         "org.freedesktop.systemd1.Manager",
4629                                         "GetUnitFileState",
4630                                         &reply,
4631                                         NULL,
4632                                         DBUS_TYPE_STRING, &n,
4633                                         DBUS_TYPE_INVALID);
4634
4635                         free(n);
4636
4637                         if (r)
4638                                 return r;
4639
4640                         if (!dbus_message_get_args(reply, &error,
4641                                                    DBUS_TYPE_STRING, &s,
4642                                                    DBUS_TYPE_INVALID)) {
4643                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4644                                 return -EIO;
4645                         }
4646
4647                         dbus_message_unref(reply);
4648                         reply = NULL;
4649
4650                         if (streq(s, "enabled") ||
4651                             streq(s, "enabled-runtime") ||
4652                             streq(s, "static"))
4653                                 enabled = true;
4654
4655                         if (!arg_quiet)
4656                                 puts(s);
4657                 }
4658         }
4659
4660         return enabled ? 0 : 1;
4661 }
4662
4663 static int systemctl_help(void) {
4664
4665         pager_open_if_enabled();
4666
4667         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4668                "Query or send control commands to the systemd manager.\n\n"
4669                "  -h --help           Show this help\n"
4670                "     --version        Show package version\n"
4671                "  -t --type=TYPE      List only units of a particular type\n"
4672                "     --state=STATE    Show only units with particular LOAD or SUB or ACTIVE state\n"
4673                "  -p --property=NAME  Show only properties by this name\n"
4674                "  -a --all            Show all loaded units/properties, including dead/empty\n"
4675                "                      ones. To list all units installed on the system, use\n"
4676                "                      the 'list-unit-files' command instead.\n"
4677                "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
4678                "  -l --full           Don't ellipsize unit names on output\n"
4679                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4680                "                      pending\n"
4681                "     --irreversible   Create jobs which cannot be implicitly cancelled\n"
4682                "     --show-types     When showing sockets, explicitly show their type\n"
4683                "     --ignore-dependencies\n"
4684                "                      When queueing a new job, ignore all its dependencies\n"
4685                "  -i --ignore-inhibitors\n"
4686                "                      When shutting down or sleeping, ignore inhibitors\n"
4687                "     --kill-who=WHO   Who to send signal to\n"
4688                "  -s --signal=SIGNAL  Which signal to send\n"
4689                "  -H --host=[USER@]HOST\n"
4690                "                      Show information for remote host\n"
4691                "  -P --privileged     Acquire privileges before execution\n"
4692                "  -q --quiet          Suppress output\n"
4693                "     --no-block       Do not wait until operation finished\n"
4694                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4695                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4696                "                      configuration\n"
4697                "     --no-legend      Do not print a legend (column headers and hints)\n"
4698                "     --no-pager       Do not pipe output into a pager\n"
4699                "     --no-ask-password\n"
4700                "                      Do not ask for system passwords\n"
4701                "     --system         Connect to system manager\n"
4702                "     --user           Connect to user service manager\n"
4703                "     --global         Enable/disable unit files globally\n"
4704                "  -f --force          When enabling unit files, override existing symlinks\n"
4705                "                      When shutting down, execute action immediately\n"
4706                "     --root=PATH      Enable unit files in the specified root directory\n"
4707                "     --runtime        Enable unit files only temporarily until next reboot\n"
4708                "  -n --lines=INTEGER  Journal entries to show\n"
4709                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4710                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
4711                "Unit Commands:\n"
4712                "  list-units                      List loaded units\n"
4713                "  list-sockets                    List loaded sockets ordered by address\n"
4714                "  start [NAME...]                 Start (activate) one or more units\n"
4715                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4716                "  reload [NAME...]                Reload one or more units\n"
4717                "  restart [NAME...]               Start or restart one or more units\n"
4718                "  try-restart [NAME...]           Restart one or more units if active\n"
4719                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
4720                "                                  otherwise start or restart\n"
4721                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
4722                "                                  otherwise restart if active\n"
4723                "  isolate [NAME]                  Start one unit and stop all others\n"
4724                "  kill [NAME...]                  Send signal to processes of a unit\n"
4725                "  is-active [NAME...]             Check whether units are active\n"
4726                "  is-failed [NAME...]             Check whether units are failed\n"
4727                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4728                "  show [NAME...|JOB...]           Show properties of one or more\n"
4729                "                                  units/jobs or the manager\n"
4730                "  set-property [NAME] [ASSIGNMENT...]\n"
4731                "                                  Sets one or more properties of a unit\n"
4732                "  help [NAME...|PID...]           Show manual for one or more units\n"
4733                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4734                "                                  units\n"
4735                "  load [NAME...]                  Load one or more units\n"
4736                "  list-dependencies [NAME]        Recursively show units which are required\n"
4737                "                                  or wanted by this unit or by which this\n"
4738                "                                  unit is required or wanted\n\n"
4739                "Unit File Commands:\n"
4740                "  list-unit-files                 List installed unit files\n"
4741                "  enable [NAME...]                Enable one or more unit files\n"
4742                "  disable [NAME...]               Disable one or more unit files\n"
4743                "  reenable [NAME...]              Reenable one or more unit files\n"
4744                "  preset [NAME...]                Enable/disable one or more unit files\n"
4745                "                                  based on preset configuration\n"
4746                "  mask [NAME...]                  Mask one or more units\n"
4747                "  unmask [NAME...]                Unmask one or more units\n"
4748                "  link [PATH...]                  Link one or more units files into\n"
4749                "                                  the search path\n"
4750                "  get-default                     Get the name of the default target\n"
4751                "  set-default NAME                Set the default target\n"
4752                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4753                "Job Commands:\n"
4754                "  list-jobs                       List jobs\n"
4755                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4756                "Snapshot Commands:\n"
4757                "  snapshot [NAME]                 Create a snapshot\n"
4758                "  delete [NAME...]                Remove one or more snapshots\n\n"
4759                "Environment Commands:\n"
4760                "  show-environment                Dump environment\n"
4761                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4762                "  unset-environment [NAME...]     Unset one or more environment variables\n"
4763                "  set-log-level LEVEL             Set logging threshold for systemd\n\n"
4764                "Manager Lifecycle Commands:\n"
4765                "  daemon-reload                   Reload systemd manager configuration\n"
4766                "  daemon-reexec                   Reexecute systemd manager\n\n"
4767                "System Commands:\n"
4768                "  default                         Enter system default mode\n"
4769                "  rescue                          Enter system rescue mode\n"
4770                "  emergency                       Enter system emergency mode\n"
4771                "  halt                            Shut down and halt the system\n"
4772                "  poweroff                        Shut down and power-off the system\n"
4773                "  reboot                          Shut down and reboot the system\n"
4774                "  kexec                           Shut down and reboot the system with kexec\n"
4775                "  exit                            Request user instance exit\n"
4776                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4777                "  suspend                         Suspend the system\n"
4778                "  hibernate                       Hibernate the system\n"
4779                "  hybrid-sleep                    Hibernate and suspend the system\n",
4780                program_invocation_short_name);
4781
4782         return 0;
4783 }
4784
4785 static int halt_help(void) {
4786
4787         printf("%s [OPTIONS...]\n\n"
4788                "%s the system.\n\n"
4789                "     --help      Show this help\n"
4790                "     --halt      Halt the machine\n"
4791                "  -p --poweroff  Switch off the machine\n"
4792                "     --reboot    Reboot the machine\n"
4793                "  -f --force     Force immediate halt/power-off/reboot\n"
4794                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4795                "  -d --no-wtmp   Don't write wtmp record\n"
4796                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4797                program_invocation_short_name,
4798                arg_action == ACTION_REBOOT   ? "Reboot" :
4799                arg_action == ACTION_POWEROFF ? "Power off" :
4800                                                "Halt");
4801
4802         return 0;
4803 }
4804
4805 static int shutdown_help(void) {
4806
4807         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4808                "Shut down the system.\n\n"
4809                "     --help      Show this help\n"
4810                "  -H --halt      Halt the machine\n"
4811                "  -P --poweroff  Power-off the machine\n"
4812                "  -r --reboot    Reboot the machine\n"
4813                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4814                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4815                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4816                "  -c             Cancel a pending shutdown\n",
4817                program_invocation_short_name);
4818
4819         return 0;
4820 }
4821
4822 static int telinit_help(void) {
4823
4824         printf("%s [OPTIONS...] {COMMAND}\n\n"
4825                "Send control commands to the init daemon.\n\n"
4826                "     --help      Show this help\n"
4827                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4828                "Commands:\n"
4829                "  0              Power-off the machine\n"
4830                "  6              Reboot the machine\n"
4831                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4832                "  1, s, S        Enter rescue mode\n"
4833                "  q, Q           Reload init daemon configuration\n"
4834                "  u, U           Reexecute init daemon\n",
4835                program_invocation_short_name);
4836
4837         return 0;
4838 }
4839
4840 static int runlevel_help(void) {
4841
4842         printf("%s [OPTIONS...]\n\n"
4843                "Prints the previous and current runlevel of the init system.\n\n"
4844                "     --help      Show this help\n",
4845                program_invocation_short_name);
4846
4847         return 0;
4848 }
4849
4850 static int help_types(void) {
4851         int i;
4852         const char *t;
4853
4854         puts("Available unit types:");
4855         for(i = 0; i < _UNIT_TYPE_MAX; i++) {
4856                 t = unit_type_to_string(i);
4857                 if (t)
4858                         puts(t);
4859         }
4860
4861         return 0;
4862 }
4863
4864 static int systemctl_parse_argv(int argc, char *argv[]) {
4865
4866         enum {
4867                 ARG_FAIL = 0x100,
4868                 ARG_REVERSE,
4869                 ARG_AFTER,
4870                 ARG_BEFORE,
4871                 ARG_SHOW_TYPES,
4872                 ARG_IRREVERSIBLE,
4873                 ARG_IGNORE_DEPENDENCIES,
4874                 ARG_VERSION,
4875                 ARG_USER,
4876                 ARG_SYSTEM,
4877                 ARG_GLOBAL,
4878                 ARG_NO_BLOCK,
4879                 ARG_NO_LEGEND,
4880                 ARG_NO_PAGER,
4881                 ARG_NO_WALL,
4882                 ARG_ROOT,
4883                 ARG_NO_RELOAD,
4884                 ARG_KILL_WHO,
4885                 ARG_NO_ASK_PASSWORD,
4886                 ARG_FAILED,
4887                 ARG_RUNTIME,
4888                 ARG_FORCE,
4889                 ARG_PLAIN,
4890                 ARG_STATE
4891         };
4892
4893         static const struct option options[] = {
4894                 { "help",                no_argument,       NULL, 'h'                     },
4895                 { "version",             no_argument,       NULL, ARG_VERSION             },
4896                 { "type",                required_argument, NULL, 't'                     },
4897                 { "property",            required_argument, NULL, 'p'                     },
4898                 { "all",                 no_argument,       NULL, 'a'                     },
4899                 { "reverse",             no_argument,       NULL, ARG_REVERSE             },
4900                 { "after",               no_argument,       NULL, ARG_AFTER               },
4901                 { "before",              no_argument,       NULL, ARG_BEFORE              },
4902                 { "show-types",          no_argument,       NULL, ARG_SHOW_TYPES          },
4903                 { "failed",              no_argument,       NULL, ARG_FAILED              }, /* compatibility only */
4904                 { "full",                no_argument,       NULL, 'l'                     },
4905                 { "fail",                no_argument,       NULL, ARG_FAIL                },
4906                 { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        },
4907                 { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES },
4908                 { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
4909                 { "user",                no_argument,       NULL, ARG_USER                },
4910                 { "system",              no_argument,       NULL, ARG_SYSTEM              },
4911                 { "global",              no_argument,       NULL, ARG_GLOBAL              },
4912                 { "no-block",            no_argument,       NULL, ARG_NO_BLOCK            },
4913                 { "no-legend",           no_argument,       NULL, ARG_NO_LEGEND           },
4914                 { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
4915                 { "no-wall",             no_argument,       NULL, ARG_NO_WALL             },
4916                 { "quiet",               no_argument,       NULL, 'q'                     },
4917                 { "root",                required_argument, NULL, ARG_ROOT                },
4918                 { "force",               no_argument,       NULL, ARG_FORCE               },
4919                 { "no-reload",           no_argument,       NULL, ARG_NO_RELOAD           },
4920                 { "kill-who",            required_argument, NULL, ARG_KILL_WHO            },
4921                 { "signal",              required_argument, NULL, 's'                     },
4922                 { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
4923                 { "host",                required_argument, NULL, 'H'                     },
4924                 { "privileged",          no_argument,       NULL, 'P'                     },
4925                 { "runtime",             no_argument,       NULL, ARG_RUNTIME             },
4926                 { "lines",               required_argument, NULL, 'n'                     },
4927                 { "output",              required_argument, NULL, 'o'                     },
4928                 { "plain",               no_argument,       NULL, ARG_PLAIN               },
4929                 { "state",               required_argument, NULL, ARG_STATE               },
4930                 { NULL,                  0,                 NULL, 0                       }
4931         };
4932
4933         int c;
4934
4935         assert(argc >= 0);
4936         assert(argv);
4937
4938         while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:Pn:o:i", options, NULL)) >= 0) {
4939
4940                 switch (c) {
4941
4942                 case 'h':
4943                         systemctl_help();
4944                         return 0;
4945
4946                 case ARG_VERSION:
4947                         puts(PACKAGE_STRING);
4948                         puts(SYSTEMD_FEATURES);
4949                         return 0;
4950
4951                 case 't': {
4952                         char *word, *state;
4953                         size_t size;
4954
4955                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
4956                                 _cleanup_free_ char *type;
4957
4958                                 type = strndup(word, size);
4959                                 if (!type)
4960                                         return -ENOMEM;
4961
4962                                 if (streq(type, "help")) {
4963                                         help_types();
4964                                         return 0;
4965                                 }
4966
4967                                 if (unit_type_from_string(type) >= 0) {
4968                                         if (strv_push(&arg_types, type))
4969                                                 return log_oom();
4970                                         type = NULL;
4971                                         continue;
4972                                 }
4973
4974                                 /* It's much nicer to use --state= for
4975                                  * load states, but let's support this
4976                                  * in --types= too for compatibility
4977                                  * with old versions */
4978                                 if (unit_load_state_from_string(optarg) >= 0) {
4979                                         if (strv_push(&arg_states, type) < 0)
4980                                                 return log_oom();
4981                                         type = NULL;
4982                                         continue;
4983                                 }
4984
4985                                 log_error("Unknown unit type or load state '%s'.", type);
4986                                 log_info("Use -t help to see a list of allowed values.");
4987                                 return -EINVAL;
4988                         }
4989
4990                         break;
4991                 }
4992
4993                 case 'p': {
4994                         /* Make sure that if the empty property list
4995                            was specified, we won't show any properties. */
4996                         if (isempty(optarg) && !arg_properties) {
4997                                 arg_properties = strv_new(NULL, NULL);
4998                                 if (!arg_properties)
4999                                         return log_oom();
5000                         } else {
5001                                 char *word, *state;
5002                                 size_t size;
5003
5004                                 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5005                                         char *prop;
5006
5007                                         prop = strndup(word, size);
5008                                         if (!prop)
5009                                                 return log_oom();
5010
5011                                         if (strv_push(&arg_properties, prop) < 0) {
5012                                                 free(prop);
5013                                                 return log_oom();
5014                                         }
5015                                 }
5016                         }
5017
5018                         /* If the user asked for a particular
5019                          * property, show it to him, even if it is
5020                          * empty. */
5021                         arg_all = true;
5022
5023                         break;
5024                 }
5025
5026                 case 'a':
5027                         arg_all = true;
5028                         break;
5029
5030                 case ARG_REVERSE:
5031                         arg_dependency = DEPENDENCY_REVERSE;
5032                         break;
5033
5034                 case ARG_AFTER:
5035                         arg_dependency = DEPENDENCY_AFTER;
5036                         break;
5037
5038                 case ARG_BEFORE:
5039                         arg_dependency = DEPENDENCY_BEFORE;
5040                         break;
5041
5042                 case ARG_SHOW_TYPES:
5043                         arg_show_types = true;
5044                         break;
5045
5046                 case ARG_FAIL:
5047                         arg_job_mode = "fail";
5048                         break;
5049
5050                 case ARG_IRREVERSIBLE:
5051                         arg_job_mode = "replace-irreversibly";
5052                         break;
5053
5054                 case ARG_IGNORE_DEPENDENCIES:
5055                         arg_job_mode = "ignore-dependencies";
5056                         break;
5057
5058                 case ARG_USER:
5059                         arg_scope = UNIT_FILE_USER;
5060                         break;
5061
5062                 case ARG_SYSTEM:
5063                         arg_scope = UNIT_FILE_SYSTEM;
5064                         break;
5065
5066                 case ARG_GLOBAL:
5067                         arg_scope = UNIT_FILE_GLOBAL;
5068                         break;
5069
5070                 case ARG_NO_BLOCK:
5071                         arg_no_block = true;
5072                         break;
5073
5074                 case ARG_NO_LEGEND:
5075                         arg_no_legend = true;
5076                         break;
5077
5078                 case ARG_NO_PAGER:
5079                         arg_no_pager = true;
5080                         break;
5081
5082                 case ARG_NO_WALL:
5083                         arg_no_wall = true;
5084                         break;
5085
5086                 case ARG_ROOT:
5087                         arg_root = optarg;
5088                         break;
5089
5090                 case 'l':
5091                         arg_full = true;
5092                         break;
5093
5094                 case ARG_FAILED:
5095                         if (strv_extend(&arg_states, "failed") < 0)
5096                                 return log_oom();
5097
5098                         break;
5099
5100                 case 'q':
5101                         arg_quiet = true;
5102                         break;
5103
5104                 case ARG_FORCE:
5105                         arg_force ++;
5106                         break;
5107
5108                 case 'f':
5109                         arg_force ++;
5110                         break;
5111
5112                 case ARG_NO_RELOAD:
5113                         arg_no_reload = true;
5114                         break;
5115
5116                 case ARG_KILL_WHO:
5117                         arg_kill_who = optarg;
5118                         break;
5119
5120                 case 's':
5121                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5122                                 log_error("Failed to parse signal string %s.", optarg);
5123                                 return -EINVAL;
5124                         }
5125                         break;
5126
5127                 case ARG_NO_ASK_PASSWORD:
5128                         arg_ask_password = false;
5129                         break;
5130
5131                 case 'P':
5132                         arg_transport = TRANSPORT_POLKIT;
5133                         break;
5134
5135                 case 'H':
5136                         arg_transport = TRANSPORT_SSH;
5137                         parse_user_at_host(optarg, &arg_user, &arg_host);
5138                         break;
5139
5140                 case ARG_RUNTIME:
5141                         arg_runtime = true;
5142                         break;
5143
5144                 case 'n':
5145                         if (safe_atou(optarg, &arg_lines) < 0) {
5146                                 log_error("Failed to parse lines '%s'", optarg);
5147                                 return -EINVAL;
5148                         }
5149                         break;
5150
5151                 case 'o':
5152                         arg_output = output_mode_from_string(optarg);
5153                         if (arg_output < 0) {
5154                                 log_error("Unknown output '%s'.", optarg);
5155                                 return -EINVAL;
5156                         }
5157                         break;
5158
5159                 case 'i':
5160                         arg_ignore_inhibitors = true;
5161                         break;
5162
5163                 case ARG_PLAIN:
5164                         arg_plain = true;
5165                         break;
5166
5167                 case ARG_STATE: {
5168                         char *word, *state;
5169                         size_t size;
5170
5171                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5172                                 char *s;
5173
5174                                 s = strndup(word, size);
5175                                 if (!s)
5176                                         return log_oom();
5177
5178                                 if (strv_push(&arg_states, s) < 0) {
5179                                         free(s);
5180                                         return log_oom();
5181                                 }
5182                         }
5183                         break;
5184                 }
5185
5186                 case '?':
5187                         return -EINVAL;
5188
5189                 default:
5190                         log_error("Unknown option code '%c'.", c);
5191                         return -EINVAL;
5192                 }
5193         }
5194
5195         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
5196                 log_error("Cannot access user instance remotely.");
5197                 return -EINVAL;
5198         }
5199
5200         return 1;
5201 }
5202
5203 static int halt_parse_argv(int argc, char *argv[]) {
5204
5205         enum {
5206                 ARG_HELP = 0x100,
5207                 ARG_HALT,
5208                 ARG_REBOOT,
5209                 ARG_NO_WALL
5210         };
5211
5212         static const struct option options[] = {
5213                 { "help",      no_argument,       NULL, ARG_HELP    },
5214                 { "halt",      no_argument,       NULL, ARG_HALT    },
5215                 { "poweroff",  no_argument,       NULL, 'p'         },
5216                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
5217                 { "force",     no_argument,       NULL, 'f'         },
5218                 { "wtmp-only", no_argument,       NULL, 'w'         },
5219                 { "no-wtmp",   no_argument,       NULL, 'd'         },
5220                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5221                 { NULL,        0,                 NULL, 0           }
5222         };
5223
5224         int c, runlevel;
5225
5226         assert(argc >= 0);
5227         assert(argv);
5228
5229         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5230                 if (runlevel == '0' || runlevel == '6')
5231                         arg_force = 2;
5232
5233         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5234                 switch (c) {
5235
5236                 case ARG_HELP:
5237                         halt_help();
5238                         return 0;
5239
5240                 case ARG_HALT:
5241                         arg_action = ACTION_HALT;
5242                         break;
5243
5244                 case 'p':
5245                         if (arg_action != ACTION_REBOOT)
5246                                 arg_action = ACTION_POWEROFF;
5247                         break;
5248
5249                 case ARG_REBOOT:
5250                         arg_action = ACTION_REBOOT;
5251                         break;
5252
5253                 case 'f':
5254                         arg_force = 2;
5255                         break;
5256
5257                 case 'w':
5258                         arg_dry = true;
5259                         break;
5260
5261                 case 'd':
5262                         arg_no_wtmp = true;
5263                         break;
5264
5265                 case ARG_NO_WALL:
5266                         arg_no_wall = true;
5267                         break;
5268
5269                 case 'i':
5270                 case 'h':
5271                 case 'n':
5272                         /* Compatibility nops */
5273                         break;
5274
5275                 case '?':
5276                         return -EINVAL;
5277
5278                 default:
5279                         log_error("Unknown option code '%c'.", c);
5280                         return -EINVAL;
5281                 }
5282         }
5283
5284         if (optind < argc) {
5285                 log_error("Too many arguments.");
5286                 return -EINVAL;
5287         }
5288
5289         return 1;
5290 }
5291
5292 static int parse_time_spec(const char *t, usec_t *_u) {
5293         assert(t);
5294         assert(_u);
5295
5296         if (streq(t, "now"))
5297                 *_u = 0;
5298         else if (!strchr(t, ':')) {
5299                 uint64_t u;
5300
5301                 if (safe_atou64(t, &u) < 0)
5302                         return -EINVAL;
5303
5304                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5305         } else {
5306                 char *e = NULL;
5307                 long hour, minute;
5308                 struct tm tm = {};
5309                 time_t s;
5310                 usec_t n;
5311
5312                 errno = 0;
5313                 hour = strtol(t, &e, 10);
5314                 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
5315                         return -EINVAL;
5316
5317                 minute = strtol(e+1, &e, 10);
5318                 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
5319                         return -EINVAL;
5320
5321                 n = now(CLOCK_REALTIME);
5322                 s = (time_t) (n / USEC_PER_SEC);
5323
5324                 assert_se(localtime_r(&s, &tm));
5325
5326                 tm.tm_hour = (int) hour;
5327                 tm.tm_min = (int) minute;
5328                 tm.tm_sec = 0;
5329
5330                 assert_se(s = mktime(&tm));
5331
5332                 *_u = (usec_t) s * USEC_PER_SEC;
5333
5334                 while (*_u <= n)
5335                         *_u += USEC_PER_DAY;
5336         }
5337
5338         return 0;
5339 }
5340
5341 static int shutdown_parse_argv(int argc, char *argv[]) {
5342
5343         enum {
5344                 ARG_HELP = 0x100,
5345                 ARG_NO_WALL
5346         };
5347
5348         static const struct option options[] = {
5349                 { "help",      no_argument,       NULL, ARG_HELP    },
5350                 { "halt",      no_argument,       NULL, 'H'         },
5351                 { "poweroff",  no_argument,       NULL, 'P'         },
5352                 { "reboot",    no_argument,       NULL, 'r'         },
5353                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
5354                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5355                 { NULL,        0,                 NULL, 0           }
5356         };
5357
5358         int c, r;
5359
5360         assert(argc >= 0);
5361         assert(argv);
5362
5363         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
5364                 switch (c) {
5365
5366                 case ARG_HELP:
5367                         shutdown_help();
5368                         return 0;
5369
5370                 case 'H':
5371                         arg_action = ACTION_HALT;
5372                         break;
5373
5374                 case 'P':
5375                         arg_action = ACTION_POWEROFF;
5376                         break;
5377
5378                 case 'r':
5379                         if (kexec_loaded())
5380                                 arg_action = ACTION_KEXEC;
5381                         else
5382                                 arg_action = ACTION_REBOOT;
5383                         break;
5384
5385                 case 'K':
5386                         arg_action = ACTION_KEXEC;
5387                         break;
5388
5389                 case 'h':
5390                         if (arg_action != ACTION_HALT)
5391                                 arg_action = ACTION_POWEROFF;
5392                         break;
5393
5394                 case 'k':
5395                         arg_dry = true;
5396                         break;
5397
5398                 case ARG_NO_WALL:
5399                         arg_no_wall = true;
5400                         break;
5401
5402                 case 't':
5403                 case 'a':
5404                         /* Compatibility nops */
5405                         break;
5406
5407                 case 'c':
5408                         arg_action = ACTION_CANCEL_SHUTDOWN;
5409                         break;
5410
5411                 case '?':
5412                         return -EINVAL;
5413
5414                 default:
5415                         log_error("Unknown option code '%c'.", c);
5416                         return -EINVAL;
5417                 }
5418         }
5419
5420         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
5421                 r = parse_time_spec(argv[optind], &arg_when);
5422                 if (r < 0) {
5423                         log_error("Failed to parse time specification: %s", argv[optind]);
5424                         return r;
5425                 }
5426         } else
5427                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
5428
5429         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5430                 /* No time argument for shutdown cancel */
5431                 arg_wall = argv + optind;
5432         else if (argc > optind + 1)
5433                 /* We skip the time argument */
5434                 arg_wall = argv + optind + 1;
5435
5436         optind = argc;
5437
5438         return 1;
5439 }
5440
5441 static int telinit_parse_argv(int argc, char *argv[]) {
5442
5443         enum {
5444                 ARG_HELP = 0x100,
5445                 ARG_NO_WALL
5446         };
5447
5448         static const struct option options[] = {
5449                 { "help",      no_argument,       NULL, ARG_HELP    },
5450                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5451                 { NULL,        0,                 NULL, 0           }
5452         };
5453
5454         static const struct {
5455                 char from;
5456                 enum action to;
5457         } table[] = {
5458                 { '0', ACTION_POWEROFF },
5459                 { '6', ACTION_REBOOT },
5460                 { '1', ACTION_RESCUE },
5461                 { '2', ACTION_RUNLEVEL2 },
5462                 { '3', ACTION_RUNLEVEL3 },
5463                 { '4', ACTION_RUNLEVEL4 },
5464                 { '5', ACTION_RUNLEVEL5 },
5465                 { 's', ACTION_RESCUE },
5466                 { 'S', ACTION_RESCUE },
5467                 { 'q', ACTION_RELOAD },
5468                 { 'Q', ACTION_RELOAD },
5469                 { 'u', ACTION_REEXEC },
5470                 { 'U', ACTION_REEXEC }
5471         };
5472
5473         unsigned i;
5474         int c;
5475
5476         assert(argc >= 0);
5477         assert(argv);
5478
5479         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5480                 switch (c) {
5481
5482                 case ARG_HELP:
5483                         telinit_help();
5484                         return 0;
5485
5486                 case ARG_NO_WALL:
5487                         arg_no_wall = true;
5488                         break;
5489
5490                 case '?':
5491                         return -EINVAL;
5492
5493                 default:
5494                         log_error("Unknown option code '%c'.", c);
5495                         return -EINVAL;
5496                 }
5497         }
5498
5499         if (optind >= argc) {
5500                 telinit_help();
5501                 return -EINVAL;
5502         }
5503
5504         if (optind + 1 < argc) {
5505                 log_error("Too many arguments.");
5506                 return -EINVAL;
5507         }
5508
5509         if (strlen(argv[optind]) != 1) {
5510                 log_error("Expected single character argument.");
5511                 return -EINVAL;
5512         }
5513
5514         for (i = 0; i < ELEMENTSOF(table); i++)
5515                 if (table[i].from == argv[optind][0])
5516                         break;
5517
5518         if (i >= ELEMENTSOF(table)) {
5519                 log_error("Unknown command '%s'.", argv[optind]);
5520                 return -EINVAL;
5521         }
5522
5523         arg_action = table[i].to;
5524
5525         optind ++;
5526
5527         return 1;
5528 }
5529
5530 static int runlevel_parse_argv(int argc, char *argv[]) {
5531
5532         enum {
5533                 ARG_HELP = 0x100,
5534         };
5535
5536         static const struct option options[] = {
5537                 { "help",      no_argument,       NULL, ARG_HELP    },
5538                 { NULL,        0,                 NULL, 0           }
5539         };
5540
5541         int c;
5542
5543         assert(argc >= 0);
5544         assert(argv);
5545
5546         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5547                 switch (c) {
5548
5549                 case ARG_HELP:
5550                         runlevel_help();
5551                         return 0;
5552
5553                 case '?':
5554                         return -EINVAL;
5555
5556                 default:
5557                         log_error("Unknown option code '%c'.", c);
5558                         return -EINVAL;
5559                 }
5560         }
5561
5562         if (optind < argc) {
5563                 log_error("Too many arguments.");
5564                 return -EINVAL;
5565         }
5566
5567         return 1;
5568 }
5569
5570 static int parse_argv(int argc, char *argv[]) {
5571         assert(argc >= 0);
5572         assert(argv);
5573
5574         if (program_invocation_short_name) {
5575
5576                 if (strstr(program_invocation_short_name, "halt")) {
5577                         arg_action = ACTION_HALT;
5578                         return halt_parse_argv(argc, argv);
5579                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5580                         arg_action = ACTION_POWEROFF;
5581                         return halt_parse_argv(argc, argv);
5582                 } else if (strstr(program_invocation_short_name, "reboot")) {
5583                         if (kexec_loaded())
5584                                 arg_action = ACTION_KEXEC;
5585                         else
5586                                 arg_action = ACTION_REBOOT;
5587                         return halt_parse_argv(argc, argv);
5588                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5589                         arg_action = ACTION_POWEROFF;
5590                         return shutdown_parse_argv(argc, argv);
5591                 } else if (strstr(program_invocation_short_name, "init")) {
5592
5593                         if (sd_booted() > 0) {
5594                                 arg_action = ACTION_INVALID;
5595                                 return telinit_parse_argv(argc, argv);
5596                         } else {
5597                                 /* Hmm, so some other init system is
5598                                  * running, we need to forward this
5599                                  * request to it. For now we simply
5600                                  * guess that it is Upstart. */
5601
5602                                 execv(TELINIT, argv);
5603
5604                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5605                                 return -EIO;
5606                         }
5607
5608                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5609                         arg_action = ACTION_RUNLEVEL;
5610                         return runlevel_parse_argv(argc, argv);
5611                 }
5612         }
5613
5614         arg_action = ACTION_SYSTEMCTL;
5615         return systemctl_parse_argv(argc, argv);
5616 }
5617
5618 _pure_ static int action_to_runlevel(void) {
5619
5620         static const char table[_ACTION_MAX] = {
5621                 [ACTION_HALT] =      '0',
5622                 [ACTION_POWEROFF] =  '0',
5623                 [ACTION_REBOOT] =    '6',
5624                 [ACTION_RUNLEVEL2] = '2',
5625                 [ACTION_RUNLEVEL3] = '3',
5626                 [ACTION_RUNLEVEL4] = '4',
5627                 [ACTION_RUNLEVEL5] = '5',
5628                 [ACTION_RESCUE] =    '1'
5629         };
5630
5631         assert(arg_action < _ACTION_MAX);
5632
5633         return table[arg_action];
5634 }
5635
5636 static int talk_upstart(void) {
5637         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
5638         _cleanup_dbus_error_free_ DBusError error;
5639         int previous, rl, r;
5640         char
5641                 env1_buf[] = "RUNLEVEL=X",
5642                 env2_buf[] = "PREVLEVEL=X";
5643         char *env1 = env1_buf, *env2 = env2_buf;
5644         const char *emit = "runlevel";
5645         dbus_bool_t b_false = FALSE;
5646         DBusMessageIter iter, sub;
5647         DBusConnection *bus;
5648
5649         dbus_error_init(&error);
5650
5651         if (!(rl = action_to_runlevel()))
5652                 return 0;
5653
5654         if (utmp_get_runlevel(&previous, NULL) < 0)
5655                 previous = 'N';
5656
5657         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5658                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5659                         r = 0;
5660                         goto finish;
5661                 }
5662
5663                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5664                 r = -EIO;
5665                 goto finish;
5666         }
5667
5668         if ((r = bus_check_peercred(bus)) < 0) {
5669                 log_error("Failed to verify owner of bus.");
5670                 goto finish;
5671         }
5672
5673         if (!(m = dbus_message_new_method_call(
5674                               "com.ubuntu.Upstart",
5675                               "/com/ubuntu/Upstart",
5676                               "com.ubuntu.Upstart0_6",
5677                               "EmitEvent"))) {
5678
5679                 log_error("Could not allocate message.");
5680                 r = -ENOMEM;
5681                 goto finish;
5682         }
5683
5684         dbus_message_iter_init_append(m, &iter);
5685
5686         env1_buf[sizeof(env1_buf)-2] = rl;
5687         env2_buf[sizeof(env2_buf)-2] = previous;
5688
5689         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5690             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5691             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5692             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5693             !dbus_message_iter_close_container(&iter, &sub) ||
5694             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5695                 log_error("Could not append arguments to message.");
5696                 r = -ENOMEM;
5697                 goto finish;
5698         }
5699
5700         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5701
5702                 if (bus_error_is_no_service(&error)) {
5703                         r = -EADDRNOTAVAIL;
5704                         goto finish;
5705                 }
5706
5707                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5708                 r = -EIO;
5709                 goto finish;
5710         }
5711
5712         r = 1;
5713
5714 finish:
5715         if (bus) {
5716                 dbus_connection_flush(bus);
5717                 dbus_connection_close(bus);
5718                 dbus_connection_unref(bus);
5719         }
5720
5721         return r;
5722 }
5723
5724 static int talk_initctl(void) {
5725         struct init_request request = {};
5726         int r;
5727         _cleanup_close_ int fd = -1;
5728         char rl;
5729
5730         rl = action_to_runlevel();
5731         if (!rl)
5732                 return 0;
5733
5734         request.magic = INIT_MAGIC;
5735         request.sleeptime = 0;
5736         request.cmd = INIT_CMD_RUNLVL;
5737         request.runlevel = rl;
5738
5739         fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5740         if (fd < 0) {
5741                 if (errno == ENOENT)
5742                         return 0;
5743
5744                 log_error("Failed to open "INIT_FIFO": %m");
5745                 return -errno;
5746         }
5747
5748         errno = 0;
5749         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5750         if (r) {
5751                 log_error("Failed to write to "INIT_FIFO": %m");
5752                 return errno > 0 ? -errno : -EIO;
5753         }
5754
5755         return 1;
5756 }
5757
5758 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5759
5760         static const struct {
5761                 const char* verb;
5762                 const enum {
5763                         MORE,
5764                         LESS,
5765                         EQUAL
5766                 } argc_cmp;
5767                 const int argc;
5768                 int (* const dispatch)(DBusConnection *bus, char **args);
5769         } verbs[] = {
5770                 { "list-units",            LESS,  1, list_units        },
5771                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5772                 { "list-sockets",          LESS,  1, list_sockets      },
5773                 { "list-jobs",             EQUAL, 1, list_jobs         },
5774                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5775                 { "load",                  MORE,  2, load_unit         },
5776                 { "cancel",                MORE,  2, cancel_job        },
5777                 { "start",                 MORE,  2, start_unit        },
5778                 { "stop",                  MORE,  2, start_unit        },
5779                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5780                 { "reload",                MORE,  2, start_unit        },
5781                 { "restart",               MORE,  2, start_unit        },
5782                 { "try-restart",           MORE,  2, start_unit        },
5783                 { "reload-or-restart",     MORE,  2, start_unit        },
5784                 { "reload-or-try-restart", MORE,  2, start_unit        },
5785                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5786                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5787                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5788                 { "isolate",               EQUAL, 2, start_unit        },
5789                 { "kill",                  MORE,  2, kill_unit         },
5790                 { "is-active",             MORE,  2, check_unit_active },
5791                 { "check",                 MORE,  2, check_unit_active },
5792                 { "is-failed",             MORE,  2, check_unit_failed },
5793                 { "show",                  MORE,  1, show              },
5794                 { "status",                MORE,  1, show              },
5795                 { "help",                  MORE,  2, show              },
5796                 { "snapshot",              LESS,  2, snapshot          },
5797                 { "delete",                MORE,  2, delete_snapshot   },
5798                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5799                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5800                 { "show-environment",      EQUAL, 1, show_enviroment   },
5801                 { "set-environment",       MORE,  2, set_environment   },
5802                 { "unset-environment",     MORE,  2, set_environment   },
5803                 { "halt",                  EQUAL, 1, start_special     },
5804                 { "poweroff",              EQUAL, 1, start_special     },
5805                 { "reboot",                EQUAL, 1, start_special     },
5806                 { "kexec",                 EQUAL, 1, start_special     },
5807                 { "suspend",               EQUAL, 1, start_special     },
5808                 { "hibernate",             EQUAL, 1, start_special     },
5809                 { "hybrid-sleep",          EQUAL, 1, start_special     },
5810                 { "default",               EQUAL, 1, start_special     },
5811                 { "rescue",                EQUAL, 1, start_special     },
5812                 { "emergency",             EQUAL, 1, start_special     },
5813                 { "exit",                  EQUAL, 1, start_special     },
5814                 { "reset-failed",          MORE,  1, reset_failed      },
5815                 { "enable",                MORE,  2, enable_unit       },
5816                 { "disable",               MORE,  2, enable_unit       },
5817                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5818                 { "reenable",              MORE,  2, enable_unit       },
5819                 { "preset",                MORE,  2, enable_unit       },
5820                 { "mask",                  MORE,  2, enable_unit       },
5821                 { "unmask",                MORE,  2, enable_unit       },
5822                 { "link",                  MORE,  2, enable_unit       },
5823                 { "switch-root",           MORE,  2, switch_root       },
5824                 { "list-dependencies",     LESS,  2, list_dependencies },
5825                 { "set-default",           EQUAL, 2, enable_unit       },
5826                 { "get-default",           LESS,  1, get_default       },
5827                 { "set-log-level",         EQUAL, 2, set_log_level     },
5828                 { "set-property",          MORE,  3, set_property      },
5829         };
5830
5831         int left;
5832         unsigned i;
5833
5834         assert(argc >= 0);
5835         assert(argv);
5836         assert(error);
5837
5838         left = argc - optind;
5839
5840         if (left <= 0)
5841                 /* Special rule: no arguments means "list-units" */
5842                 i = 0;
5843         else {
5844                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5845                         log_error("This command expects one or more "
5846                                   "unit names. Did you mean --help?");
5847                         return -EINVAL;
5848                 }
5849
5850                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5851                         if (streq(argv[optind], verbs[i].verb))
5852                                 break;
5853
5854                 if (i >= ELEMENTSOF(verbs)) {
5855                         log_error("Unknown operation '%s'.", argv[optind]);
5856                         return -EINVAL;
5857                 }
5858         }
5859
5860         switch (verbs[i].argc_cmp) {
5861
5862         case EQUAL:
5863                 if (left != verbs[i].argc) {
5864                         log_error("Invalid number of arguments.");
5865                         return -EINVAL;
5866                 }
5867
5868                 break;
5869
5870         case MORE:
5871                 if (left < verbs[i].argc) {
5872                         log_error("Too few arguments.");
5873                         return -EINVAL;
5874                 }
5875
5876                 break;
5877
5878         case LESS:
5879                 if (left > verbs[i].argc) {
5880                         log_error("Too many arguments.");
5881                         return -EINVAL;
5882                 }
5883
5884                 break;
5885
5886         default:
5887                 assert_not_reached("Unknown comparison operator.");
5888         }
5889
5890         /* Require a bus connection for all operations but
5891          * enable/disable */
5892         if (!streq(verbs[i].verb, "enable") &&
5893             !streq(verbs[i].verb, "disable") &&
5894             !streq(verbs[i].verb, "is-enabled") &&
5895             !streq(verbs[i].verb, "list-unit-files") &&
5896             !streq(verbs[i].verb, "reenable") &&
5897             !streq(verbs[i].verb, "preset") &&
5898             !streq(verbs[i].verb, "mask") &&
5899             !streq(verbs[i].verb, "unmask") &&
5900             !streq(verbs[i].verb, "link") &&
5901             !streq(verbs[i].verb, "set-default") &&
5902             !streq(verbs[i].verb, "get-default")) {
5903
5904                 if (running_in_chroot() > 0) {
5905                         log_info("Running in chroot, ignoring request.");
5906                         return 0;
5907                 }
5908
5909                 if (((!streq(verbs[i].verb, "reboot") &&
5910                       !streq(verbs[i].verb, "halt") &&
5911                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5912                         log_error("Failed to get D-Bus connection: %s",
5913                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5914                         return -EIO;
5915                 }
5916
5917         } else {
5918
5919                 if (!bus && !avoid_bus()) {
5920                         log_error("Failed to get D-Bus connection: %s",
5921                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5922                         return -EIO;
5923                 }
5924         }
5925
5926         return verbs[i].dispatch(bus, argv + optind);
5927 }
5928
5929 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5930         _cleanup_close_ int fd;
5931         struct sd_shutdown_command c = {
5932                 .usec = t,
5933                 .mode = mode,
5934                 .dry_run = dry_run,
5935                 .warn_wall = warn,
5936         };
5937         union sockaddr_union sockaddr = {
5938                 .un.sun_family = AF_UNIX,
5939                 .un.sun_path = "/run/systemd/shutdownd",
5940         };
5941         struct iovec iovec[2] = {
5942                 {.iov_base = (char*) &c,
5943                  .iov_len = offsetof(struct sd_shutdown_command, wall_message),
5944                 }
5945         };
5946         struct msghdr msghdr = {
5947                 .msg_name = &sockaddr,
5948                 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
5949                                + sizeof("/run/systemd/shutdownd") - 1,
5950                 .msg_iov = iovec,
5951                 .msg_iovlen = 1,
5952         };
5953
5954         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5955         if (fd < 0)
5956                 return -errno;
5957
5958         if (!isempty(message)) {
5959                 iovec[1].iov_base = (char*) message;
5960                 iovec[1].iov_len = strlen(message);
5961                 msghdr.msg_iovlen++;
5962         }
5963
5964         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
5965                 return -errno;
5966
5967         return 0;
5968 }
5969
5970 static int reload_with_fallback(DBusConnection *bus) {
5971
5972         if (bus) {
5973                 /* First, try systemd via D-Bus. */
5974                 if (daemon_reload(bus, NULL) >= 0)
5975                         return 0;
5976         }
5977
5978         /* Nothing else worked, so let's try signals */
5979         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5980
5981         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5982                 log_error("kill() failed: %m");
5983                 return -errno;
5984         }
5985
5986         return 0;
5987 }
5988
5989 static int start_with_fallback(DBusConnection *bus) {
5990
5991         if (bus) {
5992                 /* First, try systemd via D-Bus. */
5993                 if (start_unit(bus, NULL) >= 0)
5994                         goto done;
5995         }
5996
5997         /* Hmm, talking to systemd via D-Bus didn't work. Then
5998          * let's try to talk to Upstart via D-Bus. */
5999         if (talk_upstart() > 0)
6000                 goto done;
6001
6002         /* Nothing else worked, so let's try
6003          * /dev/initctl */
6004         if (talk_initctl() > 0)
6005                 goto done;
6006
6007         log_error("Failed to talk to init daemon.");
6008         return -EIO;
6009
6010 done:
6011         warn_wall(arg_action);
6012         return 0;
6013 }
6014
6015 static _noreturn_ void halt_now(enum action a) {
6016
6017        /* Make sure C-A-D is handled by the kernel from this
6018          * point on... */
6019         reboot(RB_ENABLE_CAD);
6020
6021         switch (a) {
6022
6023         case ACTION_HALT:
6024                 log_info("Halting.");
6025                 reboot(RB_HALT_SYSTEM);
6026                 break;
6027
6028         case ACTION_POWEROFF:
6029                 log_info("Powering off.");
6030                 reboot(RB_POWER_OFF);
6031                 break;
6032
6033         case ACTION_REBOOT:
6034                 log_info("Rebooting.");
6035                 reboot(RB_AUTOBOOT);
6036                 break;
6037
6038         default:
6039                 assert_not_reached("Unknown halt action.");
6040         }
6041
6042         assert_not_reached("Uh? This shouldn't happen.");
6043 }
6044
6045 static int halt_main(DBusConnection *bus) {
6046         int r;
6047
6048         r = check_inhibitors(bus, arg_action);
6049         if (r < 0)
6050                 return r;
6051
6052         if (geteuid() != 0) {
6053                 /* Try logind if we are a normal user and no special
6054                  * mode applies. Maybe PolicyKit allows us to shutdown
6055                  * the machine. */
6056
6057                 if (arg_when <= 0 &&
6058                     !arg_dry &&
6059                     arg_force <= 0 &&
6060                     (arg_action == ACTION_POWEROFF ||
6061                      arg_action == ACTION_REBOOT)) {
6062                         r = reboot_with_logind(bus, arg_action);
6063                         if (r >= 0)
6064                                 return r;
6065                 }
6066
6067                 log_error("Must be root.");
6068                 return -EPERM;
6069         }
6070
6071         if (arg_when > 0) {
6072                 _cleanup_free_ char *m;
6073
6074                 m = strv_join(arg_wall, " ");
6075                 r = send_shutdownd(arg_when,
6076                                    arg_action == ACTION_HALT     ? 'H' :
6077                                    arg_action == ACTION_POWEROFF ? 'P' :
6078                                    arg_action == ACTION_KEXEC    ? 'K' :
6079                                                                    'r',
6080                                    arg_dry,
6081                                    !arg_no_wall,
6082                                    m);
6083
6084                 if (r < 0)
6085                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
6086                 else {
6087                         char date[FORMAT_TIMESTAMP_MAX];
6088
6089                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6090                                  format_timestamp(date, sizeof(date), arg_when));
6091                         return 0;
6092                 }
6093         }
6094
6095         if (!arg_dry && !arg_force)
6096                 return start_with_fallback(bus);
6097
6098         if (!arg_no_wtmp) {
6099                 if (sd_booted() > 0)
6100                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
6101                 else {
6102                         r = utmp_put_shutdown();
6103                         if (r < 0)
6104                                 log_warning("Failed to write utmp record: %s", strerror(-r));
6105                 }
6106         }
6107
6108         if (arg_dry)
6109                 return 0;
6110
6111         halt_now(arg_action);
6112         /* We should never reach this. */
6113         return -ENOSYS;
6114 }
6115
6116 static int runlevel_main(void) {
6117         int r, runlevel, previous;
6118
6119         r = utmp_get_runlevel(&runlevel, &previous);
6120         if (r < 0) {
6121                 puts("unknown");
6122                 return r;
6123         }
6124
6125         printf("%c %c\n",
6126                previous <= 0 ? 'N' : previous,
6127                runlevel <= 0 ? 'N' : runlevel);
6128
6129         return 0;
6130 }
6131
6132 int main(int argc, char*argv[]) {
6133         int r, retval = EXIT_FAILURE;
6134         DBusConnection *bus = NULL;
6135         _cleanup_dbus_error_free_ DBusError error;
6136
6137         dbus_error_init(&error);
6138
6139         setlocale(LC_ALL, "");
6140         log_parse_environment();
6141         log_open();
6142
6143         r = parse_argv(argc, argv);
6144         if (r < 0)
6145                 goto finish;
6146         else if (r == 0) {
6147                 retval = EXIT_SUCCESS;
6148                 goto finish;
6149         }
6150
6151         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6152          * let's shortcut this */
6153         if (arg_action == ACTION_RUNLEVEL) {
6154                 r = runlevel_main();
6155                 retval = r < 0 ? EXIT_FAILURE : r;
6156                 goto finish;
6157         }
6158
6159         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6160                 log_info("Running in chroot, ignoring request.");
6161                 retval = 0;
6162                 goto finish;
6163         }
6164
6165         if (!avoid_bus()) {
6166                 if (arg_transport == TRANSPORT_NORMAL)
6167                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
6168                 else if (arg_transport == TRANSPORT_POLKIT) {
6169                         bus_connect_system_polkit(&bus, &error);
6170                         private_bus = false;
6171                 } else if (arg_transport == TRANSPORT_SSH) {
6172                         bus_connect_system_ssh(arg_user, arg_host, &bus, &error);
6173                         private_bus = false;
6174                 } else
6175                         assert_not_reached("Uh, invalid transport...");
6176         }
6177
6178         switch (arg_action) {
6179
6180         case ACTION_SYSTEMCTL:
6181                 r = systemctl_main(bus, argc, argv, &error);
6182                 break;
6183
6184         case ACTION_HALT:
6185         case ACTION_POWEROFF:
6186         case ACTION_REBOOT:
6187         case ACTION_KEXEC:
6188                 r = halt_main(bus);
6189                 break;
6190
6191         case ACTION_RUNLEVEL2:
6192         case ACTION_RUNLEVEL3:
6193         case ACTION_RUNLEVEL4:
6194         case ACTION_RUNLEVEL5:
6195         case ACTION_RESCUE:
6196         case ACTION_EMERGENCY:
6197         case ACTION_DEFAULT:
6198                 r = start_with_fallback(bus);
6199                 break;
6200
6201         case ACTION_RELOAD:
6202         case ACTION_REEXEC:
6203                 r = reload_with_fallback(bus);
6204                 break;
6205
6206         case ACTION_CANCEL_SHUTDOWN: {
6207                 char *m = NULL;
6208
6209                 if (arg_wall) {
6210                         m = strv_join(arg_wall, " ");
6211                         if (!m) {
6212                                 retval = EXIT_FAILURE;
6213                                 goto finish;
6214                         }
6215                 }
6216                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6217                 if (r < 0)
6218                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
6219                 free(m);
6220                 break;
6221         }
6222
6223         case ACTION_INVALID:
6224         case ACTION_RUNLEVEL:
6225         default:
6226                 assert_not_reached("Unknown action");
6227         }
6228
6229         retval = r < 0 ? EXIT_FAILURE : r;
6230
6231 finish:
6232         if (bus) {
6233                 dbus_connection_flush(bus);
6234                 dbus_connection_close(bus);
6235                 dbus_connection_unref(bus);
6236         }
6237
6238         dbus_shutdown();
6239
6240         strv_free(arg_types);
6241         strv_free(arg_states);
6242         strv_free(arg_properties);
6243
6244         pager_close();
6245         ask_password_agent_close();
6246         polkit_agent_close();
6247
6248         return retval;
6249 }