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