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