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