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