chiark / gitweb /
systemctl: allow comma sepearted property lists
[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 enum action verb_to_action(const char *verb) {
1522         if (streq(verb, "halt"))
1523                 return ACTION_HALT;
1524         else if (streq(verb, "poweroff"))
1525                 return ACTION_POWEROFF;
1526         else if (streq(verb, "reboot"))
1527                 return ACTION_REBOOT;
1528         else if (streq(verb, "kexec"))
1529                 return ACTION_KEXEC;
1530         else if (streq(verb, "rescue"))
1531                 return ACTION_RESCUE;
1532         else if (streq(verb, "emergency"))
1533                 return ACTION_EMERGENCY;
1534         else if (streq(verb, "default"))
1535                 return ACTION_DEFAULT;
1536         else if (streq(verb, "exit"))
1537                 return ACTION_EXIT;
1538         else if (streq(verb, "suspend"))
1539                 return ACTION_SUSPEND;
1540         else if (streq(verb, "hibernate"))
1541                 return ACTION_HIBERNATE;
1542         else if (streq(verb, "hybrid-sleep"))
1543                 return ACTION_HYBRID_SLEEP;
1544         else
1545                 return ACTION_INVALID;
1546 }
1547
1548 static int start_unit(DBusConnection *bus, char **args) {
1549
1550         static const char * const table[_ACTION_MAX] = {
1551                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1552                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1553                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1554                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1555                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1556                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1557                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1558                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1559                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1560                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1561                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1562                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1563                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1564                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
1565                 [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
1566         };
1567
1568         int r, ret = 0;
1569         const char *method, *mode, *one_name;
1570         Set _cleanup_set_free_free_ *s = NULL;
1571         DBusError _cleanup_dbus_error_free_ error;
1572         char **name;
1573
1574         dbus_error_init(&error);
1575
1576         assert(bus);
1577
1578         ask_password_agent_open_if_enabled();
1579
1580         if (arg_action == ACTION_SYSTEMCTL) {
1581                 method =
1582                         streq(args[0], "stop") ||
1583                         streq(args[0], "condstop")              ? "StopUnit" :
1584                         streq(args[0], "reload")                ? "ReloadUnit" :
1585                         streq(args[0], "restart")               ? "RestartUnit" :
1586
1587                         streq(args[0], "try-restart")           ||
1588                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1589
1590                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1591
1592                         streq(args[0], "reload-or-try-restart") ||
1593                         streq(args[0], "condreload") ||
1594
1595                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1596                                                                   "StartUnit";
1597
1598                 mode =
1599                         (streq(args[0], "isolate") ||
1600                          streq(args[0], "rescue")  ||
1601                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1602
1603                 one_name = table[verb_to_action(args[0])];
1604
1605         } else {
1606                 assert(arg_action < ELEMENTSOF(table));
1607                 assert(table[arg_action]);
1608
1609                 method = "StartUnit";
1610
1611                 mode = (arg_action == ACTION_EMERGENCY ||
1612                         arg_action == ACTION_RESCUE ||
1613                         arg_action == ACTION_RUNLEVEL2 ||
1614                         arg_action == ACTION_RUNLEVEL3 ||
1615                         arg_action == ACTION_RUNLEVEL4 ||
1616                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1617
1618                 one_name = table[arg_action];
1619         }
1620
1621         if (!arg_no_block) {
1622                 ret = enable_wait_for_jobs(bus);
1623                 if (ret < 0) {
1624                         log_error("Could not watch jobs: %s", strerror(-ret));
1625                         return ret;
1626                 }
1627
1628                 s = set_new(string_hash_func, string_compare_func);
1629                 if (!s)
1630                         return log_oom();
1631         }
1632
1633         if (one_name) {
1634                 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1635                 if (ret < 0)
1636                         ret = translate_bus_error_to_exit_status(ret, &error);
1637         } else {
1638                 STRV_FOREACH(name, args+1) {
1639                         r = start_unit_one(bus, method, *name, mode, &error, s);
1640                         if (r < 0) {
1641                                 ret = translate_bus_error_to_exit_status(r, &error);
1642                                 dbus_error_free(&error);
1643                         }
1644                 }
1645         }
1646
1647         if (!arg_no_block) {
1648                 r = wait_for_jobs(bus, s);
1649                 if (r < 0)
1650                         return r;
1651
1652                 /* When stopping units, warn if they can still be triggered by
1653                  * another active unit (socket, path, timer) */
1654                 if (!arg_quiet && streq(method, "StopUnit")) {
1655                         if (one_name)
1656                                 check_triggering_units(bus, one_name);
1657                         else
1658                                 STRV_FOREACH(name, args+1)
1659                                         check_triggering_units(bus, *name);
1660                 }
1661         }
1662
1663         return ret;
1664 }
1665
1666 /* Ask systemd-logind, which might grant access to unprivileged users
1667  * through PolicyKit */
1668 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1669 #ifdef HAVE_LOGIND
1670         const char *method;
1671         dbus_bool_t interactive = true;
1672
1673         if (!bus)
1674                 return -EIO;
1675
1676         polkit_agent_open_if_enabled();
1677
1678         switch (a) {
1679
1680         case ACTION_REBOOT:
1681                 method = "Reboot";
1682                 break;
1683
1684         case ACTION_POWEROFF:
1685                 method = "PowerOff";
1686                 break;
1687
1688         case ACTION_SUSPEND:
1689                 method = "Suspend";
1690                 break;
1691
1692         case ACTION_HIBERNATE:
1693                 method = "Hibernate";
1694                 break;
1695
1696         case ACTION_HYBRID_SLEEP:
1697                 method = "HybridSleep";
1698                 break;
1699
1700         default:
1701                 return -EINVAL;
1702         }
1703
1704         return bus_method_call_with_reply(
1705                         bus,
1706                         "org.freedesktop.login1",
1707                         "/org/freedesktop/login1",
1708                         "org.freedesktop.login1.Manager",
1709                         method,
1710                         NULL,
1711                         NULL,
1712                         DBUS_TYPE_BOOLEAN, &interactive,
1713                         DBUS_TYPE_INVALID);
1714 #else
1715         return -ENOSYS;
1716 #endif
1717 }
1718
1719 static int check_inhibitors(DBusConnection *bus, enum action a) {
1720 #ifdef HAVE_LOGIND
1721         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1722         DBusMessageIter iter, sub, sub2;
1723         int r;
1724         unsigned c = 0;
1725         _cleanup_strv_free_ char **sessions = NULL;
1726         char **s;
1727
1728         if (!bus)
1729                 return 0;
1730
1731         if (arg_ignore_inhibitors || arg_force > 0)
1732                 return 0;
1733
1734         if (arg_when > 0)
1735                 return 0;
1736
1737         if (geteuid() == 0)
1738                 return 0;
1739
1740         if (!on_tty())
1741                 return 0;
1742
1743         r = bus_method_call_with_reply(
1744                         bus,
1745                         "org.freedesktop.login1",
1746                         "/org/freedesktop/login1",
1747                         "org.freedesktop.login1.Manager",
1748                         "ListInhibitors",
1749                         &reply,
1750                         NULL,
1751                         DBUS_TYPE_INVALID);
1752         if (r < 0)
1753                 /* If logind is not around, then there are no inhibitors... */
1754                 return 0;
1755
1756         if (!dbus_message_iter_init(reply, &iter) ||
1757             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1758             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1759                 log_error("Failed to parse reply.");
1760                 return -EIO;
1761         }
1762
1763         dbus_message_iter_recurse(&iter, &sub);
1764         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1765                 const char *what, *who, *why, *mode;
1766                 uint32_t uid, pid;
1767                 _cleanup_strv_free_ char **sv = NULL;
1768                 _cleanup_free_ char *comm = NULL, *user = NULL;
1769
1770                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1771                         log_error("Failed to parse reply.");
1772                         return -EIO;
1773                 }
1774
1775                 dbus_message_iter_recurse(&sub, &sub2);
1776
1777                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1778                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1779                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1780                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1781                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1782                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1783                         log_error("Failed to parse reply.");
1784                         return -EIO;
1785                 }
1786
1787                 if (!streq(mode, "block"))
1788                         goto next;
1789
1790                 sv = strv_split(what, ":");
1791                 if (!sv)
1792                         return log_oom();
1793
1794                 if (!strv_contains(sv,
1795                                   a == ACTION_HALT ||
1796                                   a == ACTION_POWEROFF ||
1797                                   a == ACTION_REBOOT ||
1798                                   a == ACTION_KEXEC ? "shutdown" : "sleep"))
1799                         goto next;
1800
1801                 get_process_comm(pid, &comm);
1802                 user = uid_to_name(uid);
1803                 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
1804                             who, (unsigned long) pid, strna(comm), strna(user), why);
1805                 c++;
1806
1807         next:
1808                 dbus_message_iter_next(&sub);
1809         }
1810
1811         dbus_message_iter_recurse(&iter, &sub);
1812
1813         /* Check for current sessions */
1814         sd_get_sessions(&sessions);
1815         STRV_FOREACH(s, sessions) {
1816                 uid_t uid;
1817                 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1818
1819                 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1820                         continue;
1821
1822                 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1823                         continue;
1824
1825                 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1826                         continue;
1827
1828                 sd_session_get_tty(*s, &tty);
1829                 sd_session_get_seat(*s, &seat);
1830                 sd_session_get_service(*s, &service);
1831                 user = uid_to_name(uid);
1832
1833                 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1834                 c++;
1835         }
1836
1837         if (c <= 0)
1838                 return 0;
1839
1840         log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
1841                   a == ACTION_HALT ? "halt" :
1842                   a == ACTION_POWEROFF ? "poweroff" :
1843                   a == ACTION_REBOOT ? "reboot" :
1844                   a == ACTION_KEXEC ? "kexec" :
1845                   a == ACTION_SUSPEND ? "suspend" :
1846                   a == ACTION_HIBERNATE ? "hibernate" : "hybrid-sleep");
1847
1848         return -EPERM;
1849 #else
1850         return 0;
1851 #endif
1852 }
1853
1854 static int start_special(DBusConnection *bus, char **args) {
1855         enum action a;
1856         int r;
1857
1858         assert(args);
1859
1860         a = verb_to_action(args[0]);
1861
1862         r = check_inhibitors(bus, a);
1863         if (r < 0)
1864                 return r;
1865
1866         if (arg_force >= 2 && geteuid() != 0) {
1867                 log_error("Must be root.");
1868                 return -EPERM;
1869         }
1870
1871         if (arg_force >= 2 &&
1872             (a == ACTION_HALT ||
1873              a == ACTION_POWEROFF ||
1874              a == ACTION_REBOOT))
1875                 halt_now(a);
1876
1877         if (arg_force >= 1 &&
1878             (a == ACTION_HALT ||
1879              a == ACTION_POWEROFF ||
1880              a == ACTION_REBOOT ||
1881              a == ACTION_KEXEC ||
1882              a == ACTION_EXIT))
1883                 return daemon_reload(bus, args);
1884
1885         /* first try logind, to allow authentication with polkit */
1886         if (geteuid() != 0 &&
1887             (a == ACTION_POWEROFF ||
1888              a == ACTION_REBOOT ||
1889              a == ACTION_SUSPEND ||
1890              a == ACTION_HIBERNATE ||
1891              a == ACTION_HYBRID_SLEEP)) {
1892                 r = reboot_with_logind(bus, a);
1893                 if (r >= 0)
1894                         return r;
1895         }
1896
1897         r = start_unit(bus, args);
1898         if (r == EXIT_SUCCESS)
1899                 warn_wall(a);
1900
1901         return r;
1902 }
1903
1904 static int check_unit_active(DBusConnection *bus, char **args) {
1905         const char * const check_states[] = {
1906                 "active",
1907                 "reloading",
1908                 NULL
1909         };
1910
1911         char **name;
1912         int r = 3; /* According to LSB: "program is not running" */
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 check_unit_failed(DBusConnection *bus, char **args) {
1931         const char * const check_states[] = {
1932                 "failed",
1933                 NULL
1934         };
1935
1936         char **name;
1937         int r = 1;
1938
1939         assert(bus);
1940         assert(args);
1941
1942         STRV_FOREACH(name, args+1) {
1943                 int state;
1944
1945                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1946                 if (state < 0)
1947                         return state;
1948                 if (state > 0)
1949                         r = 0;
1950         }
1951
1952         return r;
1953 }
1954
1955 static int kill_unit(DBusConnection *bus, char **args) {
1956         char **name;
1957         int r = 0;
1958
1959         assert(bus);
1960         assert(args);
1961
1962         if (!arg_kill_who)
1963                 arg_kill_who = "all";
1964
1965         STRV_FOREACH(name, args+1) {
1966                 _cleanup_free_ char *n = NULL;
1967
1968                 n = unit_name_mangle(*name);
1969                 if (!n)
1970                         return log_oom();
1971
1972                 r = bus_method_call_with_reply(
1973                                 bus,
1974                                 "org.freedesktop.systemd1",
1975                                 "/org/freedesktop/systemd1",
1976                                 "org.freedesktop.systemd1.Manager",
1977                                 "KillUnit",
1978                                 NULL,
1979                                 NULL,
1980                                 DBUS_TYPE_STRING, &n,
1981                                 DBUS_TYPE_STRING, &arg_kill_who,
1982                                 DBUS_TYPE_INT32, &arg_signal,
1983                                 DBUS_TYPE_INVALID);
1984                 if (r < 0)
1985                         return r;
1986         }
1987         return 0;
1988 }
1989
1990 static int set_cgroup(DBusConnection *bus, char **args) {
1991         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
1992         DBusError error;
1993         const char *method;
1994         DBusMessageIter iter;
1995         int r;
1996         _cleanup_free_ char *n = NULL;
1997         const char *runtime;
1998
1999         assert(bus);
2000         assert(args);
2001
2002         dbus_error_init(&error);
2003
2004         method =
2005                 streq(args[0], "set-cgroup")  ? "SetUnitControlGroups" :
2006                 streq(args[0], "unset-group") ? "UnsetUnitControlGroups"
2007                                               : "UnsetUnitControlGroupAttributes";
2008
2009         n = unit_name_mangle(args[1]);
2010         if (!n)
2011                 return log_oom();
2012
2013         m = dbus_message_new_method_call(
2014                         "org.freedesktop.systemd1",
2015                         "/org/freedesktop/systemd1",
2016                         "org.freedesktop.systemd1.Manager",
2017                         method);
2018         if (!m)
2019                 return log_oom();
2020
2021         dbus_message_iter_init_append(m, &iter);
2022         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2023                 return log_oom();
2024
2025         r = bus_append_strv_iter(&iter, args + 2);
2026         if (r < 0)
2027                 return log_oom();
2028
2029         runtime = arg_runtime ? "runtime" : "persistent";
2030         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2031                 return log_oom();
2032
2033         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2034         if (!reply) {
2035                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2036                 dbus_error_free(&error);
2037                 return -EIO;
2038         }
2039
2040         return 0;
2041 }
2042
2043 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2044         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2045         DBusError error;
2046         DBusMessageIter iter, sub, sub2;
2047         char **x, **y;
2048         _cleanup_free_ char *n = NULL;
2049         const char *runtime;
2050
2051         assert(bus);
2052         assert(args);
2053
2054         dbus_error_init(&error);
2055
2056         if (strv_length(args) % 2 != 0) {
2057                 log_error("Expecting an uneven number of arguments!");
2058                 return -EINVAL;
2059         }
2060
2061         n = unit_name_mangle(args[1]);
2062         if (!n)
2063                 return log_oom();
2064
2065         m = dbus_message_new_method_call(
2066                         "org.freedesktop.systemd1",
2067                         "/org/freedesktop/systemd1",
2068                         "org.freedesktop.systemd1.Manager",
2069                         "SetUnitControlGroupAttributes");
2070         if (!m)
2071                 return log_oom();
2072
2073         dbus_message_iter_init_append(m, &iter);
2074         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2075             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub))
2076                 return log_oom();
2077
2078         STRV_FOREACH_PAIR(x, y, args + 2) {
2079                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2080                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) ||
2081                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) ||
2082                     !dbus_message_iter_close_container(&sub, &sub2))
2083                         return log_oom();
2084         }
2085
2086         runtime = arg_runtime ? "runtime" : "persistent";
2087         if (!dbus_message_iter_close_container(&iter, &sub) ||
2088             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2089                 return log_oom();
2090
2091         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2092         if (!reply) {
2093                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2094                 dbus_error_free(&error);
2095                 return -EIO;
2096         }
2097
2098         return 0;
2099 }
2100
2101 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2102         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2103         DBusError error;
2104         DBusMessageIter iter;
2105         int r;
2106         _cleanup_free_ char *n = NULL;
2107         _cleanup_strv_free_ char **list = NULL;
2108         char **a;
2109
2110         assert(bus);
2111         assert(args);
2112
2113         dbus_error_init(&error);
2114
2115         n = unit_name_mangle(args[1]);
2116         if (!n)
2117                 return log_oom();
2118
2119         m = dbus_message_new_method_call(
2120                         "org.freedesktop.systemd1",
2121                         "/org/freedesktop/systemd1",
2122                         "org.freedesktop.systemd1.Manager",
2123                         "GetUnitControlGroupAttributes");
2124         if (!m)
2125                 return log_oom();
2126
2127         dbus_message_iter_init_append(m, &iter);
2128         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2129                 return log_oom();
2130
2131         r = bus_append_strv_iter(&iter, args + 2);
2132         if (r < 0)
2133                 return log_oom();
2134
2135         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2136         if (!reply) {
2137                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2138                 dbus_error_free(&error);
2139                 return -EIO;
2140         }
2141
2142         dbus_message_iter_init(reply, &iter);
2143         r = bus_parse_strv_iter(&iter, &list);
2144         if (r < 0) {
2145                 log_error("Failed to parse value list.");
2146                 return r;
2147         }
2148
2149         STRV_FOREACH(a, list) {
2150                 if (endswith(*a, "\n"))
2151                         fputs(*a, stdout);
2152                 else
2153                         puts(*a);
2154         }
2155
2156         return 0;
2157 }
2158
2159 typedef struct ExecStatusInfo {
2160         char *name;
2161
2162         char *path;
2163         char **argv;
2164
2165         bool ignore;
2166
2167         usec_t start_timestamp;
2168         usec_t exit_timestamp;
2169         pid_t pid;
2170         int code;
2171         int status;
2172
2173         LIST_FIELDS(struct ExecStatusInfo, exec);
2174 } ExecStatusInfo;
2175
2176 static void exec_status_info_free(ExecStatusInfo *i) {
2177         assert(i);
2178
2179         free(i->name);
2180         free(i->path);
2181         strv_free(i->argv);
2182         free(i);
2183 }
2184
2185 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2186         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2187         DBusMessageIter sub2, sub3;
2188         const char*path;
2189         unsigned n;
2190         uint32_t pid;
2191         int32_t code, status;
2192         dbus_bool_t ignore;
2193
2194         assert(i);
2195         assert(i);
2196
2197         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2198                 return -EIO;
2199
2200         dbus_message_iter_recurse(sub, &sub2);
2201
2202         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2203                 return -EIO;
2204
2205         i->path = strdup(path);
2206         if (!i->path)
2207                 return -ENOMEM;
2208
2209         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2210             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2211                 return -EIO;
2212
2213         n = 0;
2214         dbus_message_iter_recurse(&sub2, &sub3);
2215         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2216                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2217                 dbus_message_iter_next(&sub3);
2218                 n++;
2219         }
2220
2221         i->argv = new0(char*, n+1);
2222         if (!i->argv)
2223                 return -ENOMEM;
2224
2225         n = 0;
2226         dbus_message_iter_recurse(&sub2, &sub3);
2227         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2228                 const char *s;
2229
2230                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2231                 dbus_message_iter_get_basic(&sub3, &s);
2232                 dbus_message_iter_next(&sub3);
2233
2234                 i->argv[n] = strdup(s);
2235                 if (!i->argv[n])
2236                         return -ENOMEM;
2237
2238                 n++;
2239         }
2240
2241         if (!dbus_message_iter_next(&sub2) ||
2242             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2243             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2244             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2245             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2246             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2247             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2248             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2249             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2250                 return -EIO;
2251
2252         i->ignore = ignore;
2253         i->start_timestamp = (usec_t) start_timestamp;
2254         i->exit_timestamp = (usec_t) exit_timestamp;
2255         i->pid = (pid_t) pid;
2256         i->code = code;
2257         i->status = status;
2258
2259         return 0;
2260 }
2261
2262 typedef struct UnitStatusInfo {
2263         const char *id;
2264         const char *load_state;
2265         const char *active_state;
2266         const char *sub_state;
2267         const char *unit_file_state;
2268
2269         const char *description;
2270         const char *following;
2271
2272         char **documentation;
2273
2274         const char *fragment_path;
2275         const char *source_path;
2276         const char *default_control_group;
2277
2278         const char *load_error;
2279         const char *result;
2280
2281         usec_t inactive_exit_timestamp;
2282         usec_t inactive_exit_timestamp_monotonic;
2283         usec_t active_enter_timestamp;
2284         usec_t active_exit_timestamp;
2285         usec_t inactive_enter_timestamp;
2286
2287         bool need_daemon_reload;
2288
2289         /* Service */
2290         pid_t main_pid;
2291         pid_t control_pid;
2292         const char *status_text;
2293         bool running:1;
2294
2295         usec_t start_timestamp;
2296         usec_t exit_timestamp;
2297
2298         int exit_code, exit_status;
2299
2300         usec_t condition_timestamp;
2301         bool condition_result;
2302
2303         /* Socket */
2304         unsigned n_accepted;
2305         unsigned n_connections;
2306         bool accept;
2307
2308         /* Device */
2309         const char *sysfs_path;
2310
2311         /* Mount, Automount */
2312         const char *where;
2313
2314         /* Swap */
2315         const char *what;
2316
2317         LIST_HEAD(ExecStatusInfo, exec);
2318 } UnitStatusInfo;
2319
2320 static void print_status_info(UnitStatusInfo *i) {
2321         ExecStatusInfo *p;
2322         const char *on, *off, *ss;
2323         usec_t timestamp;
2324         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2325         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2326         const char *path;
2327         int flags =
2328                 arg_all * OUTPUT_SHOW_ALL |
2329                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2330                 on_tty() * OUTPUT_COLOR |
2331                 !arg_quiet * OUTPUT_WARN_CUTOFF |
2332                 arg_full * OUTPUT_FULL_WIDTH;
2333
2334         assert(i);
2335
2336         /* This shows pretty information about a unit. See
2337          * print_property() for a low-level property printer */
2338
2339         printf("%s", strna(i->id));
2340
2341         if (i->description && !streq_ptr(i->id, i->description))
2342                 printf(" - %s", i->description);
2343
2344         printf("\n");
2345
2346         if (i->following)
2347                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2348
2349         if (streq_ptr(i->load_state, "error")) {
2350                 on = ansi_highlight_red(true);
2351                 off = ansi_highlight_red(false);
2352         } else
2353                 on = off = "";
2354
2355         path = i->source_path ? i->source_path : i->fragment_path;
2356
2357         if (i->load_error)
2358                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2359         else if (path && i->unit_file_state)
2360                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2361         else if (path)
2362                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2363         else
2364                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2365
2366         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2367
2368         if (streq_ptr(i->active_state, "failed")) {
2369                 on = ansi_highlight_red(true);
2370                 off = ansi_highlight_red(false);
2371         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2372                 on = ansi_highlight_green(true);
2373                 off = ansi_highlight_green(false);
2374         } else
2375                 on = off = "";
2376
2377         if (ss)
2378                 printf("\t  Active: %s%s (%s)%s",
2379                        on,
2380                        strna(i->active_state),
2381                        ss,
2382                        off);
2383         else
2384                 printf("\t  Active: %s%s%s",
2385                        on,
2386                        strna(i->active_state),
2387                        off);
2388
2389         if (!isempty(i->result) && !streq(i->result, "success"))
2390                 printf(" (Result: %s)", i->result);
2391
2392         timestamp = (streq_ptr(i->active_state, "active")      ||
2393                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2394                     (streq_ptr(i->active_state, "inactive")    ||
2395                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2396                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2397                                                                   i->active_exit_timestamp;
2398
2399         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2400         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2401
2402         if (s1)
2403                 printf(" since %s; %s\n", s2, s1);
2404         else if (s2)
2405                 printf(" since %s\n", s2);
2406         else
2407                 printf("\n");
2408
2409         if (!i->condition_result && i->condition_timestamp > 0) {
2410                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2411                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2412
2413                 if (s1)
2414                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2415                 else if (s2)
2416                         printf("\t          start condition failed at %s\n", s2);
2417         }
2418
2419         if (i->sysfs_path)
2420                 printf("\t  Device: %s\n", i->sysfs_path);
2421         if (i->where)
2422                 printf("\t   Where: %s\n", i->where);
2423         if (i->what)
2424                 printf("\t    What: %s\n", i->what);
2425
2426         if (!strv_isempty(i->documentation)) {
2427                 char **t;
2428                 bool first = true;
2429
2430                 STRV_FOREACH(t, i->documentation) {
2431                         if (first) {
2432                                 printf("\t    Docs: %s\n", *t);
2433                                 first = false;
2434                         } else
2435                                 printf("\t          %s\n", *t);
2436                 }
2437         }
2438
2439         if (i->accept)
2440                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2441
2442         LIST_FOREACH(exec, p, i->exec) {
2443                 _cleanup_free_ char *t = NULL;
2444                 bool good;
2445
2446                 /* Only show exited processes here */
2447                 if (p->code == 0)
2448                         continue;
2449
2450                 t = strv_join(p->argv, " ");
2451                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2452
2453                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2454                 if (!good) {
2455                         on = ansi_highlight_red(true);
2456                         off = ansi_highlight_red(false);
2457                 } else
2458                         on = off = "";
2459
2460                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2461
2462                 if (p->code == CLD_EXITED) {
2463                         const char *c;
2464
2465                         printf("status=%i", p->status);
2466
2467                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2468                         if (c)
2469                                 printf("/%s", c);
2470
2471                 } else
2472                         printf("signal=%s", signal_to_string(p->status));
2473
2474                 printf(")%s\n", off);
2475
2476                 if (i->main_pid == p->pid &&
2477                     i->start_timestamp == p->start_timestamp &&
2478                     i->exit_timestamp == p->start_timestamp)
2479                         /* Let's not show this twice */
2480                         i->main_pid = 0;
2481
2482                 if (p->pid == i->control_pid)
2483                         i->control_pid = 0;
2484         }
2485
2486         if (i->main_pid > 0 || i->control_pid > 0) {
2487                 printf("\t");
2488
2489                 if (i->main_pid > 0) {
2490                         printf("Main PID: %u", (unsigned) i->main_pid);
2491
2492                         if (i->running) {
2493                                 _cleanup_free_ char *t = NULL;
2494                                 get_process_comm(i->main_pid, &t);
2495                                 if (t)
2496                                         printf(" (%s)", t);
2497                         } else if (i->exit_code > 0) {
2498                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2499
2500                                 if (i->exit_code == CLD_EXITED) {
2501                                         const char *c;
2502
2503                                         printf("status=%i", i->exit_status);
2504
2505                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2506                                         if (c)
2507                                                 printf("/%s", c);
2508
2509                                 } else
2510                                         printf("signal=%s", signal_to_string(i->exit_status));
2511                                 printf(")");
2512                         }
2513                 }
2514
2515                 if (i->main_pid > 0 && i->control_pid > 0)
2516                         printf(";");
2517
2518                 if (i->control_pid > 0) {
2519                         _cleanup_free_ char *t = NULL;
2520
2521                         printf(" Control: %u", (unsigned) i->control_pid);
2522
2523                         get_process_comm(i->control_pid, &t);
2524                         if (t)
2525                                 printf(" (%s)", t);
2526                 }
2527
2528                 printf("\n");
2529         }
2530
2531         if (i->status_text)
2532                 printf("\t  Status: \"%s\"\n", i->status_text);
2533
2534         if (i->default_control_group &&
2535             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2536                 unsigned c;
2537
2538                 printf("\t  CGroup: %s\n", i->default_control_group);
2539
2540                 if (arg_transport != TRANSPORT_SSH) {
2541                         unsigned k = 0;
2542                         pid_t extra[2];
2543
2544                         c = columns();
2545                         if (c > 18)
2546                                 c -= 18;
2547                         else
2548                                 c = 0;
2549
2550                         if (i->main_pid > 0)
2551                                 extra[k++] = i->main_pid;
2552
2553                         if (i->control_pid > 0)
2554                                 extra[k++] = i->control_pid;
2555
2556                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, extra, k, flags);
2557                 }
2558         }
2559
2560         if (i->id && arg_transport != TRANSPORT_SSH) {
2561                 printf("\n");
2562                 if(arg_scope == UNIT_FILE_SYSTEM)
2563                         show_journal_by_unit(stdout,
2564                                              i->id,
2565                                              arg_output,
2566                                              0,
2567                                              i->inactive_exit_timestamp_monotonic,
2568                                              arg_lines,
2569                                              flags);
2570                 else
2571                         show_journal_by_user_unit(stdout,
2572                                                   i->id,
2573                                                   arg_output,
2574                                                   0,
2575                                                   i->inactive_exit_timestamp_monotonic,
2576                                                   arg_lines,
2577                                                   getuid(),
2578                                                   flags);
2579         }
2580
2581         if (i->need_daemon_reload)
2582                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2583                        ansi_highlight_red(true),
2584                        ansi_highlight_red(false),
2585                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2586 }
2587
2588 static void show_unit_help(UnitStatusInfo *i) {
2589         char **p;
2590
2591         assert(i);
2592
2593         if (!i->documentation) {
2594                 log_info("Documentation for %s not known.", i->id);
2595                 return;
2596         }
2597
2598         STRV_FOREACH(p, i->documentation) {
2599
2600                 if (startswith(*p, "man:")) {
2601                         size_t k;
2602                         char *e = NULL;
2603                         char _cleanup_free_ *page = NULL, *section = NULL;
2604                         const char *args[4] = { "man", NULL, NULL, NULL };
2605                         pid_t pid;
2606
2607                         k = strlen(*p);
2608
2609                         if ((*p)[k-1] == ')')
2610                                 e = strrchr(*p, '(');
2611
2612                         if (e) {
2613                                 page = strndup((*p) + 4, e - *p - 4);
2614                                 section = strndup(e + 1, *p + k - e - 2);
2615                                 if (!page || !section) {
2616                                         log_oom();
2617                                         return;
2618                                 }
2619
2620                                 args[1] = section;
2621                                 args[2] = page;
2622                         } else
2623                                 args[1] = *p + 4;
2624
2625                         pid = fork();
2626                         if (pid < 0) {
2627                                 log_error("Failed to fork: %m");
2628                                 continue;
2629                         }
2630
2631                         if (pid == 0) {
2632                                 /* Child */
2633                                 execvp(args[0], (char**) args);
2634                                 log_error("Failed to execute man: %m");
2635                                 _exit(EXIT_FAILURE);
2636                         }
2637
2638                         wait_for_terminate(pid, NULL);
2639                 } else
2640                         log_info("Can't show: %s", *p);
2641         }
2642 }
2643
2644 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2645
2646         assert(name);
2647         assert(iter);
2648         assert(i);
2649
2650         switch (dbus_message_iter_get_arg_type(iter)) {
2651
2652         case DBUS_TYPE_STRING: {
2653                 const char *s;
2654
2655                 dbus_message_iter_get_basic(iter, &s);
2656
2657                 if (!isempty(s)) {
2658                         if (streq(name, "Id"))
2659                                 i->id = s;
2660                         else if (streq(name, "LoadState"))
2661                                 i->load_state = s;
2662                         else if (streq(name, "ActiveState"))
2663                                 i->active_state = s;
2664                         else if (streq(name, "SubState"))
2665                                 i->sub_state = s;
2666                         else if (streq(name, "Description"))
2667                                 i->description = s;
2668                         else if (streq(name, "FragmentPath"))
2669                                 i->fragment_path = s;
2670                         else if (streq(name, "SourcePath"))
2671                                 i->source_path = s;
2672                         else if (streq(name, "DefaultControlGroup"))
2673                                 i->default_control_group = s;
2674                         else if (streq(name, "StatusText"))
2675                                 i->status_text = s;
2676                         else if (streq(name, "SysFSPath"))
2677                                 i->sysfs_path = s;
2678                         else if (streq(name, "Where"))
2679                                 i->where = s;
2680                         else if (streq(name, "What"))
2681                                 i->what = s;
2682                         else if (streq(name, "Following"))
2683                                 i->following = s;
2684                         else if (streq(name, "UnitFileState"))
2685                                 i->unit_file_state = s;
2686                         else if (streq(name, "Result"))
2687                                 i->result = s;
2688                 }
2689
2690                 break;
2691         }
2692
2693         case DBUS_TYPE_BOOLEAN: {
2694                 dbus_bool_t b;
2695
2696                 dbus_message_iter_get_basic(iter, &b);
2697
2698                 if (streq(name, "Accept"))
2699                         i->accept = b;
2700                 else if (streq(name, "NeedDaemonReload"))
2701                         i->need_daemon_reload = b;
2702                 else if (streq(name, "ConditionResult"))
2703                         i->condition_result = b;
2704
2705                 break;
2706         }
2707
2708         case DBUS_TYPE_UINT32: {
2709                 uint32_t u;
2710
2711                 dbus_message_iter_get_basic(iter, &u);
2712
2713                 if (streq(name, "MainPID")) {
2714                         if (u > 0) {
2715                                 i->main_pid = (pid_t) u;
2716                                 i->running = true;
2717                         }
2718                 } else if (streq(name, "ControlPID"))
2719                         i->control_pid = (pid_t) u;
2720                 else if (streq(name, "ExecMainPID")) {
2721                         if (u > 0)
2722                                 i->main_pid = (pid_t) u;
2723                 } else if (streq(name, "NAccepted"))
2724                         i->n_accepted = u;
2725                 else if (streq(name, "NConnections"))
2726                         i->n_connections = u;
2727
2728                 break;
2729         }
2730
2731         case DBUS_TYPE_INT32: {
2732                 int32_t j;
2733
2734                 dbus_message_iter_get_basic(iter, &j);
2735
2736                 if (streq(name, "ExecMainCode"))
2737                         i->exit_code = (int) j;
2738                 else if (streq(name, "ExecMainStatus"))
2739                         i->exit_status = (int) j;
2740
2741                 break;
2742         }
2743
2744         case DBUS_TYPE_UINT64: {
2745                 uint64_t u;
2746
2747                 dbus_message_iter_get_basic(iter, &u);
2748
2749                 if (streq(name, "ExecMainStartTimestamp"))
2750                         i->start_timestamp = (usec_t) u;
2751                 else if (streq(name, "ExecMainExitTimestamp"))
2752                         i->exit_timestamp = (usec_t) u;
2753                 else if (streq(name, "ActiveEnterTimestamp"))
2754                         i->active_enter_timestamp = (usec_t) u;
2755                 else if (streq(name, "InactiveEnterTimestamp"))
2756                         i->inactive_enter_timestamp = (usec_t) u;
2757                 else if (streq(name, "InactiveExitTimestamp"))
2758                         i->inactive_exit_timestamp = (usec_t) u;
2759                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2760                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2761                 else if (streq(name, "ActiveExitTimestamp"))
2762                         i->active_exit_timestamp = (usec_t) u;
2763                 else if (streq(name, "ConditionTimestamp"))
2764                         i->condition_timestamp = (usec_t) u;
2765
2766                 break;
2767         }
2768
2769         case DBUS_TYPE_ARRAY: {
2770
2771                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2772                     startswith(name, "Exec")) {
2773                         DBusMessageIter sub;
2774
2775                         dbus_message_iter_recurse(iter, &sub);
2776                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2777                                 ExecStatusInfo *info;
2778                                 int r;
2779
2780                                 if (!(info = new0(ExecStatusInfo, 1)))
2781                                         return -ENOMEM;
2782
2783                                 if (!(info->name = strdup(name))) {
2784                                         free(info);
2785                                         return -ENOMEM;
2786                                 }
2787
2788                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2789                                         free(info);
2790                                         return r;
2791                                 }
2792
2793                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2794
2795                                 dbus_message_iter_next(&sub);
2796                         }
2797                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2798                            streq(name, "Documentation")) {
2799
2800                         DBusMessageIter sub;
2801
2802                         dbus_message_iter_recurse(iter, &sub);
2803                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2804                                 const char *s;
2805                                 char **l;
2806
2807                                 dbus_message_iter_get_basic(&sub, &s);
2808
2809                                 l = strv_append(i->documentation, s);
2810                                 if (!l)
2811                                         return -ENOMEM;
2812
2813                                 strv_free(i->documentation);
2814                                 i->documentation = l;
2815
2816                                 dbus_message_iter_next(&sub);
2817                         }
2818                 }
2819
2820                 break;
2821         }
2822
2823         case DBUS_TYPE_STRUCT: {
2824
2825                 if (streq(name, "LoadError")) {
2826                         DBusMessageIter sub;
2827                         const char *n, *message;
2828                         int r;
2829
2830                         dbus_message_iter_recurse(iter, &sub);
2831
2832                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2833                         if (r < 0)
2834                                 return r;
2835
2836                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2837                         if (r < 0)
2838                                 return r;
2839
2840                         if (!isempty(message))
2841                                 i->load_error = message;
2842                 }
2843
2844                 break;
2845         }
2846         }
2847
2848         return 0;
2849 }
2850
2851 static int print_property(const char *name, DBusMessageIter *iter) {
2852         assert(name);
2853         assert(iter);
2854
2855         /* This is a low-level property printer, see
2856          * print_status_info() for the nicer output */
2857
2858         if (arg_property && !strv_find(arg_property, name))
2859                 return 0;
2860
2861         switch (dbus_message_iter_get_arg_type(iter)) {
2862
2863         case DBUS_TYPE_STRUCT: {
2864                 DBusMessageIter sub;
2865                 dbus_message_iter_recurse(iter, &sub);
2866
2867                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2868                         uint32_t u;
2869
2870                         dbus_message_iter_get_basic(&sub, &u);
2871
2872                         if (u)
2873                                 printf("%s=%u\n", name, (unsigned) u);
2874                         else if (arg_all)
2875                                 printf("%s=\n", name);
2876
2877                         return 0;
2878                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2879                         const char *s;
2880
2881                         dbus_message_iter_get_basic(&sub, &s);
2882
2883                         if (arg_all || s[0])
2884                                 printf("%s=%s\n", name, s);
2885
2886                         return 0;
2887                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2888                         const char *a = NULL, *b = NULL;
2889
2890                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2891                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2892
2893                         if (arg_all || !isempty(a) || !isempty(b))
2894                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2895
2896                         return 0;
2897                 }
2898
2899                 break;
2900         }
2901
2902         case DBUS_TYPE_ARRAY:
2903
2904                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2905                         DBusMessageIter sub, sub2;
2906
2907                         dbus_message_iter_recurse(iter, &sub);
2908                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2909                                 const char *path;
2910                                 dbus_bool_t ignore;
2911
2912                                 dbus_message_iter_recurse(&sub, &sub2);
2913
2914                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2915                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2916                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2917
2918                                 dbus_message_iter_next(&sub);
2919                         }
2920
2921                         return 0;
2922
2923                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2924                         DBusMessageIter sub, sub2;
2925
2926                         dbus_message_iter_recurse(iter, &sub);
2927                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2928                                 const char *type, *path;
2929
2930                                 dbus_message_iter_recurse(&sub, &sub2);
2931
2932                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2933                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2934                                         printf("%s=%s\n", type, path);
2935
2936                                 dbus_message_iter_next(&sub);
2937                         }
2938
2939                         return 0;
2940
2941                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2942                         DBusMessageIter sub, sub2;
2943
2944                         dbus_message_iter_recurse(iter, &sub);
2945                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2946                                 const char *base;
2947                                 uint64_t value, next_elapse;
2948
2949                                 dbus_message_iter_recurse(&sub, &sub2);
2950
2951                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2952                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2953                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2954                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2955
2956                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2957                                                base,
2958                                                format_timespan(timespan1, sizeof(timespan1), value),
2959                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2960                                 }
2961
2962                                 dbus_message_iter_next(&sub);
2963                         }
2964
2965                         return 0;
2966
2967                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2968                         DBusMessageIter sub, sub2;
2969
2970                         dbus_message_iter_recurse(iter, &sub);
2971                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2972                                 const char *controller, *attr, *value;
2973
2974                                 dbus_message_iter_recurse(&sub, &sub2);
2975
2976                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2977                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2978                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2979
2980                                         printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2981                                                controller,
2982                                                attr,
2983                                                value);
2984                                 }
2985
2986                                 dbus_message_iter_next(&sub);
2987                         }
2988
2989                         return 0;
2990
2991                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2992                         DBusMessageIter sub;
2993
2994                         dbus_message_iter_recurse(iter, &sub);
2995                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2996                                 ExecStatusInfo info;
2997
2998                                 zero(info);
2999                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3000                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3001                                         char _cleanup_free_ *t;
3002
3003                                         t = strv_join(info.argv, " ");
3004
3005                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3006                                                name,
3007                                                strna(info.path),
3008                                                strna(t),
3009                                                yes_no(info.ignore),
3010                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3011                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3012                                                (unsigned) info. pid,
3013                                                sigchld_code_to_string(info.code),
3014                                                info.status,
3015                                                info.code == CLD_EXITED ? "" : "/",
3016                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3017                                 }
3018
3019                                 free(info.path);
3020                                 strv_free(info.argv);
3021
3022                                 dbus_message_iter_next(&sub);
3023                         }
3024
3025                         return 0;
3026                 }
3027
3028                 break;
3029         }
3030
3031         if (generic_print_property(name, iter, arg_all) > 0)
3032                 return 0;
3033
3034         if (arg_all)
3035                 printf("%s=[unprintable]\n", name);
3036
3037         return 0;
3038 }
3039
3040 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3041         _cleanup_free_ DBusMessage *reply = NULL;
3042         const char *interface = "";
3043         int r;
3044         DBusMessageIter iter, sub, sub2, sub3;
3045         UnitStatusInfo info;
3046         ExecStatusInfo *p;
3047
3048         assert(path);
3049         assert(new_line);
3050
3051         zero(info);
3052
3053         r = bus_method_call_with_reply(
3054                         bus,
3055                         "org.freedesktop.systemd1",
3056                         path,
3057                         "org.freedesktop.DBus.Properties",
3058                         "GetAll",
3059                         &reply,
3060                         NULL,
3061                         DBUS_TYPE_STRING, &interface,
3062                         DBUS_TYPE_INVALID);
3063         if (r < 0)
3064                 return r;
3065
3066         if (!dbus_message_iter_init(reply, &iter) ||
3067             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3068             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3069                 log_error("Failed to parse reply.");
3070                 return -EIO;
3071         }
3072
3073         dbus_message_iter_recurse(&iter, &sub);
3074
3075         if (*new_line)
3076                 printf("\n");
3077
3078         *new_line = true;
3079
3080         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3081                 const char *name;
3082
3083                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
3084                 dbus_message_iter_recurse(&sub, &sub2);
3085
3086                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
3087                     dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
3088                         log_error("Failed to parse reply.");
3089                         return -EIO;
3090                 }
3091
3092                 dbus_message_iter_recurse(&sub2, &sub3);
3093
3094                 if (show_properties)
3095                         r = print_property(name, &sub3);
3096                 else
3097                         r = status_property(name, &sub3, &info);
3098                 if (r < 0) {
3099                         log_error("Failed to parse reply.");
3100                         return -EIO;
3101                 }
3102
3103                 dbus_message_iter_next(&sub);
3104         }
3105
3106         r = 0;
3107
3108         if (!show_properties) {
3109                 if (streq(verb, "help"))
3110                         show_unit_help(&info);
3111                 else
3112                         print_status_info(&info);
3113         }
3114
3115         strv_free(info.documentation);
3116
3117         if (!streq_ptr(info.active_state, "active") &&
3118             !streq_ptr(info.active_state, "reloading") &&
3119             streq(verb, "status"))
3120                 /* According to LSB: "program not running" */
3121                 r = 3;
3122
3123         while ((p = info.exec)) {
3124                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3125                 exec_status_info_free(p);
3126         }
3127
3128         return r;
3129 }
3130
3131 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3132         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3133         const char *path = NULL;
3134         DBusError _cleanup_dbus_error_free_ error;
3135         int r;
3136
3137         dbus_error_init(&error);
3138
3139         r = bus_method_call_with_reply(
3140                         bus,
3141                         "org.freedesktop.systemd1",
3142                         "/org/freedesktop/systemd1",
3143                         "org.freedesktop.systemd1.Manager",
3144                         "GetUnitByPID",
3145                         &reply,
3146                         NULL,
3147                         DBUS_TYPE_UINT32, &pid,
3148                         DBUS_TYPE_INVALID);
3149         if (r < 0)
3150                 return r;
3151
3152         if (!dbus_message_get_args(reply, &error,
3153                                    DBUS_TYPE_OBJECT_PATH, &path,
3154                                    DBUS_TYPE_INVALID)) {
3155                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3156                 return -EIO;
3157         }
3158
3159         r = show_one(verb, bus, path, false, new_line);
3160         return r;
3161 }
3162
3163 static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) {
3164         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3165         _cleanup_free_ struct unit_info *unit_infos = NULL;
3166         unsigned c = 0;
3167         const struct unit_info *u;
3168         int r;
3169
3170         r = get_unit_list(bus, &reply, &unit_infos, &c);
3171         if (r < 0)
3172                 return r;
3173
3174         for (u = unit_infos; u < unit_infos + c; u++) {
3175                 char _cleanup_free_ *p = NULL;
3176
3177                 if (!output_show_unit(u))
3178                         continue;
3179
3180                 p = unit_dbus_path_from_name(u->id);
3181                 if (!p)
3182                         return log_oom();
3183
3184                 printf("%s -> '%s'\n", u->id, p);
3185
3186                 r = show_one(verb, bus, p, show_properties, new_line);
3187                 if (r != 0)
3188                         return r;
3189         }
3190
3191         return 0;
3192 }
3193
3194 static int show(DBusConnection *bus, char **args) {
3195         int r, ret = 0;
3196         bool show_properties, show_status, new_line = false;
3197         char **name;
3198
3199         assert(bus);
3200         assert(args);
3201
3202         show_properties = streq(args[0], "show");
3203         show_status = streq(args[0], "status");
3204
3205         if (show_properties)
3206                 pager_open_if_enabled();
3207
3208         /* If no argument is specified inspect the manager itself */
3209
3210         if (show_properties && strv_length(args) <= 1)
3211                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3212
3213         if (show_status && strv_length(args) <= 1)
3214                 return show_all(args[0], bus, false, &new_line);
3215
3216         STRV_FOREACH(name, args+1) {
3217                 uint32_t id;
3218
3219                 if (safe_atou32(*name, &id) < 0) {
3220                         _cleanup_free_ char *p = NULL, *n = NULL;
3221                         /* Interpret as unit name */
3222
3223                         n = unit_name_mangle(*name);
3224                         if (!n)
3225                                 return log_oom();
3226
3227                         p = unit_dbus_path_from_name(n);
3228                         if (!p)
3229                                 return log_oom();
3230
3231                         r = show_one(args[0], bus, p, show_properties, &new_line);
3232                         if (r != 0)
3233                                 ret = r;
3234
3235                 } else if (show_properties) {
3236                         _cleanup_free_ char *p = NULL;
3237
3238                         /* Interpret as job id */
3239                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3240                                 return log_oom();
3241
3242                         r = show_one(args[0], bus, p, show_properties, &new_line);
3243                         if (r != 0)
3244                                 ret = r;
3245
3246                 } else {
3247                         /* Interpret as PID */
3248                         r = show_one_by_pid(args[0], bus, id, &new_line);
3249                         if (r != 0)
3250                                 ret = r;
3251                 }
3252         }
3253
3254         return ret;
3255 }
3256
3257 static int dump(DBusConnection *bus, char **args) {
3258         _cleanup_free_ DBusMessage *reply = NULL;
3259         DBusError error;
3260         int r;
3261         const char *text;
3262
3263         dbus_error_init(&error);
3264
3265         pager_open_if_enabled();
3266
3267         r = bus_method_call_with_reply(
3268                         bus,
3269                         "org.freedesktop.systemd1",
3270                         "/org/freedesktop/systemd1",
3271                         "org.freedesktop.systemd1.Manager",
3272                         "Dump",
3273                         &reply,
3274                         NULL,
3275                         DBUS_TYPE_INVALID);
3276         if (r < 0)
3277                 return r;
3278
3279         if (!dbus_message_get_args(reply, &error,
3280                                    DBUS_TYPE_STRING, &text,
3281                                    DBUS_TYPE_INVALID)) {
3282                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3283                 dbus_error_free(&error);
3284                 return  -EIO;
3285         }
3286
3287         fputs(text, stdout);
3288         return 0;
3289 }
3290
3291 static int snapshot(DBusConnection *bus, char **args) {
3292         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3293         DBusError error;
3294         int r;
3295         dbus_bool_t cleanup = FALSE;
3296         DBusMessageIter iter, sub;
3297         const char
3298                 *path, *id,
3299                 *interface = "org.freedesktop.systemd1.Unit",
3300                 *property = "Id";
3301         _cleanup_free_ char *n = NULL;
3302
3303         dbus_error_init(&error);
3304
3305         if (strv_length(args) > 1)
3306                 n = snapshot_name_mangle(args[1]);
3307         else
3308                 n = strdup("");
3309         if (!n)
3310                 return log_oom();
3311
3312         r = bus_method_call_with_reply (
3313                         bus,
3314                         "org.freedesktop.systemd1",
3315                         "/org/freedesktop/systemd1",
3316                         "org.freedesktop.systemd1.Manager",
3317                         "CreateSnapshot",
3318                         &reply,
3319                         NULL,
3320                         DBUS_TYPE_STRING, &n,
3321                         DBUS_TYPE_BOOLEAN, &cleanup,
3322                         DBUS_TYPE_INVALID);
3323         if (r < 0)
3324                 return r;
3325
3326         if (!dbus_message_get_args(reply, &error,
3327                                    DBUS_TYPE_OBJECT_PATH, &path,
3328                                    DBUS_TYPE_INVALID)) {
3329                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3330                 dbus_error_free(&error);
3331                 return -EIO;
3332         }
3333
3334         dbus_message_unref(reply);
3335         reply = NULL;
3336
3337         r = bus_method_call_with_reply (
3338                         bus,
3339                         "org.freedesktop.systemd1",
3340                         path,
3341                         "org.freedesktop.DBus.Properties",
3342                         "Get",
3343                         &reply,
3344                         NULL,
3345                         DBUS_TYPE_STRING, &interface,
3346                         DBUS_TYPE_STRING, &property,
3347                         DBUS_TYPE_INVALID);
3348         if (r < 0)
3349                 return r;
3350
3351         if (!dbus_message_iter_init(reply, &iter) ||
3352             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3353                 log_error("Failed to parse reply.");
3354                 return -EIO;
3355         }
3356
3357         dbus_message_iter_recurse(&iter, &sub);
3358
3359         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3360                 log_error("Failed to parse reply.");
3361                 return -EIO;
3362         }
3363
3364         dbus_message_iter_get_basic(&sub, &id);
3365
3366         if (!arg_quiet)
3367                 puts(id);
3368
3369         return 0;
3370 }
3371
3372 static int delete_snapshot(DBusConnection *bus, char **args) {
3373         char **name;
3374
3375         assert(args);
3376
3377         STRV_FOREACH(name, args+1) {
3378                 _cleanup_free_ char *n = NULL;
3379                 int r;
3380
3381                 n = snapshot_name_mangle(*name);
3382                 if (!n)
3383                         return log_oom();
3384
3385                 r = bus_method_call_with_reply(
3386                                 bus,
3387                                 "org.freedesktop.systemd1",
3388                                 "/org/freedesktop/systemd1",
3389                                 "org.freedesktop.systemd1.Manager",
3390                                 "RemoveSnapshot",
3391                                 NULL,
3392                                 NULL,
3393                                 DBUS_TYPE_STRING, &n,
3394                                 DBUS_TYPE_INVALID);
3395                 if (r < 0)
3396                         return r;
3397         }
3398
3399         return 0;
3400 }
3401
3402 static int daemon_reload(DBusConnection *bus, char **args) {
3403         int r;
3404         const char *method;
3405         DBusError error;
3406
3407         if (arg_action == ACTION_RELOAD)
3408                 method = "Reload";
3409         else if (arg_action == ACTION_REEXEC)
3410                 method = "Reexecute";
3411         else {
3412                 assert(arg_action == ACTION_SYSTEMCTL);
3413
3414                 method =
3415                         streq(args[0], "clear-jobs")    ||
3416                         streq(args[0], "cancel")        ? "ClearJobs" :
3417                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3418                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3419                         streq(args[0], "halt")          ? "Halt" :
3420                         streq(args[0], "poweroff")      ? "PowerOff" :
3421                         streq(args[0], "reboot")        ? "Reboot" :
3422                         streq(args[0], "kexec")         ? "KExec" :
3423                         streq(args[0], "exit")          ? "Exit" :
3424                                     /* "daemon-reload" */ "Reload";
3425         }
3426
3427         r = bus_method_call_with_reply(
3428                         bus,
3429                         "org.freedesktop.systemd1",
3430                         "/org/freedesktop/systemd1",
3431                         "org.freedesktop.systemd1.Manager",
3432                         method,
3433                         NULL,
3434                         &error,
3435                         DBUS_TYPE_INVALID);
3436
3437         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3438                 /* There's always a fallback possible for
3439                  * legacy actions. */
3440                 r = -EADDRNOTAVAIL;
3441         else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3442                 /* On reexecution, we expect a disconnect, not
3443                  * a reply */
3444                 r = 0;
3445         else if (r < 0)
3446                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3447
3448         dbus_error_free(&error);
3449         return r;
3450 }
3451
3452 static int reset_failed(DBusConnection *bus, char **args) {
3453         int r = 0;
3454         char **name;
3455
3456         if (strv_length(args) <= 1)
3457                 return daemon_reload(bus, args);
3458
3459         STRV_FOREACH(name, args+1) {
3460                 _cleanup_free_ char *n;
3461
3462                 n = unit_name_mangle(*name);
3463                 if (!n)
3464                         return log_oom();
3465
3466                 r = bus_method_call_with_reply(
3467                                 bus,
3468                                 "org.freedesktop.systemd1",
3469                                 "/org/freedesktop/systemd1",
3470                                 "org.freedesktop.systemd1.Manager",
3471                                 "ResetFailedUnit",
3472                                 NULL,
3473                                 NULL,
3474                                 DBUS_TYPE_STRING, &n,
3475                                 DBUS_TYPE_INVALID);
3476                 if (r < 0)
3477                         return r;
3478         }
3479
3480         return 0;
3481 }
3482
3483 static int show_enviroment(DBusConnection *bus, char **args) {
3484         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3485         DBusMessageIter iter, sub, sub2;
3486         int r;
3487         const char
3488                 *interface = "org.freedesktop.systemd1.Manager",
3489                 *property = "Environment";
3490
3491         pager_open_if_enabled();
3492
3493         r = bus_method_call_with_reply(
3494                         bus,
3495                         "org.freedesktop.systemd1",
3496                         "/org/freedesktop/systemd1",
3497                         "org.freedesktop.DBus.Properties",
3498                         "Get",
3499                         &reply,
3500                         NULL,
3501                         DBUS_TYPE_STRING, &interface,
3502                         DBUS_TYPE_STRING, &property,
3503                         DBUS_TYPE_INVALID);
3504         if (r < 0)
3505                 return r;
3506
3507         if (!dbus_message_iter_init(reply, &iter) ||
3508             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3509                 log_error("Failed to parse reply.");
3510                 return -EIO;
3511         }
3512
3513         dbus_message_iter_recurse(&iter, &sub);
3514
3515         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3516             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3517                 log_error("Failed to parse reply.");
3518                 return -EIO;
3519         }
3520
3521         dbus_message_iter_recurse(&sub, &sub2);
3522
3523         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3524                 const char *text;
3525
3526                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3527                         log_error("Failed to parse reply.");
3528                         return -EIO;
3529                 }
3530
3531                 dbus_message_iter_get_basic(&sub2, &text);
3532                 puts(text);
3533
3534                 dbus_message_iter_next(&sub2);
3535         }
3536
3537         return 0;
3538 }
3539
3540 static int switch_root(DBusConnection *bus, char **args) {
3541         unsigned l;
3542         const char *root;
3543         _cleanup_free_ char *init = NULL;
3544
3545         l = strv_length(args);
3546         if (l < 2 || l > 3) {
3547                 log_error("Wrong number of arguments.");
3548                 return -EINVAL;
3549         }
3550
3551         root = args[1];
3552
3553         if (l >= 3)
3554                 init = strdup(args[2]);
3555         else {
3556                 parse_env_file("/proc/cmdline", WHITESPACE,
3557                                "init", &init,
3558                                NULL);
3559
3560                 if (!init)
3561                         init = strdup("");
3562         }
3563         if (!init)
3564                 return log_oom();
3565
3566         log_debug("switching root - root: %s; init: %s", root, init);
3567
3568         return bus_method_call_with_reply(
3569                         bus,
3570                         "org.freedesktop.systemd1",
3571                         "/org/freedesktop/systemd1",
3572                         "org.freedesktop.systemd1.Manager",
3573                         "SwitchRoot",
3574                         NULL,
3575                         NULL,
3576                         DBUS_TYPE_STRING, &root,
3577                         DBUS_TYPE_STRING, &init,
3578                         DBUS_TYPE_INVALID);
3579 }
3580
3581 static int set_environment(DBusConnection *bus, char **args) {
3582         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
3583         DBusError error;
3584         const char *method;
3585         DBusMessageIter iter;
3586         int r;
3587
3588         assert(bus);
3589         assert(args);
3590
3591         dbus_error_init(&error);
3592
3593         method = streq(args[0], "set-environment")
3594                 ? "SetEnvironment"
3595                 : "UnsetEnvironment";
3596
3597         m = dbus_message_new_method_call(
3598                         "org.freedesktop.systemd1",
3599                         "/org/freedesktop/systemd1",
3600                         "org.freedesktop.systemd1.Manager",
3601                         method);
3602         if (!m)
3603                 return log_oom();
3604
3605         dbus_message_iter_init_append(m, &iter);
3606
3607         r = bus_append_strv_iter(&iter, args + 1);
3608         if (r < 0)
3609                 return log_oom();
3610
3611         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3612         if (!reply) {
3613                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3614                 dbus_error_free(&error);
3615                 return -EIO;
3616         }
3617
3618         return 0;
3619 }
3620
3621 static int enable_sysv_units(char **args) {
3622         int r = 0;
3623
3624 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
3625         const char *verb = args[0];
3626         unsigned f = 1, t = 1;
3627         LookupPaths paths;
3628
3629         if (arg_scope != UNIT_FILE_SYSTEM)
3630                 return 0;
3631
3632         if (!streq(verb, "enable") &&
3633             !streq(verb, "disable") &&
3634             !streq(verb, "is-enabled"))
3635                 return 0;
3636
3637         /* Processes all SysV units, and reshuffles the array so that
3638          * afterwards only the native units remain */
3639
3640         zero(paths);
3641         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
3642         if (r < 0)
3643                 return r;
3644
3645         r = 0;
3646         for (f = 1; args[f]; f++) {
3647                 const char *name;
3648                 char *p;
3649                 bool found_native = false, found_sysv;
3650                 unsigned c = 1;
3651                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3652                 char **k, *l, *q = NULL;
3653                 int j;
3654                 pid_t pid;
3655                 siginfo_t status;
3656
3657                 name = args[f];
3658
3659                 if (!endswith(name, ".service"))
3660                         continue;
3661
3662                 if (path_is_absolute(name))
3663                         continue;
3664
3665                 STRV_FOREACH(k, paths.unit_path) {
3666                         p = NULL;
3667
3668                         if (!isempty(arg_root))
3669                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3670                         else
3671                                 asprintf(&p, "%s/%s", *k, name);
3672
3673                         if (!p) {
3674                                 r = log_oom();
3675                                 goto finish;
3676                         }
3677
3678                         found_native = access(p, F_OK) >= 0;
3679                         free(p);
3680
3681                         if (found_native)
3682                                 break;
3683                 }
3684
3685                 if (found_native)
3686                         continue;
3687
3688                 p = NULL;
3689                 if (!isempty(arg_root))
3690                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3691                 else
3692                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3693                 if (!p) {
3694                         r = log_oom();
3695                         goto finish;
3696                 }
3697
3698                 p[strlen(p) - sizeof(".service") + 1] = 0;
3699                 found_sysv = access(p, F_OK) >= 0;
3700
3701                 if (!found_sysv) {
3702                         free(p);
3703                         continue;
3704                 }
3705
3706                 /* Mark this entry, so that we don't try enabling it as native unit */
3707                 args[f] = (char*) "";
3708
3709                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3710
3711                 if (!isempty(arg_root))
3712                         argv[c++] = q = strappend("--root=", arg_root);
3713
3714                 argv[c++] = path_get_file_name(p);
3715                 argv[c++] =
3716                         streq(verb, "enable") ? "on" :
3717                         streq(verb, "disable") ? "off" : "--level=5";
3718                 argv[c] = NULL;
3719
3720                 l = strv_join((char**)argv, " ");
3721                 if (!l) {
3722                         free(q);
3723                         free(p);
3724                         r = log_oom();
3725                         goto finish;
3726                 }
3727
3728                 log_info("Executing %s", l);
3729                 free(l);
3730
3731                 pid = fork();
3732                 if (pid < 0) {
3733                         log_error("Failed to fork: %m");
3734                         free(p);
3735                         free(q);
3736                         r = -errno;
3737                         goto finish;
3738                 } else if (pid == 0) {
3739                         /* Child */
3740
3741                         execv(argv[0], (char**) argv);
3742                         _exit(EXIT_FAILURE);
3743                 }
3744
3745                 free(p);
3746                 free(q);
3747
3748                 j = wait_for_terminate(pid, &status);
3749                 if (j < 0) {
3750                         log_error("Failed to wait for child: %s", strerror(-r));
3751                         r = j;
3752                         goto finish;
3753                 }
3754
3755                 if (status.si_code == CLD_EXITED) {
3756                         if (streq(verb, "is-enabled")) {
3757                                 if (status.si_status == 0) {
3758                                         if (!arg_quiet)
3759                                                 puts("enabled");
3760                                         r = 1;
3761                                 } else {
3762                                         if (!arg_quiet)
3763                                                 puts("disabled");
3764                                 }
3765
3766                         } else if (status.si_status != 0) {
3767                                 r = -EINVAL;
3768                                 goto finish;
3769                         }
3770                 } else {
3771                         r = -EPROTO;
3772                         goto finish;
3773                 }
3774         }
3775
3776 finish:
3777         lookup_paths_free(&paths);
3778
3779         /* Drop all SysV units */
3780         for (f = 1, t = 1; args[f]; f++) {
3781
3782                 if (isempty(args[f]))
3783                         continue;
3784
3785                 args[t++] = args[f];
3786         }
3787
3788         args[t] = NULL;
3789
3790 #endif
3791         return r;
3792 }
3793
3794 static int mangle_names(char **original_names, char ***mangled_names) {
3795         char **i, **l, **name;
3796
3797         l = new(char*, strv_length(original_names) + 1);
3798         if (!l)
3799                 return log_oom();
3800
3801         i = l;
3802         STRV_FOREACH(name, original_names) {
3803
3804                 /* When enabling units qualified path names are OK,
3805                  * too, hence allow them explicitly. */
3806
3807                 if (is_path(*name))
3808                         *i = strdup(*name);
3809                 else
3810                         *i = unit_name_mangle(*name);
3811
3812                 if (!*i) {
3813                         strv_free(l);
3814                         return log_oom();
3815                 }
3816
3817                 i++;
3818         }
3819
3820         *i = NULL;
3821         *mangled_names = l;
3822
3823         return 0;
3824 }
3825
3826 static int enable_unit(DBusConnection *bus, char **args) {
3827         const char *verb = args[0];
3828         UnitFileChange *changes = NULL;
3829         unsigned n_changes = 0, i;
3830         int carries_install_info = -1;
3831         DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
3832         int r;
3833         DBusError _cleanup_dbus_error_free_ error;
3834         char _cleanup_strv_free_ **mangled_names = NULL;
3835
3836         dbus_error_init(&error);
3837
3838         r = enable_sysv_units(args);
3839         if (r < 0)
3840                 return r;
3841
3842         if (!args[1])
3843                 return 0;
3844
3845         if (!bus || avoid_bus()) {
3846                 if (streq(verb, "enable")) {
3847                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3848                         carries_install_info = r;
3849                 } else if (streq(verb, "disable"))
3850                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3851                 else if (streq(verb, "reenable")) {
3852                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3853                         carries_install_info = r;
3854                 } else if (streq(verb, "link"))
3855                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3856                 else if (streq(verb, "preset")) {
3857                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3858                         carries_install_info = r;
3859                 } else if (streq(verb, "mask"))
3860                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3861                 else if (streq(verb, "unmask"))
3862                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3863                 else
3864                         assert_not_reached("Unknown verb");
3865
3866                 if (r < 0) {
3867                         log_error("Operation failed: %s", strerror(-r));
3868                         goto finish;
3869                 }
3870
3871                 if (!arg_quiet) {
3872                         for (i = 0; i < n_changes; i++) {
3873                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3874                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3875                                 else
3876                                         log_info("rm '%s'", changes[i].path);
3877                         }
3878                 }
3879
3880                 r = 0;
3881         } else {
3882                 const char *method;
3883                 bool send_force = true, expect_carries_install_info = false;
3884                 dbus_bool_t a, b;
3885                 DBusMessageIter iter, sub, sub2;
3886
3887                 if (streq(verb, "enable")) {
3888                         method = "EnableUnitFiles";
3889                         expect_carries_install_info = true;
3890                 } else if (streq(verb, "disable")) {
3891                         method = "DisableUnitFiles";
3892                         send_force = false;
3893                 } else if (streq(verb, "reenable")) {
3894                         method = "ReenableUnitFiles";
3895                         expect_carries_install_info = true;
3896                 } else if (streq(verb, "link"))
3897                         method = "LinkUnitFiles";
3898                 else if (streq(verb, "preset")) {
3899                         method = "PresetUnitFiles";
3900                         expect_carries_install_info = true;
3901                 } else if (streq(verb, "mask"))
3902                         method = "MaskUnitFiles";
3903                 else if (streq(verb, "unmask")) {
3904                         method = "UnmaskUnitFiles";
3905                         send_force = false;
3906                 } else
3907                         assert_not_reached("Unknown verb");
3908
3909                 m = dbus_message_new_method_call(
3910                                 "org.freedesktop.systemd1",
3911                                 "/org/freedesktop/systemd1",
3912                                 "org.freedesktop.systemd1.Manager",
3913                                 method);
3914                 if (!m) {
3915                         r = log_oom();
3916                         goto finish;
3917                 }
3918
3919                 dbus_message_iter_init_append(m, &iter);
3920
3921                 r = mangle_names(args+1, &mangled_names);
3922                 if(r < 0)
3923                         goto finish;
3924
3925                 r = bus_append_strv_iter(&iter, mangled_names);
3926                 if (r < 0) {
3927                         log_error("Failed to append unit files.");
3928                         goto finish;
3929                 }
3930
3931                 a = arg_runtime;
3932                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3933                         log_error("Failed to append runtime boolean.");
3934                         r = -ENOMEM;
3935                         goto finish;
3936                 }
3937
3938                 if (send_force) {
3939                         b = arg_force;
3940
3941                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3942                                 log_error("Failed to append force boolean.");
3943                                 r = -ENOMEM;
3944                                 goto finish;
3945                         }
3946                 }
3947
3948                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3949                 if (!reply) {
3950                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3951                         r = -EIO;
3952                         goto finish;
3953                 }
3954
3955                 if (!dbus_message_iter_init(reply, &iter)) {
3956                         log_error("Failed to initialize iterator.");
3957                         goto finish;
3958                 }
3959
3960                 if (expect_carries_install_info) {
3961                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3962                         if (r < 0) {
3963                                 log_error("Failed to parse reply.");
3964                                 goto finish;
3965                         }
3966
3967                         carries_install_info = b;
3968                 }
3969
3970                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3971                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3972                         log_error("Failed to parse reply.");
3973                         r = -EIO;
3974                         goto finish;
3975                 }
3976
3977                 dbus_message_iter_recurse(&iter, &sub);
3978                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3979                         const char *type, *path, *source;
3980
3981                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3982                                 log_error("Failed to parse reply.");
3983                                 r = -EIO;
3984                                 goto finish;
3985                         }
3986
3987                         dbus_message_iter_recurse(&sub, &sub2);
3988
3989                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3990                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3991                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3992                                 log_error("Failed to parse reply.");
3993                                 r = -EIO;
3994                                 goto finish;
3995                         }
3996
3997                         if (!arg_quiet) {
3998                                 if (streq(type, "symlink"))
3999                                         log_info("ln -s '%s' '%s'", source, path);
4000                                 else
4001                                         log_info("rm '%s'", path);
4002                         }
4003
4004                         dbus_message_iter_next(&sub);
4005                 }
4006
4007                 /* Try to reload if enabeld */
4008                 if (!arg_no_reload)
4009                         r = daemon_reload(bus, args);
4010         }
4011
4012         if (carries_install_info == 0)
4013                 log_warning(
4014 "The unit files have no [Install] section. They are not meant to be enabled\n"
4015 "using systemctl.\n"
4016 "Possible reasons for having this kind of units are:\n"
4017 "1) A unit may be statically enabled by being symlinked from another unit's\n"
4018 "   .wants/ or .requires/ directory.\n"
4019 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4020 "   a requirement dependency on it.\n"
4021 "3) A unit may be started when needed via activation (socket, path, timer,\n"
4022 "   D-Bus, udev, scripted systemctl call, ...).\n");
4023
4024 finish:
4025         unit_file_changes_free(changes, n_changes);
4026
4027         return r;
4028 }
4029
4030 static int unit_is_enabled(DBusConnection *bus, char **args) {
4031         DBusError _cleanup_dbus_error_free_ error;
4032         int r;
4033         DBusMessage _cleanup_dbus_message_unref_ *reply = NULL;
4034         bool enabled;
4035         char **name;
4036
4037         dbus_error_init(&error);
4038
4039         r = enable_sysv_units(args);
4040         if (r < 0)
4041                 return r;
4042
4043         enabled = r > 0;
4044
4045         if (!bus || avoid_bus()) {
4046
4047                 STRV_FOREACH(name, args+1) {
4048                         UnitFileState state;
4049
4050                         state = unit_file_get_state(arg_scope, arg_root, *name);
4051                         if (state < 0)
4052                                 return state;
4053
4054                         if (state == UNIT_FILE_ENABLED ||
4055                             state == UNIT_FILE_ENABLED_RUNTIME ||
4056                             state == UNIT_FILE_STATIC)
4057                                 enabled = true;
4058
4059                         if (!arg_quiet)
4060                                 puts(unit_file_state_to_string(state));
4061                 }
4062
4063         } else {
4064                 STRV_FOREACH(name, args+1) {
4065                         const char *s;
4066
4067                         r = bus_method_call_with_reply (
4068                                         bus,
4069                                         "org.freedesktop.systemd1",
4070                                         "/org/freedesktop/systemd1",
4071                                         "org.freedesktop.systemd1.Manager",
4072                                         "GetUnitFileState",
4073                                         &reply,
4074                                         NULL,
4075                                         DBUS_TYPE_STRING, name,
4076                                         DBUS_TYPE_INVALID);
4077                         if (r)
4078                                 return r;
4079
4080                         if (!dbus_message_get_args(reply, &error,
4081                                                    DBUS_TYPE_STRING, &s,
4082                                                    DBUS_TYPE_INVALID)) {
4083                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4084                                 return -EIO;
4085                         }
4086
4087                         dbus_message_unref(reply);
4088                         reply = NULL;
4089
4090                         if (streq(s, "enabled") ||
4091                             streq(s, "enabled-runtime") ||
4092                             streq(s, "static"))
4093                                 enabled = true;
4094
4095                         if (!arg_quiet)
4096                                 puts(s);
4097                 }
4098         }
4099
4100         return enabled ? 0 : 1;
4101 }
4102
4103 static int systemctl_help(void) {
4104
4105         pager_open_if_enabled();
4106
4107         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4108                "Query or send control commands to the systemd manager.\n\n"
4109                "  -h --help           Show this help\n"
4110                "     --version        Show package version\n"
4111                "  -t --type=TYPE      List only units of a particular type\n"
4112                "  -p --property=NAME  Show only properties by this name\n"
4113                "  -a --all            Show all units/properties, including dead/empty ones\n"
4114                "     --failed         Show only failed units\n"
4115                "     --full           Don't ellipsize unit names on output\n"
4116                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4117                "                      pending\n"
4118                "     --ignore-dependencies\n"
4119                "                      When queueing a new job, ignore all its dependencies\n"
4120                "  -i --ignore-inhibitors\n"
4121                "                      When shutting down or sleeping, ignore inhibitors\n"
4122                "     --kill-who=WHO   Who to send signal to\n"
4123                "  -s --signal=SIGNAL  Which signal to send\n"
4124                "  -H --host=[USER@]HOST\n"
4125                "                      Show information for remote host\n"
4126                "  -P --privileged     Acquire privileges before execution\n"
4127                "  -q --quiet          Suppress output\n"
4128                "     --no-block       Do not wait until operation finished\n"
4129                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4130                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4131                "                      configuration\n"
4132                "     --no-legend      Do not print a legend (column headers and hints)\n"
4133                "     --no-pager       Do not pipe output into a pager\n"
4134                "     --no-ask-password\n"
4135                "                      Do not ask for system passwords\n"
4136                "     --system         Connect to system manager\n"
4137                "     --user           Connect to user service manager\n"
4138                "     --global         Enable/disable unit files globally\n"
4139                "  -f --force          When enabling unit files, override existing symlinks\n"
4140                "                      When shutting down, execute action immediately\n"
4141                "     --root=PATH      Enable unit files in the specified root directory\n"
4142                "     --runtime        Enable unit files only temporarily until next reboot\n"
4143                "  -n --lines=INTEGER  Journal entries to show\n"
4144                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4145                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
4146                "Unit Commands:\n"
4147                "  list-units                      List loaded units\n"
4148                "  start [NAME...]                 Start (activate) one or more units\n"
4149                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4150                "  reload [NAME...]                Reload one or more units\n"
4151                "  restart [NAME...]               Start or restart one or more units\n"
4152                "  try-restart [NAME...]           Restart one or more units if active\n"
4153                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
4154                "                                  otherwise start or restart\n"
4155                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
4156                "                                  otherwise restart if active\n"
4157                "  isolate [NAME]                  Start one unit and stop all others\n"
4158                "  kill [NAME...]                  Send signal to processes of a unit\n"
4159                "  is-active [NAME...]             Check whether units are active\n"
4160                "  is-failed [NAME...]             Check whether units are failed\n"
4161                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4162                "  show [NAME...|JOB...]           Show properties of one or more\n"
4163                "                                  units/jobs or the manager\n"
4164                "  help [NAME...|PID...]           Show manual for one or more units\n"
4165                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4166                "                                  units\n"
4167                "  get-cgroup-attr [NAME] [ATTR] ...\n"
4168                "                                  Get control group attrubute\n"
4169                "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
4170                "                                  Set control group attribute\n"
4171                "  unset-cgroup-attr [NAME] [ATTR...]\n"
4172                "                                  Unset control group attribute\n"
4173                "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
4174                "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
4175                "  load [NAME...]                  Load one or more units\n"
4176                "  list-dependencies [NAME]        Recursively show units which are required\n"
4177                "                                  or wanted by this unit\n\n"
4178                "Unit File Commands:\n"
4179                "  list-unit-files                 List installed unit files\n"
4180                "  enable [NAME...]                Enable one or more unit files\n"
4181                "  disable [NAME...]               Disable one or more unit files\n"
4182                "  reenable [NAME...]              Reenable one or more unit files\n"
4183                "  preset [NAME...]                Enable/disable one or more unit files\n"
4184                "                                  based on preset configuration\n"
4185                "  mask [NAME...]                  Mask one or more units\n"
4186                "  unmask [NAME...]                Unmask one or more units\n"
4187                "  link [PATH...]                  Link one or more units files into\n"
4188                "                                  the search path\n"
4189                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4190                "Job Commands:\n"
4191                "  list-jobs                       List jobs\n"
4192                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4193                "Status Commands:\n"
4194                "  dump                            Dump server status\n"
4195                "Snapshot Commands:\n"
4196                "  snapshot [NAME]                 Create a snapshot\n"
4197                "  delete [NAME...]                Remove one or more snapshots\n\n"
4198                "Environment Commands:\n"
4199                "  show-environment                Dump environment\n"
4200                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4201                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4202                "Manager Lifecycle Commands:\n"
4203                "  daemon-reload                   Reload systemd manager configuration\n"
4204                "  daemon-reexec                   Reexecute systemd manager\n\n"
4205                "System Commands:\n"
4206                "  default                         Enter system default mode\n"
4207                "  rescue                          Enter system rescue mode\n"
4208                "  emergency                       Enter system emergency mode\n"
4209                "  halt                            Shut down and halt the system\n"
4210                "  poweroff                        Shut down and power-off the system\n"
4211                "  reboot                          Shut down and reboot the system\n"
4212                "  kexec                           Shut down and reboot the system with kexec\n"
4213                "  exit                            Request user instance exit\n"
4214                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4215                "  suspend                         Suspend the system\n"
4216                "  hibernate                       Hibernate the system\n"
4217                "  hybrid-sleep                    Hibernate and suspend the system\n",
4218                program_invocation_short_name);
4219
4220         return 0;
4221 }
4222
4223 static int halt_help(void) {
4224
4225         printf("%s [OPTIONS...]\n\n"
4226                "%s the system.\n\n"
4227                "     --help      Show this help\n"
4228                "     --halt      Halt the machine\n"
4229                "  -p --poweroff  Switch off the machine\n"
4230                "     --reboot    Reboot the machine\n"
4231                "  -f --force     Force immediate halt/power-off/reboot\n"
4232                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4233                "  -d --no-wtmp   Don't write wtmp record\n"
4234                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4235                program_invocation_short_name,
4236                arg_action == ACTION_REBOOT   ? "Reboot" :
4237                arg_action == ACTION_POWEROFF ? "Power off" :
4238                                                "Halt");
4239
4240         return 0;
4241 }
4242
4243 static int shutdown_help(void) {
4244
4245         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4246                "Shut down the system.\n\n"
4247                "     --help      Show this help\n"
4248                "  -H --halt      Halt the machine\n"
4249                "  -P --poweroff  Power-off the machine\n"
4250                "  -r --reboot    Reboot the machine\n"
4251                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4252                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4253                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4254                "  -c             Cancel a pending shutdown\n",
4255                program_invocation_short_name);
4256
4257         return 0;
4258 }
4259
4260 static int telinit_help(void) {
4261
4262         printf("%s [OPTIONS...] {COMMAND}\n\n"
4263                "Send control commands to the init daemon.\n\n"
4264                "     --help      Show this help\n"
4265                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4266                "Commands:\n"
4267                "  0              Power-off the machine\n"
4268                "  6              Reboot the machine\n"
4269                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4270                "  1, s, S        Enter rescue mode\n"
4271                "  q, Q           Reload init daemon configuration\n"
4272                "  u, U           Reexecute init daemon\n",
4273                program_invocation_short_name);
4274
4275         return 0;
4276 }
4277
4278 static int runlevel_help(void) {
4279
4280         printf("%s [OPTIONS...]\n\n"
4281                "Prints the previous and current runlevel of the init system.\n\n"
4282                "     --help      Show this help\n",
4283                program_invocation_short_name);
4284
4285         return 0;
4286 }
4287
4288 static int help_types(void) {
4289         int i;
4290
4291         puts("Available unit types:");
4292         for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++)
4293                 if (unit_type_table[i])
4294                         puts(unit_type_table[i]);
4295
4296         puts("\nAvailable unit load states: ");
4297         for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++)
4298                 if (unit_type_table[i])
4299                         puts(unit_load_state_table[i]);
4300
4301         return 0;
4302 }
4303
4304 static int systemctl_parse_argv(int argc, char *argv[]) {
4305
4306         enum {
4307                 ARG_FAIL = 0x100,
4308                 ARG_IGNORE_DEPENDENCIES,
4309                 ARG_VERSION,
4310                 ARG_USER,
4311                 ARG_SYSTEM,
4312                 ARG_GLOBAL,
4313                 ARG_NO_BLOCK,
4314                 ARG_NO_LEGEND,
4315                 ARG_NO_PAGER,
4316                 ARG_NO_WALL,
4317                 ARG_ROOT,
4318                 ARG_FULL,
4319                 ARG_NO_RELOAD,
4320                 ARG_KILL_WHO,
4321                 ARG_NO_ASK_PASSWORD,
4322                 ARG_FAILED,
4323                 ARG_RUNTIME,
4324                 ARG_FORCE
4325         };
4326
4327         static const struct option options[] = {
4328                 { "help",      no_argument,       NULL, 'h'           },
4329                 { "version",   no_argument,       NULL, ARG_VERSION   },
4330                 { "type",      required_argument, NULL, 't'           },
4331                 { "property",  required_argument, NULL, 'p'           },
4332                 { "all",       no_argument,       NULL, 'a'           },
4333                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4334                 { "full",      no_argument,       NULL, ARG_FULL      },
4335                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4336                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4337                 { "ignore-inhibitors", no_argument, NULL, 'i'         },
4338                 { "user",      no_argument,       NULL, ARG_USER      },
4339                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4340                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4341                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4342                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4343                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4344                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4345                 { "quiet",     no_argument,       NULL, 'q'           },
4346                 { "root",      required_argument, NULL, ARG_ROOT      },
4347                 { "force",     no_argument,       NULL, ARG_FORCE     },
4348                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4349                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4350                 { "signal",    required_argument, NULL, 's'           },
4351                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4352                 { "host",      required_argument, NULL, 'H'           },
4353                 { "privileged",no_argument,       NULL, 'P'           },
4354                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4355                 { "lines",     required_argument, NULL, 'n'           },
4356                 { "output",    required_argument, NULL, 'o'           },
4357                 { NULL,        0,                 NULL, 0             }
4358         };
4359
4360         int c;
4361
4362         assert(argc >= 0);
4363         assert(argv);
4364
4365         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) {
4366
4367                 switch (c) {
4368
4369                 case 'h':
4370                         systemctl_help();
4371                         return 0;
4372
4373                 case ARG_VERSION:
4374                         puts(PACKAGE_STRING);
4375                         puts(SYSTEMD_FEATURES);
4376                         return 0;
4377
4378                 case 't':
4379                         if (streq(optarg, "help")) {
4380                                 help_types();
4381                                 return 0;
4382                         }
4383
4384                         if (unit_type_from_string(optarg) >= 0) {
4385                                 arg_type = optarg;
4386                                 break;
4387                         }
4388                         if (unit_load_state_from_string(optarg) >= 0) {
4389                                 arg_load_state = optarg;
4390                                 break;
4391                         }
4392                         log_error("Unkown unit type or load state '%s'.",
4393                                   optarg);
4394                         log_info("Use -t help to see a list of allowed values.");
4395                         return -EINVAL;
4396                 case 'p': {
4397                         char *word, *state;
4398                         size_t size;
4399                         /* Make sure that if the empty property list
4400                            was specified, we won't show any properties. */
4401                         const char *source = isempty(optarg) ? " " : optarg;
4402
4403                         FOREACH_WORD_SEPARATOR(word, size, source, ",", state) {
4404                                 char _cleanup_free_ *prop;
4405                                 char **tmp;
4406
4407                                 prop = strndup(word, size);
4408                                 if (!prop)
4409                                         return -ENOMEM;
4410
4411                                 tmp = strv_append(arg_property, prop);
4412                                 if (!tmp)
4413                                         return -ENOMEM;
4414
4415                                 strv_free(arg_property);
4416                                 arg_property = tmp;
4417                         }
4418
4419                         /* If the user asked for a particular
4420                          * property, show it to him, even if it is
4421                          * empty. */
4422                         arg_all = true;
4423
4424                         break;
4425                 }
4426
4427                 case 'a':
4428                         arg_all = true;
4429                         break;
4430
4431                 case ARG_FAIL:
4432                         arg_job_mode = "fail";
4433                         break;
4434
4435                 case ARG_IGNORE_DEPENDENCIES:
4436                         arg_job_mode = "ignore-dependencies";
4437                         break;
4438
4439                 case ARG_USER:
4440                         arg_scope = UNIT_FILE_USER;
4441                         break;
4442
4443                 case ARG_SYSTEM:
4444                         arg_scope = UNIT_FILE_SYSTEM;
4445                         break;
4446
4447                 case ARG_GLOBAL:
4448                         arg_scope = UNIT_FILE_GLOBAL;
4449                         break;
4450
4451                 case ARG_NO_BLOCK:
4452                         arg_no_block = true;
4453                         break;
4454
4455                 case ARG_NO_LEGEND:
4456                         arg_no_legend = true;
4457                         break;
4458
4459                 case ARG_NO_PAGER:
4460                         arg_no_pager = true;
4461                         break;
4462
4463                 case ARG_NO_WALL:
4464                         arg_no_wall = true;
4465                         break;
4466
4467                 case ARG_ROOT:
4468                         arg_root = optarg;
4469                         break;
4470
4471                 case ARG_FULL:
4472                         arg_full = true;
4473                         break;
4474
4475                 case ARG_FAILED:
4476                         arg_failed = true;
4477                         break;
4478
4479                 case 'q':
4480                         arg_quiet = true;
4481                         break;
4482
4483                 case ARG_FORCE:
4484                         arg_force ++;
4485                         break;
4486
4487                 case 'f':
4488                         arg_force ++;
4489                         break;
4490
4491                 case ARG_NO_RELOAD:
4492                         arg_no_reload = true;
4493                         break;
4494
4495                 case ARG_KILL_WHO:
4496                         arg_kill_who = optarg;
4497                         break;
4498
4499                 case 's':
4500                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4501                                 log_error("Failed to parse signal string %s.", optarg);
4502                                 return -EINVAL;
4503                         }
4504                         break;
4505
4506                 case ARG_NO_ASK_PASSWORD:
4507                         arg_ask_password = false;
4508                         break;
4509
4510                 case 'P':
4511                         arg_transport = TRANSPORT_POLKIT;
4512                         break;
4513
4514                 case 'H':
4515                         arg_transport = TRANSPORT_SSH;
4516                         arg_host = optarg;
4517                         break;
4518
4519                 case ARG_RUNTIME:
4520                         arg_runtime = true;
4521                         break;
4522
4523                 case 'n':
4524                         if (safe_atou(optarg, &arg_lines) < 0) {
4525                                 log_error("Failed to parse lines '%s'", optarg);
4526                                 return -EINVAL;
4527                         }
4528                         break;
4529
4530                 case 'o':
4531                         arg_output = output_mode_from_string(optarg);
4532                         if (arg_output < 0) {
4533                                 log_error("Unknown output '%s'.", optarg);
4534                                 return -EINVAL;
4535                         }
4536                         break;
4537
4538                 case 'i':
4539                         arg_ignore_inhibitors = true;
4540                         break;
4541
4542                 case '?':
4543                         return -EINVAL;
4544
4545                 default:
4546                         log_error("Unknown option code '%c'.", c);
4547                         return -EINVAL;
4548                 }
4549         }
4550
4551         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4552                 log_error("Cannot access user instance remotely.");
4553                 return -EINVAL;
4554         }
4555
4556         return 1;
4557 }
4558
4559 static int halt_parse_argv(int argc, char *argv[]) {
4560
4561         enum {
4562                 ARG_HELP = 0x100,
4563                 ARG_HALT,
4564                 ARG_REBOOT,
4565                 ARG_NO_WALL
4566         };
4567
4568         static const struct option options[] = {
4569                 { "help",      no_argument,       NULL, ARG_HELP    },
4570                 { "halt",      no_argument,       NULL, ARG_HALT    },
4571                 { "poweroff",  no_argument,       NULL, 'p'         },
4572                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4573                 { "force",     no_argument,       NULL, 'f'         },
4574                 { "wtmp-only", no_argument,       NULL, 'w'         },
4575                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4576                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4577                 { NULL,        0,                 NULL, 0           }
4578         };
4579
4580         int c, runlevel;
4581
4582         assert(argc >= 0);
4583         assert(argv);
4584
4585         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4586                 if (runlevel == '0' || runlevel == '6')
4587                         arg_force = 2;
4588
4589         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4590                 switch (c) {
4591
4592                 case ARG_HELP:
4593                         halt_help();
4594                         return 0;
4595
4596                 case ARG_HALT:
4597                         arg_action = ACTION_HALT;
4598                         break;
4599
4600                 case 'p':
4601                         if (arg_action != ACTION_REBOOT)
4602                                 arg_action = ACTION_POWEROFF;
4603                         break;
4604
4605                 case ARG_REBOOT:
4606                         arg_action = ACTION_REBOOT;
4607                         break;
4608
4609                 case 'f':
4610                         arg_force = 2;
4611                         break;
4612
4613                 case 'w':
4614                         arg_dry = true;
4615                         break;
4616
4617                 case 'd':
4618                         arg_no_wtmp = true;
4619                         break;
4620
4621                 case ARG_NO_WALL:
4622                         arg_no_wall = true;
4623                         break;
4624
4625                 case 'i':
4626                 case 'h':
4627                 case 'n':
4628                         /* Compatibility nops */
4629                         break;
4630
4631                 case '?':
4632                         return -EINVAL;
4633
4634                 default:
4635                         log_error("Unknown option code '%c'.", c);
4636                         return -EINVAL;
4637                 }
4638         }
4639
4640         if (optind < argc) {
4641                 log_error("Too many arguments.");
4642                 return -EINVAL;
4643         }
4644
4645         return 1;
4646 }
4647
4648 static int parse_time_spec(const char *t, usec_t *_u) {
4649         assert(t);
4650         assert(_u);
4651
4652         if (streq(t, "now"))
4653                 *_u = 0;
4654         else if (!strchr(t, ':')) {
4655                 uint64_t u;
4656
4657                 if (safe_atou64(t, &u) < 0)
4658                         return -EINVAL;
4659
4660                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4661         } else {
4662                 char *e = NULL;
4663                 long hour, minute;
4664                 struct tm tm;
4665                 time_t s;
4666                 usec_t n;
4667
4668                 errno = 0;
4669                 hour = strtol(t, &e, 10);
4670                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4671                         return -EINVAL;
4672
4673                 minute = strtol(e+1, &e, 10);
4674                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4675                         return -EINVAL;
4676
4677                 n = now(CLOCK_REALTIME);
4678                 s = (time_t) (n / USEC_PER_SEC);
4679
4680                 zero(tm);
4681                 assert_se(localtime_r(&s, &tm));
4682
4683                 tm.tm_hour = (int) hour;
4684                 tm.tm_min = (int) minute;
4685                 tm.tm_sec = 0;
4686
4687                 assert_se(s = mktime(&tm));
4688
4689                 *_u = (usec_t) s * USEC_PER_SEC;
4690
4691                 while (*_u <= n)
4692                         *_u += USEC_PER_DAY;
4693         }
4694
4695         return 0;
4696 }
4697
4698 static int shutdown_parse_argv(int argc, char *argv[]) {
4699
4700         enum {
4701                 ARG_HELP = 0x100,
4702                 ARG_NO_WALL
4703         };
4704
4705         static const struct option options[] = {
4706                 { "help",      no_argument,       NULL, ARG_HELP    },
4707                 { "halt",      no_argument,       NULL, 'H'         },
4708                 { "poweroff",  no_argument,       NULL, 'P'         },
4709                 { "reboot",    no_argument,       NULL, 'r'         },
4710                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4711                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4712                 { NULL,        0,                 NULL, 0           }
4713         };
4714
4715         int c, r;
4716
4717         assert(argc >= 0);
4718         assert(argv);
4719
4720         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4721                 switch (c) {
4722
4723                 case ARG_HELP:
4724                         shutdown_help();
4725                         return 0;
4726
4727                 case 'H':
4728                         arg_action = ACTION_HALT;
4729                         break;
4730
4731                 case 'P':
4732                         arg_action = ACTION_POWEROFF;
4733                         break;
4734
4735                 case 'r':
4736                         if (kexec_loaded())
4737                                 arg_action = ACTION_KEXEC;
4738                         else
4739                                 arg_action = ACTION_REBOOT;
4740                         break;
4741
4742                 case 'K':
4743                         arg_action = ACTION_KEXEC;
4744                         break;
4745
4746                 case 'h':
4747                         if (arg_action != ACTION_HALT)
4748                                 arg_action = ACTION_POWEROFF;
4749                         break;
4750
4751                 case 'k':
4752                         arg_dry = true;
4753                         break;
4754
4755                 case ARG_NO_WALL:
4756                         arg_no_wall = true;
4757                         break;
4758
4759                 case 't':
4760                 case 'a':
4761                         /* Compatibility nops */
4762                         break;
4763
4764                 case 'c':
4765                         arg_action = ACTION_CANCEL_SHUTDOWN;
4766                         break;
4767
4768                 case '?':
4769                         return -EINVAL;
4770
4771                 default:
4772                         log_error("Unknown option code '%c'.", c);
4773                         return -EINVAL;
4774                 }
4775         }
4776
4777         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4778                 r = parse_time_spec(argv[optind], &arg_when);
4779                 if (r < 0) {
4780                         log_error("Failed to parse time specification: %s", argv[optind]);
4781                         return r;
4782                 }
4783         } else
4784                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4785
4786         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4787                 /* No time argument for shutdown cancel */
4788                 arg_wall = argv + optind;
4789         else if (argc > optind + 1)
4790                 /* We skip the time argument */
4791                 arg_wall = argv + optind + 1;
4792
4793         optind = argc;
4794
4795         return 1;
4796 }
4797
4798 static int telinit_parse_argv(int argc, char *argv[]) {
4799
4800         enum {
4801                 ARG_HELP = 0x100,
4802                 ARG_NO_WALL
4803         };
4804
4805         static const struct option options[] = {
4806                 { "help",      no_argument,       NULL, ARG_HELP    },
4807                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4808                 { NULL,        0,                 NULL, 0           }
4809         };
4810
4811         static const struct {
4812                 char from;
4813                 enum action to;
4814         } table[] = {
4815                 { '0', ACTION_POWEROFF },
4816                 { '6', ACTION_REBOOT },
4817                 { '1', ACTION_RESCUE },
4818                 { '2', ACTION_RUNLEVEL2 },
4819                 { '3', ACTION_RUNLEVEL3 },
4820                 { '4', ACTION_RUNLEVEL4 },
4821                 { '5', ACTION_RUNLEVEL5 },
4822                 { 's', ACTION_RESCUE },
4823                 { 'S', ACTION_RESCUE },
4824                 { 'q', ACTION_RELOAD },
4825                 { 'Q', ACTION_RELOAD },
4826                 { 'u', ACTION_REEXEC },
4827                 { 'U', ACTION_REEXEC }
4828         };
4829
4830         unsigned i;
4831         int c;
4832
4833         assert(argc >= 0);
4834         assert(argv);
4835
4836         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4837                 switch (c) {
4838
4839                 case ARG_HELP:
4840                         telinit_help();
4841                         return 0;
4842
4843                 case ARG_NO_WALL:
4844                         arg_no_wall = true;
4845                         break;
4846
4847                 case '?':
4848                         return -EINVAL;
4849
4850                 default:
4851                         log_error("Unknown option code '%c'.", c);
4852                         return -EINVAL;
4853                 }
4854         }
4855
4856         if (optind >= argc) {
4857                 telinit_help();
4858                 return -EINVAL;
4859         }
4860
4861         if (optind + 1 < argc) {
4862                 log_error("Too many arguments.");
4863                 return -EINVAL;
4864         }
4865
4866         if (strlen(argv[optind]) != 1) {
4867                 log_error("Expected single character argument.");
4868                 return -EINVAL;
4869         }
4870
4871         for (i = 0; i < ELEMENTSOF(table); i++)
4872                 if (table[i].from == argv[optind][0])
4873                         break;
4874
4875         if (i >= ELEMENTSOF(table)) {
4876                 log_error("Unknown command '%s'.", argv[optind]);
4877                 return -EINVAL;
4878         }
4879
4880         arg_action = table[i].to;
4881
4882         optind ++;
4883
4884         return 1;
4885 }
4886
4887 static int runlevel_parse_argv(int argc, char *argv[]) {
4888
4889         enum {
4890                 ARG_HELP = 0x100,
4891         };
4892
4893         static const struct option options[] = {
4894                 { "help",      no_argument,       NULL, ARG_HELP    },
4895                 { NULL,        0,                 NULL, 0           }
4896         };
4897
4898         int c;
4899
4900         assert(argc >= 0);
4901         assert(argv);
4902
4903         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4904                 switch (c) {
4905
4906                 case ARG_HELP:
4907                         runlevel_help();
4908                         return 0;
4909
4910                 case '?':
4911                         return -EINVAL;
4912
4913                 default:
4914                         log_error("Unknown option code '%c'.", c);
4915                         return -EINVAL;
4916                 }
4917         }
4918
4919         if (optind < argc) {
4920                 log_error("Too many arguments.");
4921                 return -EINVAL;
4922         }
4923
4924         return 1;
4925 }
4926
4927 static int parse_argv(int argc, char *argv[]) {
4928         assert(argc >= 0);
4929         assert(argv);
4930
4931         if (program_invocation_short_name) {
4932
4933                 if (strstr(program_invocation_short_name, "halt")) {
4934                         arg_action = ACTION_HALT;
4935                         return halt_parse_argv(argc, argv);
4936                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4937                         arg_action = ACTION_POWEROFF;
4938                         return halt_parse_argv(argc, argv);
4939                 } else if (strstr(program_invocation_short_name, "reboot")) {
4940                         if (kexec_loaded())
4941                                 arg_action = ACTION_KEXEC;
4942                         else
4943                                 arg_action = ACTION_REBOOT;
4944                         return halt_parse_argv(argc, argv);
4945                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4946                         arg_action = ACTION_POWEROFF;
4947                         return shutdown_parse_argv(argc, argv);
4948                 } else if (strstr(program_invocation_short_name, "init")) {
4949
4950                         if (sd_booted() > 0) {
4951                                 arg_action = ACTION_INVALID;
4952                                 return telinit_parse_argv(argc, argv);
4953                         } else {
4954                                 /* Hmm, so some other init system is
4955                                  * running, we need to forward this
4956                                  * request to it. For now we simply
4957                                  * guess that it is Upstart. */
4958
4959                                 execv("/lib/upstart/telinit", argv);
4960
4961                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4962                                 return -EIO;
4963                         }
4964
4965                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4966                         arg_action = ACTION_RUNLEVEL;
4967                         return runlevel_parse_argv(argc, argv);
4968                 }
4969         }
4970
4971         arg_action = ACTION_SYSTEMCTL;
4972         return systemctl_parse_argv(argc, argv);
4973 }
4974
4975 static int action_to_runlevel(void) {
4976
4977         static const char table[_ACTION_MAX] = {
4978                 [ACTION_HALT] =      '0',
4979                 [ACTION_POWEROFF] =  '0',
4980                 [ACTION_REBOOT] =    '6',
4981                 [ACTION_RUNLEVEL2] = '2',
4982                 [ACTION_RUNLEVEL3] = '3',
4983                 [ACTION_RUNLEVEL4] = '4',
4984                 [ACTION_RUNLEVEL5] = '5',
4985                 [ACTION_RESCUE] =    '1'
4986         };
4987
4988         assert(arg_action < _ACTION_MAX);
4989
4990         return table[arg_action];
4991 }
4992
4993 static int talk_upstart(void) {
4994         DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
4995         DBusError _cleanup_dbus_error_free_ error;
4996         int previous, rl, r;
4997         char
4998                 env1_buf[] = "RUNLEVEL=X",
4999                 env2_buf[] = "PREVLEVEL=X";
5000         char *env1 = env1_buf, *env2 = env2_buf;
5001         const char *emit = "runlevel";
5002         dbus_bool_t b_false = FALSE;
5003         DBusMessageIter iter, sub;
5004         DBusConnection *bus;
5005
5006         dbus_error_init(&error);
5007
5008         if (!(rl = action_to_runlevel()))
5009                 return 0;
5010
5011         if (utmp_get_runlevel(&previous, NULL) < 0)
5012                 previous = 'N';
5013
5014         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5015                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5016                         r = 0;
5017                         goto finish;
5018                 }
5019
5020                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5021                 r = -EIO;
5022                 goto finish;
5023         }
5024
5025         if ((r = bus_check_peercred(bus)) < 0) {
5026                 log_error("Failed to verify owner of bus.");
5027                 goto finish;
5028         }
5029
5030         if (!(m = dbus_message_new_method_call(
5031                               "com.ubuntu.Upstart",
5032                               "/com/ubuntu/Upstart",
5033                               "com.ubuntu.Upstart0_6",
5034                               "EmitEvent"))) {
5035
5036                 log_error("Could not allocate message.");
5037                 r = -ENOMEM;
5038                 goto finish;
5039         }
5040
5041         dbus_message_iter_init_append(m, &iter);
5042
5043         env1_buf[sizeof(env1_buf)-2] = rl;
5044         env2_buf[sizeof(env2_buf)-2] = previous;
5045
5046         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5047             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5048             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5049             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5050             !dbus_message_iter_close_container(&iter, &sub) ||
5051             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5052                 log_error("Could not append arguments to message.");
5053                 r = -ENOMEM;
5054                 goto finish;
5055         }
5056
5057         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5058
5059                 if (bus_error_is_no_service(&error)) {
5060                         r = -EADDRNOTAVAIL;
5061                         goto finish;
5062                 }
5063
5064                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5065                 r = -EIO;
5066                 goto finish;
5067         }
5068
5069         r = 1;
5070
5071 finish:
5072         if (bus) {
5073                 dbus_connection_flush(bus);
5074                 dbus_connection_close(bus);
5075                 dbus_connection_unref(bus);
5076         }
5077
5078         return r;
5079 }
5080
5081 static int talk_initctl(void) {
5082         struct init_request request;
5083         int r, fd;
5084         char rl;
5085
5086         if (!(rl = action_to_runlevel()))
5087                 return 0;
5088
5089         zero(request);
5090         request.magic = INIT_MAGIC;
5091         request.sleeptime = 0;
5092         request.cmd = INIT_CMD_RUNLVL;
5093         request.runlevel = rl;
5094
5095         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5096
5097                 if (errno == ENOENT)
5098                         return 0;
5099
5100                 log_error("Failed to open "INIT_FIFO": %m");
5101                 return -errno;
5102         }
5103
5104         errno = 0;
5105         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5106         close_nointr_nofail(fd);
5107
5108         if (r < 0) {
5109                 log_error("Failed to write to "INIT_FIFO": %m");
5110                 return errno ? -errno : -EIO;
5111         }
5112
5113         return 1;
5114 }
5115
5116 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5117
5118         static const struct {
5119                 const char* verb;
5120                 const enum {
5121                         MORE,
5122                         LESS,
5123                         EQUAL
5124                 } argc_cmp;
5125                 const int argc;
5126                 int (* const dispatch)(DBusConnection *bus, char **args);
5127         } verbs[] = {
5128                 { "list-units",            LESS,  1, list_units        },
5129                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5130                 { "list-jobs",             EQUAL, 1, list_jobs         },
5131                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5132                 { "load",                  MORE,  2, load_unit         },
5133                 { "cancel",                MORE,  2, cancel_job        },
5134                 { "start",                 MORE,  2, start_unit        },
5135                 { "stop",                  MORE,  2, start_unit        },
5136                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5137                 { "reload",                MORE,  2, start_unit        },
5138                 { "restart",               MORE,  2, start_unit        },
5139                 { "try-restart",           MORE,  2, start_unit        },
5140                 { "reload-or-restart",     MORE,  2, start_unit        },
5141                 { "reload-or-try-restart", MORE,  2, start_unit        },
5142                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5143                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5144                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5145                 { "isolate",               EQUAL, 2, start_unit        },
5146                 { "set-cgroup",            MORE,  2, set_cgroup        },
5147                 { "unset-cgroup",          MORE,  2, set_cgroup        },
5148                 { "get-cgroup-attr",       MORE,  2, get_cgroup_attr   },
5149                 { "set-cgroup-attr",       MORE,  2, set_cgroup_attr   },
5150                 { "unset-cgroup-attr",     MORE,  2, set_cgroup        },
5151                 { "kill",                  MORE,  2, kill_unit         },
5152                 { "is-active",             MORE,  2, check_unit_active },
5153                 { "check",                 MORE,  2, check_unit_active },
5154                 { "is-failed",             MORE,  2, check_unit_failed },
5155                 { "show",                  MORE,  1, show              },
5156                 { "status",                MORE,  1, show              },
5157                 { "help",                  MORE,  2, show              },
5158                 { "dump",                  EQUAL, 1, dump              },
5159                 { "snapshot",              LESS,  2, snapshot          },
5160                 { "delete",                MORE,  2, delete_snapshot   },
5161                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5162                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5163                 { "show-environment",      EQUAL, 1, show_enviroment   },
5164                 { "set-environment",       MORE,  2, set_environment   },
5165                 { "unset-environment",     MORE,  2, set_environment   },
5166                 { "halt",                  EQUAL, 1, start_special     },
5167                 { "poweroff",              EQUAL, 1, start_special     },
5168                 { "reboot",                EQUAL, 1, start_special     },
5169                 { "kexec",                 EQUAL, 1, start_special     },
5170                 { "suspend",               EQUAL, 1, start_special     },
5171                 { "hibernate",             EQUAL, 1, start_special     },
5172                 { "hybrid-sleep",          EQUAL, 1, start_special     },
5173                 { "default",               EQUAL, 1, start_special     },
5174                 { "rescue",                EQUAL, 1, start_special     },
5175                 { "emergency",             EQUAL, 1, start_special     },
5176                 { "exit",                  EQUAL, 1, start_special     },
5177                 { "reset-failed",          MORE,  1, reset_failed      },
5178                 { "enable",                MORE,  2, enable_unit       },
5179                 { "disable",               MORE,  2, enable_unit       },
5180                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5181                 { "reenable",              MORE,  2, enable_unit       },
5182                 { "preset",                MORE,  2, enable_unit       },
5183                 { "mask",                  MORE,  2, enable_unit       },
5184                 { "unmask",                MORE,  2, enable_unit       },
5185                 { "link",                  MORE,  2, enable_unit       },
5186                 { "switch-root",           MORE,  2, switch_root       },
5187                 { "list-dependencies",     LESS,  2, list_dependencies },
5188         };
5189
5190         int left;
5191         unsigned i;
5192
5193         assert(argc >= 0);
5194         assert(argv);
5195         assert(error);
5196
5197         left = argc - optind;
5198
5199         if (left <= 0)
5200                 /* Special rule: no arguments means "list-units" */
5201                 i = 0;
5202         else {
5203                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5204                         log_error("This command expects one or more "
5205                                   "unit names. Did you mean --help?");
5206                         return -EINVAL;
5207                 }
5208
5209                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5210                         if (streq(argv[optind], verbs[i].verb))
5211                                 break;
5212
5213                 if (i >= ELEMENTSOF(verbs)) {
5214                         log_error("Unknown operation '%s'.", argv[optind]);
5215                         return -EINVAL;
5216                 }
5217         }
5218
5219         switch (verbs[i].argc_cmp) {
5220
5221         case EQUAL:
5222                 if (left != verbs[i].argc) {
5223                         log_error("Invalid number of arguments.");
5224                         return -EINVAL;
5225                 }
5226
5227                 break;
5228
5229         case MORE:
5230                 if (left < verbs[i].argc) {
5231                         log_error("Too few arguments.");
5232                         return -EINVAL;
5233                 }
5234
5235                 break;
5236
5237         case LESS:
5238                 if (left > verbs[i].argc) {
5239                         log_error("Too many arguments.");
5240                         return -EINVAL;
5241                 }
5242
5243                 break;
5244
5245         default:
5246                 assert_not_reached("Unknown comparison operator.");
5247         }
5248
5249         /* Require a bus connection for all operations but
5250          * enable/disable */
5251         if (!streq(verbs[i].verb, "enable") &&
5252             !streq(verbs[i].verb, "disable") &&
5253             !streq(verbs[i].verb, "is-enabled") &&
5254             !streq(verbs[i].verb, "list-unit-files") &&
5255             !streq(verbs[i].verb, "reenable") &&
5256             !streq(verbs[i].verb, "preset") &&
5257             !streq(verbs[i].verb, "mask") &&
5258             !streq(verbs[i].verb, "unmask") &&
5259             !streq(verbs[i].verb, "link")) {
5260
5261                 if (running_in_chroot() > 0) {
5262                         log_info("Running in chroot, ignoring request.");
5263                         return 0;
5264                 }
5265
5266                 if (((!streq(verbs[i].verb, "reboot") &&
5267                       !streq(verbs[i].verb, "halt") &&
5268                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5269                         log_error("Failed to get D-Bus connection: %s",
5270                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5271                         return -EIO;
5272                 }
5273
5274         } else {
5275
5276                 if (!bus && !avoid_bus()) {
5277                         log_error("Failed to get D-Bus connection: %s",
5278                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5279                         return -EIO;
5280                 }
5281         }
5282
5283         return verbs[i].dispatch(bus, argv + optind);
5284 }
5285
5286 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5287         int _cleanup_close_ fd;
5288         struct msghdr msghdr;
5289         struct iovec iovec[2];
5290         union sockaddr_union sockaddr;
5291         struct sd_shutdown_command c;
5292
5293         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5294         if (fd < 0)
5295                 return -errno;
5296
5297         zero(c);
5298         c.usec = t;
5299         c.mode = mode;
5300         c.dry_run = dry_run;
5301         c.warn_wall = warn;
5302
5303         zero(sockaddr);
5304         sockaddr.sa.sa_family = AF_UNIX;
5305         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5306
5307         zero(msghdr);
5308         msghdr.msg_name = &sockaddr;
5309         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5310
5311         zero(iovec);
5312         iovec[0].iov_base = (char*) &c;
5313         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5314
5315         if (isempty(message))
5316                 msghdr.msg_iovlen = 1;
5317         else {
5318                 iovec[1].iov_base = (char*) message;
5319                 iovec[1].iov_len = strlen(message);
5320                 msghdr.msg_iovlen = 2;
5321         }
5322         msghdr.msg_iov = iovec;
5323
5324         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
5325                 return -errno;
5326
5327         return 0;
5328 }
5329
5330 static int reload_with_fallback(DBusConnection *bus) {
5331
5332         if (bus) {
5333                 /* First, try systemd via D-Bus. */
5334                 if (daemon_reload(bus, NULL) >= 0)
5335                         return 0;
5336         }
5337
5338         /* Nothing else worked, so let's try signals */
5339         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5340
5341         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5342                 log_error("kill() failed: %m");
5343                 return -errno;
5344         }
5345
5346         return 0;
5347 }
5348
5349 static int start_with_fallback(DBusConnection *bus) {
5350
5351         if (bus) {
5352                 /* First, try systemd via D-Bus. */
5353                 if (start_unit(bus, NULL) >= 0)
5354                         goto done;
5355         }
5356
5357         /* Hmm, talking to systemd via D-Bus didn't work. Then
5358          * let's try to talk to Upstart via D-Bus. */
5359         if (talk_upstart() > 0)
5360                 goto done;
5361
5362         /* Nothing else worked, so let's try
5363          * /dev/initctl */
5364         if (talk_initctl() > 0)
5365                 goto done;
5366
5367         log_error("Failed to talk to init daemon.");
5368         return -EIO;
5369
5370 done:
5371         warn_wall(arg_action);
5372         return 0;
5373 }
5374
5375 static _noreturn_ void halt_now(enum action a) {
5376
5377        /* Make sure C-A-D is handled by the kernel from this
5378          * point on... */
5379         reboot(RB_ENABLE_CAD);
5380
5381         switch (a) {
5382
5383         case ACTION_HALT:
5384                 log_info("Halting.");
5385                 reboot(RB_HALT_SYSTEM);
5386                 break;
5387
5388         case ACTION_POWEROFF:
5389                 log_info("Powering off.");
5390                 reboot(RB_POWER_OFF);
5391                 break;
5392
5393         case ACTION_REBOOT:
5394                 log_info("Rebooting.");
5395                 reboot(RB_AUTOBOOT);
5396                 break;
5397
5398         default:
5399                 assert_not_reached("Unknown halt action.");
5400         }
5401
5402         assert_not_reached("Uh? This shouldn't happen.");
5403 }
5404
5405 static int halt_main(DBusConnection *bus) {
5406         int r;
5407
5408         r = check_inhibitors(bus, arg_action);
5409         if (r < 0)
5410                 return r;
5411
5412         if (geteuid() != 0) {
5413                 /* Try logind if we are a normal user and no special
5414                  * mode applies. Maybe PolicyKit allows us to shutdown
5415                  * the machine. */
5416
5417                 if (arg_when <= 0 &&
5418                     !arg_dry &&
5419                     arg_force <= 0 &&
5420                     (arg_action == ACTION_POWEROFF ||
5421                      arg_action == ACTION_REBOOT)) {
5422                         r = reboot_with_logind(bus, arg_action);
5423                         if (r >= 0)
5424                                 return r;
5425                 }
5426
5427                 log_error("Must be root.");
5428                 return -EPERM;
5429         }
5430
5431         if (arg_when > 0) {
5432                 char _cleanup_free_ *m;
5433
5434                 m = strv_join(arg_wall, " ");
5435                 r = send_shutdownd(arg_when,
5436                                    arg_action == ACTION_HALT     ? 'H' :
5437                                    arg_action == ACTION_POWEROFF ? 'P' :
5438                                    arg_action == ACTION_KEXEC    ? 'K' :
5439                                                                    'r',
5440                                    arg_dry,
5441                                    !arg_no_wall,
5442                                    m);
5443
5444                 if (r < 0)
5445                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5446                 else {
5447                         char date[FORMAT_TIMESTAMP_MAX];
5448
5449                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5450                                  format_timestamp(date, sizeof(date), arg_when));
5451                         return 0;
5452                 }
5453         }
5454
5455         if (!arg_dry && !arg_force)
5456                 return start_with_fallback(bus);
5457
5458         if (!arg_no_wtmp) {
5459                 if (sd_booted() > 0)
5460                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5461                 else {
5462                         r = utmp_put_shutdown();
5463                         if (r < 0)
5464                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5465                 }
5466         }
5467
5468         if (arg_dry)
5469                 return 0;
5470
5471         halt_now(arg_action);
5472         /* We should never reach this. */
5473         return -ENOSYS;
5474 }
5475
5476 static int runlevel_main(void) {
5477         int r, runlevel, previous;
5478
5479         r = utmp_get_runlevel(&runlevel, &previous);
5480         if (r < 0) {
5481                 puts("unknown");
5482                 return r;
5483         }
5484
5485         printf("%c %c\n",
5486                previous <= 0 ? 'N' : previous,
5487                runlevel <= 0 ? 'N' : runlevel);
5488
5489         return 0;
5490 }
5491
5492 int main(int argc, char*argv[]) {
5493         int r, retval = EXIT_FAILURE;
5494         DBusConnection *bus = NULL;
5495         DBusError _cleanup_dbus_error_free_ error;
5496
5497         dbus_error_init(&error);
5498
5499         setlocale(LC_ALL, "");
5500         log_parse_environment();
5501         log_open();
5502
5503         r = parse_argv(argc, argv);
5504         if (r < 0)
5505                 goto finish;
5506         else if (r == 0) {
5507                 retval = EXIT_SUCCESS;
5508                 goto finish;
5509         }
5510
5511         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5512          * let's shortcut this */
5513         if (arg_action == ACTION_RUNLEVEL) {
5514                 r = runlevel_main();
5515                 retval = r < 0 ? EXIT_FAILURE : r;
5516                 goto finish;
5517         }
5518
5519         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5520                 log_info("Running in chroot, ignoring request.");
5521                 retval = 0;
5522                 goto finish;
5523         }
5524
5525         if (!avoid_bus()) {
5526                 if (arg_transport == TRANSPORT_NORMAL)
5527                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5528                 else if (arg_transport == TRANSPORT_POLKIT) {
5529                         bus_connect_system_polkit(&bus, &error);
5530                         private_bus = false;
5531                 } else if (arg_transport == TRANSPORT_SSH) {
5532                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5533                         private_bus = false;
5534                 } else
5535                         assert_not_reached("Uh, invalid transport...");
5536         }
5537
5538         switch (arg_action) {
5539
5540         case ACTION_SYSTEMCTL:
5541                 r = systemctl_main(bus, argc, argv, &error);
5542                 break;
5543
5544         case ACTION_HALT:
5545         case ACTION_POWEROFF:
5546         case ACTION_REBOOT:
5547         case ACTION_KEXEC:
5548                 r = halt_main(bus);
5549                 break;
5550
5551         case ACTION_RUNLEVEL2:
5552         case ACTION_RUNLEVEL3:
5553         case ACTION_RUNLEVEL4:
5554         case ACTION_RUNLEVEL5:
5555         case ACTION_RESCUE:
5556         case ACTION_EMERGENCY:
5557         case ACTION_DEFAULT:
5558                 r = start_with_fallback(bus);
5559                 break;
5560
5561         case ACTION_RELOAD:
5562         case ACTION_REEXEC:
5563                 r = reload_with_fallback(bus);
5564                 break;
5565
5566         case ACTION_CANCEL_SHUTDOWN: {
5567                 char *m = NULL;
5568
5569                 if (arg_wall) {
5570                         m = strv_join(arg_wall, " ");
5571                         if (!m) {
5572                                 retval = EXIT_FAILURE;
5573                                 goto finish;
5574                         }
5575                 }
5576                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5577                 if (r < 0)
5578                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5579                 free(m);
5580                 break;
5581         }
5582
5583         case ACTION_INVALID:
5584         case ACTION_RUNLEVEL:
5585         default:
5586                 assert_not_reached("Unknown action");
5587         }
5588
5589         retval = r < 0 ? EXIT_FAILURE : r;
5590
5591 finish:
5592         if (bus) {
5593                 dbus_connection_flush(bus);
5594                 dbus_connection_close(bus);
5595                 dbus_connection_unref(bus);
5596         }
5597
5598         dbus_shutdown();
5599
5600         strv_free(arg_property);
5601
5602         pager_close();
5603         ask_password_agent_close();
5604         polkit_agent_close();
5605
5606         return retval;
5607 }