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