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