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