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