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