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