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