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