chiark / gitweb /
6ab92cebf0fd34b5ac60766358c34b08666462ee
[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                 printf("\n");
2596                 show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow, !arg_quiet);
2597         }
2598
2599         if (i->need_daemon_reload)
2600                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2601                        ansi_highlight_red(true),
2602                        ansi_highlight_red(false),
2603                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2604 }
2605
2606 static void show_unit_help(UnitStatusInfo *i) {
2607         char **p;
2608
2609         assert(i);
2610
2611         if (!i->documentation) {
2612                 log_info("Documentation for %s not known.", i->id);
2613                 return;
2614         }
2615
2616         STRV_FOREACH(p, i->documentation) {
2617
2618                 if (startswith(*p, "man:")) {
2619                         size_t k;
2620                         char *e = NULL;
2621                         char *page = NULL, *section = NULL;
2622                         const char *args[4] = { "man", NULL, NULL, NULL };
2623                         pid_t pid;
2624
2625                         k = strlen(*p);
2626
2627                         if ((*p)[k-1] == ')')
2628                                 e = strrchr(*p, '(');
2629
2630                         if (e) {
2631                                 page = strndup((*p) + 4, e - *p - 4);
2632                                 if (!page) {
2633                                         log_error("Out of memory.");
2634                                         return;
2635                                 }
2636
2637                                 section = strndup(e + 1, *p + k - e - 2);
2638                                 if (!section) {
2639                                         free(page);
2640                                         log_error("Out of memory");
2641                                         return;
2642                                 }
2643
2644                                 args[1] = section;
2645                                 args[2] = page;
2646                         } else
2647                                 args[1] = *p + 4;
2648
2649                         pid = fork();
2650                         if (pid < 0) {
2651                                 log_error("Failed to fork: %m");
2652                                 free(page);
2653                                 free(section);
2654                                 continue;
2655                         }
2656
2657                         if (pid == 0) {
2658                                 /* Child */
2659                                 execvp(args[0], (char**) args);
2660                                 log_error("Failed to execute man: %m");
2661                                 _exit(EXIT_FAILURE);
2662                         }
2663
2664                         free(page);
2665                         free(section);
2666
2667                         wait_for_terminate(pid, NULL);
2668                 } else
2669                         log_info("Can't show: %s", *p);
2670         }
2671 }
2672
2673 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2674
2675         assert(name);
2676         assert(iter);
2677         assert(i);
2678
2679         switch (dbus_message_iter_get_arg_type(iter)) {
2680
2681         case DBUS_TYPE_STRING: {
2682                 const char *s;
2683
2684                 dbus_message_iter_get_basic(iter, &s);
2685
2686                 if (!isempty(s)) {
2687                         if (streq(name, "Id"))
2688                                 i->id = s;
2689                         else if (streq(name, "LoadState"))
2690                                 i->load_state = s;
2691                         else if (streq(name, "ActiveState"))
2692                                 i->active_state = s;
2693                         else if (streq(name, "SubState"))
2694                                 i->sub_state = s;
2695                         else if (streq(name, "Description"))
2696                                 i->description = s;
2697                         else if (streq(name, "FragmentPath"))
2698                                 i->fragment_path = s;
2699                         else if (streq(name, "SourcePath"))
2700                                 i->source_path = s;
2701                         else if (streq(name, "DefaultControlGroup"))
2702                                 i->default_control_group = s;
2703                         else if (streq(name, "StatusText"))
2704                                 i->status_text = s;
2705                         else if (streq(name, "SysFSPath"))
2706                                 i->sysfs_path = s;
2707                         else if (streq(name, "Where"))
2708                                 i->where = s;
2709                         else if (streq(name, "What"))
2710                                 i->what = s;
2711                         else if (streq(name, "Following"))
2712                                 i->following = s;
2713                         else if (streq(name, "UnitFileState"))
2714                                 i->unit_file_state = s;
2715                         else if (streq(name, "Result"))
2716                                 i->result = s;
2717                 }
2718
2719                 break;
2720         }
2721
2722         case DBUS_TYPE_BOOLEAN: {
2723                 dbus_bool_t b;
2724
2725                 dbus_message_iter_get_basic(iter, &b);
2726
2727                 if (streq(name, "Accept"))
2728                         i->accept = b;
2729                 else if (streq(name, "NeedDaemonReload"))
2730                         i->need_daemon_reload = b;
2731                 else if (streq(name, "ConditionResult"))
2732                         i->condition_result = b;
2733
2734                 break;
2735         }
2736
2737         case DBUS_TYPE_UINT32: {
2738                 uint32_t u;
2739
2740                 dbus_message_iter_get_basic(iter, &u);
2741
2742                 if (streq(name, "MainPID")) {
2743                         if (u > 0) {
2744                                 i->main_pid = (pid_t) u;
2745                                 i->running = true;
2746                         }
2747                 } else if (streq(name, "ControlPID"))
2748                         i->control_pid = (pid_t) u;
2749                 else if (streq(name, "ExecMainPID")) {
2750                         if (u > 0)
2751                                 i->main_pid = (pid_t) u;
2752                 } else if (streq(name, "NAccepted"))
2753                         i->n_accepted = u;
2754                 else if (streq(name, "NConnections"))
2755                         i->n_connections = u;
2756
2757                 break;
2758         }
2759
2760         case DBUS_TYPE_INT32: {
2761                 int32_t j;
2762
2763                 dbus_message_iter_get_basic(iter, &j);
2764
2765                 if (streq(name, "ExecMainCode"))
2766                         i->exit_code = (int) j;
2767                 else if (streq(name, "ExecMainStatus"))
2768                         i->exit_status = (int) j;
2769
2770                 break;
2771         }
2772
2773         case DBUS_TYPE_UINT64: {
2774                 uint64_t u;
2775
2776                 dbus_message_iter_get_basic(iter, &u);
2777
2778                 if (streq(name, "ExecMainStartTimestamp"))
2779                         i->start_timestamp = (usec_t) u;
2780                 else if (streq(name, "ExecMainExitTimestamp"))
2781                         i->exit_timestamp = (usec_t) u;
2782                 else if (streq(name, "ActiveEnterTimestamp"))
2783                         i->active_enter_timestamp = (usec_t) u;
2784                 else if (streq(name, "InactiveEnterTimestamp"))
2785                         i->inactive_enter_timestamp = (usec_t) u;
2786                 else if (streq(name, "InactiveExitTimestamp"))
2787                         i->inactive_exit_timestamp = (usec_t) u;
2788                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2789                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2790                 else if (streq(name, "ActiveExitTimestamp"))
2791                         i->active_exit_timestamp = (usec_t) u;
2792                 else if (streq(name, "ConditionTimestamp"))
2793                         i->condition_timestamp = (usec_t) u;
2794
2795                 break;
2796         }
2797
2798         case DBUS_TYPE_ARRAY: {
2799
2800                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2801                     startswith(name, "Exec")) {
2802                         DBusMessageIter sub;
2803
2804                         dbus_message_iter_recurse(iter, &sub);
2805                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2806                                 ExecStatusInfo *info;
2807                                 int r;
2808
2809                                 if (!(info = new0(ExecStatusInfo, 1)))
2810                                         return -ENOMEM;
2811
2812                                 if (!(info->name = strdup(name))) {
2813                                         free(info);
2814                                         return -ENOMEM;
2815                                 }
2816
2817                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2818                                         free(info);
2819                                         return r;
2820                                 }
2821
2822                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2823
2824                                 dbus_message_iter_next(&sub);
2825                         }
2826                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2827                            streq(name, "Documentation")) {
2828
2829                         DBusMessageIter sub;
2830
2831                         dbus_message_iter_recurse(iter, &sub);
2832                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2833                                 const char *s;
2834                                 char **l;
2835
2836                                 dbus_message_iter_get_basic(&sub, &s);
2837
2838                                 l = strv_append(i->documentation, s);
2839                                 if (!l)
2840                                         return -ENOMEM;
2841
2842                                 strv_free(i->documentation);
2843                                 i->documentation = l;
2844
2845                                 dbus_message_iter_next(&sub);
2846                         }
2847                 }
2848
2849                 break;
2850         }
2851
2852         case DBUS_TYPE_STRUCT: {
2853
2854                 if (streq(name, "LoadError")) {
2855                         DBusMessageIter sub;
2856                         const char *n, *message;
2857                         int r;
2858
2859                         dbus_message_iter_recurse(iter, &sub);
2860
2861                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2862                         if (r < 0)
2863                                 return r;
2864
2865                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2866                         if (r < 0)
2867                                 return r;
2868
2869                         if (!isempty(message))
2870                                 i->load_error = message;
2871                 }
2872
2873                 break;
2874         }
2875         }
2876
2877         return 0;
2878 }
2879
2880 static int print_property(const char *name, DBusMessageIter *iter) {
2881         assert(name);
2882         assert(iter);
2883
2884         /* This is a low-level property printer, see
2885          * print_status_info() for the nicer output */
2886
2887         if (arg_property && !strv_find(arg_property, name))
2888                 return 0;
2889
2890         switch (dbus_message_iter_get_arg_type(iter)) {
2891
2892         case DBUS_TYPE_STRUCT: {
2893                 DBusMessageIter sub;
2894                 dbus_message_iter_recurse(iter, &sub);
2895
2896                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2897                         uint32_t u;
2898
2899                         dbus_message_iter_get_basic(&sub, &u);
2900
2901                         if (u)
2902                                 printf("%s=%u\n", name, (unsigned) u);
2903                         else if (arg_all)
2904                                 printf("%s=\n", name);
2905
2906                         return 0;
2907                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2908                         const char *s;
2909
2910                         dbus_message_iter_get_basic(&sub, &s);
2911
2912                         if (arg_all || s[0])
2913                                 printf("%s=%s\n", name, s);
2914
2915                         return 0;
2916                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2917                         const char *a = NULL, *b = NULL;
2918
2919                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2920                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2921
2922                         if (arg_all || !isempty(a) || !isempty(b))
2923                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2924
2925                         return 0;
2926                 }
2927
2928                 break;
2929         }
2930
2931         case DBUS_TYPE_ARRAY:
2932
2933                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2934                         DBusMessageIter sub, sub2;
2935
2936                         dbus_message_iter_recurse(iter, &sub);
2937                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2938                                 const char *path;
2939                                 dbus_bool_t ignore;
2940
2941                                 dbus_message_iter_recurse(&sub, &sub2);
2942
2943                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2944                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2945                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2946
2947                                 dbus_message_iter_next(&sub);
2948                         }
2949
2950                         return 0;
2951
2952                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2953                         DBusMessageIter sub, sub2;
2954
2955                         dbus_message_iter_recurse(iter, &sub);
2956                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2957                                 const char *type, *path;
2958
2959                                 dbus_message_iter_recurse(&sub, &sub2);
2960
2961                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2962                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2963                                         printf("%s=%s\n", type, path);
2964
2965                                 dbus_message_iter_next(&sub);
2966                         }
2967
2968                         return 0;
2969
2970                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2971                         DBusMessageIter sub, sub2;
2972
2973                         dbus_message_iter_recurse(iter, &sub);
2974                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2975                                 const char *base;
2976                                 uint64_t value, next_elapse;
2977
2978                                 dbus_message_iter_recurse(&sub, &sub2);
2979
2980                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2981                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2982                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2983                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2984
2985                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2986                                                base,
2987                                                format_timespan(timespan1, sizeof(timespan1), value),
2988                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2989                                 }
2990
2991                                 dbus_message_iter_next(&sub);
2992                         }
2993
2994                         return 0;
2995
2996                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2997                         DBusMessageIter sub, sub2;
2998
2999                         dbus_message_iter_recurse(iter, &sub);
3000                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3001                                 const char *controller, *attr, *value;
3002
3003                                 dbus_message_iter_recurse(&sub, &sub2);
3004
3005                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
3006                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
3007                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
3008
3009                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
3010                                                controller,
3011                                                attr,
3012                                                value);
3013                                 }
3014
3015                                 dbus_message_iter_next(&sub);
3016                         }
3017
3018                         return 0;
3019
3020                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3021                         DBusMessageIter sub;
3022
3023                         dbus_message_iter_recurse(iter, &sub);
3024                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3025                                 ExecStatusInfo info;
3026
3027                                 zero(info);
3028                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3029                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3030                                         char *t;
3031
3032                                         t = strv_join(info.argv, " ");
3033
3034                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3035                                                name,
3036                                                strna(info.path),
3037                                                strna(t),
3038                                                yes_no(info.ignore),
3039                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3040                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3041                                                (unsigned) info. pid,
3042                                                sigchld_code_to_string(info.code),
3043                                                info.status,
3044                                                info.code == CLD_EXITED ? "" : "/",
3045                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3046
3047                                         free(t);
3048                                 }
3049
3050                                 free(info.path);
3051                                 strv_free(info.argv);
3052
3053                                 dbus_message_iter_next(&sub);
3054                         }
3055
3056                         return 0;
3057                 }
3058
3059                 break;
3060         }
3061
3062         if (generic_print_property(name, iter, arg_all) > 0)
3063                 return 0;
3064
3065         if (arg_all)
3066                 printf("%s=[unprintable]\n", name);
3067
3068         return 0;
3069 }
3070
3071 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3072         DBusMessage *m = NULL, *reply = NULL;
3073         const char *interface = "";
3074         int r;
3075         DBusError error;
3076         DBusMessageIter iter, sub, sub2, sub3;
3077         UnitStatusInfo info;
3078         ExecStatusInfo *p;
3079
3080         assert(bus);
3081         assert(path);
3082         assert(new_line);
3083
3084         zero(info);
3085         dbus_error_init(&error);
3086
3087         if (!(m = dbus_message_new_method_call(
3088                               "org.freedesktop.systemd1",
3089                               path,
3090                               "org.freedesktop.DBus.Properties",
3091                               "GetAll"))) {
3092                 log_error("Could not allocate message.");
3093                 r = -ENOMEM;
3094                 goto finish;
3095         }
3096
3097         if (!dbus_message_append_args(m,
3098                                       DBUS_TYPE_STRING, &interface,
3099                                       DBUS_TYPE_INVALID)) {
3100                 log_error("Could not append arguments to message.");
3101                 r = -ENOMEM;
3102                 goto finish;
3103         }
3104
3105         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3106                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3107                 r = -EIO;
3108                 goto finish;
3109         }
3110
3111         if (!dbus_message_iter_init(reply, &iter) ||
3112             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3113             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3114                 log_error("Failed to parse reply.");
3115                 r = -EIO;
3116                 goto finish;
3117         }
3118
3119         dbus_message_iter_recurse(&iter, &sub);
3120
3121         if (*new_line)
3122                 printf("\n");
3123
3124         *new_line = true;
3125
3126         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3127                 const char *name;
3128
3129                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
3130                         log_error("Failed to parse reply.");
3131                         r = -EIO;
3132                         goto finish;
3133                 }
3134
3135                 dbus_message_iter_recurse(&sub, &sub2);
3136
3137                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
3138                         log_error("Failed to parse reply.");
3139                         r = -EIO;
3140                         goto finish;
3141                 }
3142
3143                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
3144                         log_error("Failed to parse reply.");
3145                         r = -EIO;
3146                         goto finish;
3147                 }
3148
3149                 dbus_message_iter_recurse(&sub2, &sub3);
3150
3151                 if (show_properties)
3152                         r = print_property(name, &sub3);
3153                 else
3154                         r = status_property(name, &sub3, &info);
3155
3156                 if (r < 0) {
3157                         log_error("Failed to parse reply.");
3158                         r = -EIO;
3159                         goto finish;
3160                 }
3161
3162                 dbus_message_iter_next(&sub);
3163         }
3164
3165         r = 0;
3166
3167         if (!show_properties) {
3168                 if (streq(verb, "help"))
3169                         show_unit_help(&info);
3170                 else
3171                         print_status_info(&info);
3172         }
3173
3174         strv_free(info.documentation);
3175
3176         if (!streq_ptr(info.active_state, "active") &&
3177             !streq_ptr(info.active_state, "reloading") &&
3178             streq(verb, "status"))
3179                 /* According to LSB: "program not running" */
3180                 r = 3;
3181
3182         while ((p = info.exec)) {
3183                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3184                 exec_status_info_free(p);
3185         }
3186
3187 finish:
3188         if (m)
3189                 dbus_message_unref(m);
3190
3191         if (reply)
3192                 dbus_message_unref(reply);
3193
3194         dbus_error_free(&error);
3195
3196         return r;
3197 }
3198
3199 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3200         DBusMessage *m = NULL, *reply = NULL;
3201         const char *path = NULL;
3202         DBusError error;
3203         int r;
3204
3205         dbus_error_init(&error);
3206
3207         m = dbus_message_new_method_call(
3208                               "org.freedesktop.systemd1",
3209                               "/org/freedesktop/systemd1",
3210                               "org.freedesktop.systemd1.Manager",
3211                               "GetUnitByPID");
3212         if (!m) {
3213                 log_error("Could not allocate message.");
3214                 r = -ENOMEM;
3215                 goto finish;
3216         }
3217
3218         if (!dbus_message_append_args(m,
3219                                       DBUS_TYPE_UINT32, &pid,
3220                                       DBUS_TYPE_INVALID)) {
3221                 log_error("Could not append arguments to message.");
3222                 r = -ENOMEM;
3223                 goto finish;
3224         }
3225
3226         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3227         if (!reply) {
3228                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3229                 r = -EIO;
3230                 goto finish;
3231         }
3232
3233         if (!dbus_message_get_args(reply, &error,
3234                                    DBUS_TYPE_OBJECT_PATH, &path,
3235                                    DBUS_TYPE_INVALID)) {
3236                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3237                 r = -EIO;
3238                 goto finish;
3239         }
3240
3241         r = show_one(verb, bus, path, false, new_line);
3242
3243 finish:
3244         if (m)
3245                 dbus_message_unref(m);
3246
3247         if (reply)
3248                 dbus_message_unref(reply);
3249
3250         dbus_error_free(&error);
3251
3252         return r;
3253 }
3254
3255 static int show(DBusConnection *bus, char **args) {
3256         int r, ret = 0;
3257         bool show_properties, new_line = false;
3258         char **name;
3259
3260         assert(bus);
3261         assert(args);
3262
3263         show_properties = streq(args[0], "show");
3264
3265         if (show_properties)
3266                 pager_open_if_enabled();
3267
3268         if (show_properties && strv_length(args) <= 1) {
3269                 /* If not argument is specified inspect the manager
3270                  * itself */
3271
3272                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3273         }
3274
3275         STRV_FOREACH(name, args+1) {
3276                 uint32_t id;
3277
3278                 if (safe_atou32(*name, &id) < 0) {
3279                         char *p, *n;
3280                         /* Interpret as unit name */
3281
3282                         n = unit_name_mangle(*name);
3283                         p = unit_dbus_path_from_name(n ? n : *name);
3284                         free(n);
3285                         if (!p) {
3286                                 log_error("Out of memory");
3287                                 return -ENOMEM;
3288                         }
3289
3290                         r = show_one(args[0], bus, p, show_properties, &new_line);
3291                         free(p);
3292
3293                         if (r != 0)
3294                                 ret = r;
3295
3296                 } else if (show_properties) {
3297
3298                         /* Interpret as job id */
3299
3300                         char *p;
3301                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) {
3302                                 log_error("Out of memory");
3303                                 return -ENOMEM;
3304                         }
3305
3306                         r = show_one(args[0], bus, p, show_properties, &new_line);
3307                         free(p);
3308
3309                         if (r != 0)
3310                                 ret = r;
3311
3312                 } else {
3313
3314                         /* Interpret as PID */
3315
3316                         r = show_one_by_pid(args[0], bus, id, &new_line);
3317                         if (r != 0)
3318                                 ret = r;
3319                 }
3320         }
3321
3322         return ret;
3323 }
3324
3325 static int dump(DBusConnection *bus, char **args) {
3326         DBusMessage *m = NULL, *reply = NULL;
3327         DBusError error;
3328         int r;
3329         const char *text;
3330
3331         dbus_error_init(&error);
3332
3333         pager_open_if_enabled();
3334
3335         if (!(m = dbus_message_new_method_call(
3336                               "org.freedesktop.systemd1",
3337                               "/org/freedesktop/systemd1",
3338                               "org.freedesktop.systemd1.Manager",
3339                               "Dump"))) {
3340                 log_error("Could not allocate message.");
3341                 return -ENOMEM;
3342         }
3343
3344         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3345                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3346                 r = -EIO;
3347                 goto finish;
3348         }
3349
3350         if (!dbus_message_get_args(reply, &error,
3351                                    DBUS_TYPE_STRING, &text,
3352                                    DBUS_TYPE_INVALID)) {
3353                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3354                 r = -EIO;
3355                 goto finish;
3356         }
3357
3358         fputs(text, stdout);
3359
3360         r = 0;
3361
3362 finish:
3363         if (m)
3364                 dbus_message_unref(m);
3365
3366         if (reply)
3367                 dbus_message_unref(reply);
3368
3369         dbus_error_free(&error);
3370
3371         return r;
3372 }
3373
3374 static int snapshot(DBusConnection *bus, char **args) {
3375         DBusMessage *m = NULL, *reply = NULL;
3376         DBusError error;
3377         int r;
3378         const char *name = "", *path, *id;
3379         dbus_bool_t cleanup = FALSE;
3380         DBusMessageIter iter, sub;
3381         const char
3382                 *interface = "org.freedesktop.systemd1.Unit",
3383                 *property = "Id";
3384         char *n;
3385         bool b;
3386
3387         dbus_error_init(&error);
3388
3389         m = dbus_message_new_method_call(
3390                         "org.freedesktop.systemd1",
3391                         "/org/freedesktop/systemd1",
3392                         "org.freedesktop.systemd1.Manager",
3393                         "CreateSnapshot");
3394         if (!m) {
3395                 log_error("Could not allocate message.");
3396                 return -ENOMEM;
3397         }
3398
3399         if (strv_length(args) > 1)
3400                 name = args[1];
3401
3402         n = unit_name_mangle(name);
3403         b = dbus_message_append_args(m,
3404                                      DBUS_TYPE_STRING, n ? (const char**) &n : &name,
3405                                      DBUS_TYPE_BOOLEAN, &cleanup,
3406                                      DBUS_TYPE_INVALID);
3407         free(n);
3408         if (!b) {
3409                 log_error("Could not append arguments to message.");
3410                 r = -ENOMEM;
3411                 goto finish;
3412         }
3413
3414         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3415         if (!reply) {
3416                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3417                 r = -EIO;
3418                 goto finish;
3419         }
3420
3421         if (!dbus_message_get_args(reply, &error,
3422                                    DBUS_TYPE_OBJECT_PATH, &path,
3423                                    DBUS_TYPE_INVALID)) {
3424                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3425                 r = -EIO;
3426                 goto finish;
3427         }
3428
3429         dbus_message_unref(m);
3430         m = dbus_message_new_method_call(
3431                               "org.freedesktop.systemd1",
3432                               path,
3433                               "org.freedesktop.DBus.Properties",
3434                               "Get");
3435         if (!m) {
3436                 log_error("Could not allocate message.");
3437                 return -ENOMEM;
3438         }
3439
3440         if (!dbus_message_append_args(m,
3441                                       DBUS_TYPE_STRING, &interface,
3442                                       DBUS_TYPE_STRING, &property,
3443                                       DBUS_TYPE_INVALID)) {
3444                 log_error("Could not append arguments to message.");
3445                 r = -ENOMEM;
3446                 goto finish;
3447         }
3448
3449         dbus_message_unref(reply);
3450         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3451         if (!reply) {
3452                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3453                 r = -EIO;
3454                 goto finish;
3455         }
3456
3457         if (!dbus_message_iter_init(reply, &iter) ||
3458             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3459                 log_error("Failed to parse reply.");
3460                 r = -EIO;
3461                 goto finish;
3462         }
3463
3464         dbus_message_iter_recurse(&iter, &sub);
3465
3466         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3467                 log_error("Failed to parse reply.");
3468                 r = -EIO;
3469                 goto finish;
3470         }
3471
3472         dbus_message_iter_get_basic(&sub, &id);
3473
3474         if (!arg_quiet)
3475                 puts(id);
3476         r = 0;
3477
3478 finish:
3479         if (m)
3480                 dbus_message_unref(m);
3481
3482         if (reply)
3483                 dbus_message_unref(reply);
3484
3485         dbus_error_free(&error);
3486
3487         return r;
3488 }
3489
3490 static int delete_snapshot(DBusConnection *bus, char **args) {
3491         DBusMessage *m = NULL, *reply = NULL;
3492         int r;
3493         DBusError error;
3494         char **name;
3495
3496         assert(bus);
3497         assert(args);
3498
3499         dbus_error_init(&error);
3500
3501         STRV_FOREACH(name, args+1) {
3502                 const char *path = NULL;
3503                 char *n;
3504                 bool b;
3505
3506                 m = dbus_message_new_method_call(
3507                                 "org.freedesktop.systemd1",
3508                                 "/org/freedesktop/systemd1",
3509                                 "org.freedesktop.systemd1.Manager",
3510                                 "GetUnit");
3511                 if (!m) {
3512                         log_error("Could not allocate message.");
3513                         r = -ENOMEM;
3514                         goto finish;
3515                 }
3516
3517                 n = unit_name_mangle(*name);
3518                 b = dbus_message_append_args(m,
3519                                              DBUS_TYPE_STRING, n ? &n : name,
3520                                              DBUS_TYPE_INVALID);
3521                 free(n);
3522                 if (!b) {
3523                         log_error("Could not append arguments to message.");
3524                         r = -ENOMEM;
3525                         goto finish;
3526                 }
3527
3528                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3529                 if (!reply) {
3530                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3531                         r = -EIO;
3532                         goto finish;
3533                 }
3534
3535                 if (!dbus_message_get_args(reply, &error,
3536                                            DBUS_TYPE_OBJECT_PATH, &path,
3537                                            DBUS_TYPE_INVALID)) {
3538                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3539                         r = -EIO;
3540                         goto finish;
3541                 }
3542
3543                 dbus_message_unref(m);
3544                 m = dbus_message_new_method_call(
3545                                 "org.freedesktop.systemd1",
3546                                 path,
3547                                 "org.freedesktop.systemd1.Snapshot",
3548                                 "Remove");
3549                 if (!m) {
3550                         log_error("Could not allocate message.");
3551                         r = -ENOMEM;
3552                         goto finish;
3553                 }
3554
3555                 dbus_message_unref(reply);
3556                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3557                 if (!reply) {
3558                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3559                         r = -EIO;
3560                         goto finish;
3561                 }
3562
3563                 dbus_message_unref(m);
3564                 dbus_message_unref(reply);
3565                 m = reply = NULL;
3566         }
3567
3568         r = 0;
3569
3570 finish:
3571         if (m)
3572                 dbus_message_unref(m);
3573
3574         if (reply)
3575                 dbus_message_unref(reply);
3576
3577         dbus_error_free(&error);
3578
3579         return r;
3580 }
3581
3582 static int daemon_reload(DBusConnection *bus, char **args) {
3583         DBusMessage *m = NULL, *reply = NULL;
3584         DBusError error;
3585         int r;
3586         const char *method;
3587
3588         dbus_error_init(&error);
3589
3590         if (arg_action == ACTION_RELOAD)
3591                 method = "Reload";
3592         else if (arg_action == ACTION_REEXEC)
3593                 method = "Reexecute";
3594         else {
3595                 assert(arg_action == ACTION_SYSTEMCTL);
3596
3597                 method =
3598                         streq(args[0], "clear-jobs")    ||
3599                         streq(args[0], "cancel")        ? "ClearJobs" :
3600                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3601                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3602                         streq(args[0], "halt")          ? "Halt" :
3603                         streq(args[0], "poweroff")      ? "PowerOff" :
3604                         streq(args[0], "reboot")        ? "Reboot" :
3605                         streq(args[0], "kexec")         ? "KExec" :
3606                         streq(args[0], "exit")          ? "Exit" :
3607                                     /* "daemon-reload" */ "Reload";
3608         }
3609
3610         if (!(m = dbus_message_new_method_call(
3611                               "org.freedesktop.systemd1",
3612                               "/org/freedesktop/systemd1",
3613                               "org.freedesktop.systemd1.Manager",
3614                               method))) {
3615                 log_error("Could not allocate message.");
3616                 return -ENOMEM;
3617         }
3618
3619         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3620
3621                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3622                         /* There's always a fallback possible for
3623                          * legacy actions. */
3624                         r = -EADDRNOTAVAIL;
3625                         goto finish;
3626                 }
3627
3628                 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3629                         /* On reexecution, we expect a disconnect, not
3630                          * a reply */
3631                         r = 0;
3632                         goto finish;
3633                 }
3634
3635                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3636                 r = -EIO;
3637                 goto finish;
3638         }
3639
3640         r = 0;
3641
3642 finish:
3643         if (m)
3644                 dbus_message_unref(m);
3645
3646         if (reply)
3647                 dbus_message_unref(reply);
3648
3649         dbus_error_free(&error);
3650
3651         return r;
3652 }
3653
3654 static int reset_failed(DBusConnection *bus, char **args) {
3655         DBusMessage *m = NULL;
3656         int r;
3657         DBusError error;
3658         char **name;
3659
3660         assert(bus);
3661         dbus_error_init(&error);
3662
3663         if (strv_length(args) <= 1)
3664                 return daemon_reload(bus, args);
3665
3666         STRV_FOREACH(name, args+1) {
3667                 DBusMessage *reply;
3668                 char *n;
3669                 bool b;
3670
3671                 m = dbus_message_new_method_call(
3672                                 "org.freedesktop.systemd1",
3673                                 "/org/freedesktop/systemd1",
3674                                 "org.freedesktop.systemd1.Manager",
3675                                 "ResetFailedUnit");
3676                 if (!m) {
3677                         log_error("Could not allocate message.");
3678                         r = -ENOMEM;
3679                         goto finish;
3680                 }
3681
3682                 n = unit_name_mangle(*name);
3683                 b = dbus_message_append_args(m,
3684                                              DBUS_TYPE_STRING, n ? &n : name,
3685                                              DBUS_TYPE_INVALID);
3686                 free(n);
3687                 if (!b) {
3688                         log_error("Could not append arguments to message.");
3689                         r = -ENOMEM;
3690                         goto finish;
3691                 }
3692
3693                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3694                 if (!reply) {
3695                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3696                         r = -EIO;
3697                         goto finish;
3698                 }
3699
3700                 dbus_message_unref(m);
3701                 dbus_message_unref(reply);
3702                 m = reply = NULL;
3703         }
3704
3705         r = 0;
3706
3707 finish:
3708         if (m)
3709                 dbus_message_unref(m);
3710
3711         dbus_error_free(&error);
3712
3713         return r;
3714 }
3715
3716 static int show_enviroment(DBusConnection *bus, char **args) {
3717         DBusMessage *m = NULL, *reply = NULL;
3718         DBusError error;
3719         DBusMessageIter iter, sub, sub2;
3720         int r;
3721         const char
3722                 *interface = "org.freedesktop.systemd1.Manager",
3723                 *property = "Environment";
3724
3725         dbus_error_init(&error);
3726
3727         pager_open_if_enabled();
3728
3729         if (!(m = dbus_message_new_method_call(
3730                               "org.freedesktop.systemd1",
3731                               "/org/freedesktop/systemd1",
3732                               "org.freedesktop.DBus.Properties",
3733                               "Get"))) {
3734                 log_error("Could not allocate message.");
3735                 return -ENOMEM;
3736         }
3737
3738         if (!dbus_message_append_args(m,
3739                                       DBUS_TYPE_STRING, &interface,
3740                                       DBUS_TYPE_STRING, &property,
3741                                       DBUS_TYPE_INVALID)) {
3742                 log_error("Could not append arguments to message.");
3743                 r = -ENOMEM;
3744                 goto finish;
3745         }
3746
3747         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3748                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3749                 r = -EIO;
3750                 goto finish;
3751         }
3752
3753         if (!dbus_message_iter_init(reply, &iter) ||
3754             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3755                 log_error("Failed to parse reply.");
3756                 r = -EIO;
3757                 goto finish;
3758         }
3759
3760         dbus_message_iter_recurse(&iter, &sub);
3761
3762         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3763             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3764                 log_error("Failed to parse reply.");
3765                 r = -EIO;
3766                 goto finish;
3767         }
3768
3769         dbus_message_iter_recurse(&sub, &sub2);
3770
3771         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3772                 const char *text;
3773
3774                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3775                         log_error("Failed to parse reply.");
3776                         r = -EIO;
3777                         goto finish;
3778                 }
3779
3780                 dbus_message_iter_get_basic(&sub2, &text);
3781                 printf("%s\n", text);
3782
3783                 dbus_message_iter_next(&sub2);
3784         }
3785
3786         r = 0;
3787
3788 finish:
3789         if (m)
3790                 dbus_message_unref(m);
3791
3792         if (reply)
3793                 dbus_message_unref(reply);
3794
3795         dbus_error_free(&error);
3796
3797         return r;
3798 }
3799
3800 static int switch_root(DBusConnection *bus, char **args) {
3801         DBusMessage *m = NULL, *reply = NULL;
3802         unsigned l;
3803         const char *root, *init;
3804         DBusError error;
3805         int r;
3806
3807         dbus_error_init(&error);
3808
3809         l = strv_length(args);
3810         if (l < 2 || l > 3) {
3811                 log_error("Wrong number of arguments.");
3812                 return -EINVAL;
3813         }
3814
3815         root = args[1];
3816         init = l >= 3 ? args[2] : "";
3817
3818         m = dbus_message_new_method_call(
3819                         "org.freedesktop.systemd1",
3820                         "/org/freedesktop/systemd1",
3821                         "org.freedesktop.systemd1.Manager",
3822                         "SwitchRoot");
3823         if (!m) {
3824                 log_error("Could not allocate message.");
3825                 return -ENOMEM;
3826         }
3827
3828         if (!dbus_message_append_args(
3829                             m,
3830                             DBUS_TYPE_STRING, &root,
3831                             DBUS_TYPE_STRING, &init,
3832                             DBUS_TYPE_INVALID)) {
3833                 log_error("Could not append arguments to message.");
3834                 r = -ENOMEM;
3835                 goto finish;
3836         }
3837
3838         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3839         if (!reply) {
3840                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3841                 r = -EIO;
3842                 goto finish;
3843         }
3844
3845         r = 0;
3846
3847 finish:
3848         if (m)
3849                 dbus_message_unref(m);
3850
3851         if (reply)
3852                 dbus_message_unref(reply);
3853
3854         dbus_error_free(&error);
3855
3856         return r;
3857 }
3858
3859 static int set_environment(DBusConnection *bus, char **args) {
3860         DBusMessage *m = NULL, *reply = NULL;
3861         DBusError error;
3862         int r;
3863         const char *method;
3864         DBusMessageIter iter, sub;
3865         char **name;
3866
3867         dbus_error_init(&error);
3868
3869         method = streq(args[0], "set-environment")
3870                 ? "SetEnvironment"
3871                 : "UnsetEnvironment";
3872
3873         if (!(m = dbus_message_new_method_call(
3874                               "org.freedesktop.systemd1",
3875                               "/org/freedesktop/systemd1",
3876                               "org.freedesktop.systemd1.Manager",
3877                               method))) {
3878
3879                 log_error("Could not allocate message.");
3880                 return -ENOMEM;
3881         }
3882
3883         dbus_message_iter_init_append(m, &iter);
3884
3885         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3886                 log_error("Could not append arguments to message.");
3887                 r = -ENOMEM;
3888                 goto finish;
3889         }
3890
3891         STRV_FOREACH(name, args+1)
3892                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3893                         log_error("Could not append arguments to message.");
3894                         r = -ENOMEM;
3895                         goto finish;
3896                 }
3897
3898         if (!dbus_message_iter_close_container(&iter, &sub)) {
3899                 log_error("Could not append arguments to message.");
3900                 r = -ENOMEM;
3901                 goto finish;
3902         }
3903
3904         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3905                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3906                 r = -EIO;
3907                 goto finish;
3908         }
3909
3910         r = 0;
3911
3912 finish:
3913         if (m)
3914                 dbus_message_unref(m);
3915
3916         if (reply)
3917                 dbus_message_unref(reply);
3918
3919         dbus_error_free(&error);
3920
3921         return r;
3922 }
3923
3924 static int enable_sysv_units(char **args) {
3925         int r = 0;
3926
3927 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3928         const char *verb = args[0];
3929         unsigned f = 1, t = 1;
3930         LookupPaths paths;
3931
3932         if (arg_scope != UNIT_FILE_SYSTEM)
3933                 return 0;
3934
3935         if (!streq(verb, "enable") &&
3936             !streq(verb, "disable") &&
3937             !streq(verb, "is-enabled"))
3938                 return 0;
3939
3940         /* Processes all SysV units, and reshuffles the array so that
3941          * afterwards only the native units remain */
3942
3943         zero(paths);
3944         r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
3945         if (r < 0)
3946                 return r;
3947
3948         r = 0;
3949         for (f = 1; args[f]; f++) {
3950                 const char *name;
3951                 char *p;
3952                 bool found_native = false, found_sysv;
3953                 unsigned c = 1;
3954                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3955                 char **k, *l, *q = NULL;
3956                 int j;
3957                 pid_t pid;
3958                 siginfo_t status;
3959
3960                 name = args[f];
3961
3962                 if (!endswith(name, ".service"))
3963                         continue;
3964
3965                 if (path_is_absolute(name))
3966                         continue;
3967
3968                 STRV_FOREACH(k, paths.unit_path) {
3969                         p = NULL;
3970
3971                         if (!isempty(arg_root))
3972                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3973                         else
3974                                 asprintf(&p, "%s/%s", *k, name);
3975
3976                         if (!p) {
3977                                 log_error("No memory");
3978                                 r = -ENOMEM;
3979                                 goto finish;
3980                         }
3981
3982                         found_native = access(p, F_OK) >= 0;
3983                         free(p);
3984
3985                         if (found_native)
3986                                 break;
3987                 }
3988
3989                 if (found_native)
3990                         continue;
3991
3992                 p = NULL;
3993                 if (!isempty(arg_root))
3994                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3995                 else
3996                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3997                 if (!p) {
3998                         log_error("No memory");
3999                         r = -ENOMEM;
4000                         goto finish;
4001                 }
4002
4003                 p[strlen(p) - sizeof(".service") + 1] = 0;
4004                 found_sysv = access(p, F_OK) >= 0;
4005
4006                 if (!found_sysv) {
4007                         free(p);
4008                         continue;
4009                 }
4010
4011                 /* Mark this entry, so that we don't try enabling it as native unit */
4012                 args[f] = (char*) "";
4013
4014                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
4015
4016                 if (!isempty(arg_root))
4017                         argv[c++] = q = strappend("--root=", arg_root);
4018
4019                 argv[c++] = path_get_file_name(p);
4020                 argv[c++] =
4021                         streq(verb, "enable") ? "on" :
4022                         streq(verb, "disable") ? "off" : "--level=5";
4023                 argv[c] = NULL;
4024
4025                 l = strv_join((char**)argv, " ");
4026                 if (!l) {
4027                         log_error("No memory.");
4028                         free(q);
4029                         free(p);
4030                         r = -ENOMEM;
4031                         goto finish;
4032                 }
4033
4034                 log_info("Executing %s", l);
4035                 free(l);
4036
4037                 pid = fork();
4038                 if (pid < 0) {
4039                         log_error("Failed to fork: %m");
4040                         free(p);
4041                         free(q);
4042                         r = -errno;
4043                         goto finish;
4044                 } else if (pid == 0) {
4045                         /* Child */
4046
4047                         execv(argv[0], (char**) argv);
4048                         _exit(EXIT_FAILURE);
4049                 }
4050
4051                 free(p);
4052                 free(q);
4053
4054                 j = wait_for_terminate(pid, &status);
4055                 if (j < 0) {
4056                         log_error("Failed to wait for child: %s", strerror(-r));
4057                         r = j;
4058                         goto finish;
4059                 }
4060
4061                 if (status.si_code == CLD_EXITED) {
4062                         if (streq(verb, "is-enabled")) {
4063                                 if (status.si_status == 0) {
4064                                         if (!arg_quiet)
4065                                                 puts("enabled");
4066                                         r = 1;
4067                                 } else {
4068                                         if (!arg_quiet)
4069                                                 puts("disabled");
4070                                 }
4071
4072                         } else if (status.si_status != 0) {
4073                                 r = -EINVAL;
4074                                 goto finish;
4075                         }
4076                 } else {
4077                         r = -EPROTO;
4078                         goto finish;
4079                 }
4080         }
4081
4082 finish:
4083         lookup_paths_free(&paths);
4084
4085         /* Drop all SysV units */
4086         for (f = 1, t = 1; args[f]; f++) {
4087
4088                 if (isempty(args[f]))
4089                         continue;
4090
4091                 args[t++] = args[f];
4092         }
4093
4094         args[t] = NULL;
4095
4096 #endif
4097         return r;
4098 }
4099
4100 static int enable_unit(DBusConnection *bus, char **args) {
4101         const char *verb = args[0];
4102         UnitFileChange *changes = NULL;
4103         unsigned n_changes = 0, i;
4104         int carries_install_info = -1;
4105         DBusMessage *m = NULL, *reply = NULL;
4106         int r;
4107         DBusError error;
4108
4109         r = enable_sysv_units(args);
4110         if (r < 0)
4111                 return r;
4112
4113         if (!args[1])
4114                 return 0;
4115
4116         dbus_error_init(&error);
4117
4118         if (!bus || avoid_bus()) {
4119                 if (streq(verb, "enable")) {
4120                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4121                         carries_install_info = r;
4122                 } else if (streq(verb, "disable"))
4123                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4124                 else if (streq(verb, "reenable")) {
4125                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4126                         carries_install_info = r;
4127                 } else if (streq(verb, "link"))
4128                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4129                 else if (streq(verb, "preset")) {
4130                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4131                         carries_install_info = r;
4132                 } else if (streq(verb, "mask"))
4133                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4134                 else if (streq(verb, "unmask"))
4135                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4136                 else
4137                         assert_not_reached("Unknown verb");
4138
4139                 if (r < 0) {
4140                         log_error("Operation failed: %s", strerror(-r));
4141                         goto finish;
4142                 }
4143
4144                 if (!arg_quiet) {
4145                         for (i = 0; i < n_changes; i++) {
4146                                 if (changes[i].type == UNIT_FILE_SYMLINK)
4147                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4148                                 else
4149                                         log_info("rm '%s'", changes[i].path);
4150                         }
4151                 }
4152
4153         } else {
4154                 const char *method;
4155                 bool send_force = true, expect_carries_install_info = false;
4156                 dbus_bool_t a, b;
4157                 DBusMessageIter iter, sub, sub2;
4158
4159                 if (streq(verb, "enable")) {
4160                         method = "EnableUnitFiles";
4161                         expect_carries_install_info = true;
4162                 } else if (streq(verb, "disable")) {
4163                         method = "DisableUnitFiles";
4164                         send_force = false;
4165                 } else if (streq(verb, "reenable")) {
4166                         method = "ReenableUnitFiles";
4167                         expect_carries_install_info = true;
4168                 } else if (streq(verb, "link"))
4169                         method = "LinkUnitFiles";
4170                 else if (streq(verb, "preset")) {
4171                         method = "PresetUnitFiles";
4172                         expect_carries_install_info = true;
4173                 } else if (streq(verb, "mask"))
4174                         method = "MaskUnitFiles";
4175                 else if (streq(verb, "unmask")) {
4176                         method = "UnmaskUnitFiles";
4177                         send_force = false;
4178                 } else
4179                         assert_not_reached("Unknown verb");
4180
4181                 m = dbus_message_new_method_call(
4182                                 "org.freedesktop.systemd1",
4183                                 "/org/freedesktop/systemd1",
4184                                 "org.freedesktop.systemd1.Manager",
4185                                 method);
4186                 if (!m) {
4187                         log_error("Out of memory");
4188                         r = -ENOMEM;
4189                         goto finish;
4190                 }
4191
4192                 dbus_message_iter_init_append(m, &iter);
4193
4194                 r = bus_append_strv_iter(&iter, args+1);
4195                 if (r < 0) {
4196                         log_error("Failed to append unit files.");
4197                         goto finish;
4198                 }
4199
4200                 a = arg_runtime;
4201                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4202                         log_error("Failed to append runtime boolean.");
4203                         r = -ENOMEM;
4204                         goto finish;
4205                 }
4206
4207                 if (send_force) {
4208                         b = arg_force;
4209
4210                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4211                                 log_error("Failed to append force boolean.");
4212                                 r = -ENOMEM;
4213                                 goto finish;
4214                         }
4215                 }
4216
4217                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4218                 if (!reply) {
4219                         log_error("Failed to issue method call: %s", bus_error_message(&error));
4220                         r = -EIO;
4221                         goto finish;
4222                 }
4223
4224                 if (!dbus_message_iter_init(reply, &iter)) {
4225                         log_error("Failed to initialize iterator.");
4226                         goto finish;
4227                 }
4228
4229                 if (expect_carries_install_info) {
4230                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4231                         if (r < 0) {
4232                                 log_error("Failed to parse reply.");
4233                                 goto finish;
4234                         }
4235
4236                         carries_install_info = b;
4237                 }
4238
4239                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4240                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4241                         log_error("Failed to parse reply.");
4242                         r = -EIO;
4243                         goto finish;
4244                 }
4245
4246                 dbus_message_iter_recurse(&iter, &sub);
4247                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4248                         const char *type, *path, *source;
4249
4250                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4251                                 log_error("Failed to parse reply.");
4252                                 r = -EIO;
4253                                 goto finish;
4254                         }
4255
4256                         dbus_message_iter_recurse(&sub, &sub2);
4257
4258                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4259                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4260                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4261                                 log_error("Failed to parse reply.");
4262                                 r = -EIO;
4263                                 goto finish;
4264                         }
4265
4266                         if (!arg_quiet) {
4267                                 if (streq(type, "symlink"))
4268                                         log_info("ln -s '%s' '%s'", source, path);
4269                                 else
4270                                         log_info("rm '%s'", path);
4271                         }
4272
4273                         dbus_message_iter_next(&sub);
4274                 }
4275
4276                 /* Try to reload if enabeld */
4277                 if (!arg_no_reload)
4278                         r = daemon_reload(bus, args);
4279         }
4280
4281         if (carries_install_info == 0)
4282                 log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
4283
4284 finish:
4285         if (m)
4286                 dbus_message_unref(m);
4287
4288         if (reply)
4289                 dbus_message_unref(reply);
4290
4291         unit_file_changes_free(changes, n_changes);
4292
4293         dbus_error_free(&error);
4294         return r;
4295 }
4296
4297 static int unit_is_enabled(DBusConnection *bus, char **args) {
4298         DBusError error;
4299         int r;
4300         DBusMessage *m = NULL, *reply = NULL;
4301         bool enabled;
4302         char **name;
4303
4304         dbus_error_init(&error);
4305
4306         r = enable_sysv_units(args);
4307         if (r < 0)
4308                 return r;
4309
4310         enabled = r > 0;
4311
4312         if (!bus || avoid_bus()) {
4313
4314                 STRV_FOREACH(name, args+1) {
4315                         UnitFileState state;
4316
4317                         state = unit_file_get_state(arg_scope, arg_root, *name);
4318                         if (state < 0) {
4319                                 r = state;
4320                                 goto finish;
4321                         }
4322
4323                         if (state == UNIT_FILE_ENABLED ||
4324                             state == UNIT_FILE_ENABLED_RUNTIME ||
4325                             state == UNIT_FILE_STATIC)
4326                                 enabled = true;
4327
4328                         if (!arg_quiet)
4329                                 puts(unit_file_state_to_string(state));
4330                 }
4331
4332         } else {
4333                 STRV_FOREACH(name, args+1) {
4334                         const char *s;
4335
4336                         m = dbus_message_new_method_call(
4337                                         "org.freedesktop.systemd1",
4338                                         "/org/freedesktop/systemd1",
4339                                         "org.freedesktop.systemd1.Manager",
4340                                         "GetUnitFileState");
4341                         if (!m) {
4342                                 log_error("Out of memory");
4343                                 r = -ENOMEM;
4344                                 goto finish;
4345                         }
4346
4347                         if (!dbus_message_append_args(m,
4348                                                       DBUS_TYPE_STRING, name,
4349                                                       DBUS_TYPE_INVALID)) {
4350                                 log_error("Could not append arguments to message.");
4351                                 r = -ENOMEM;
4352                                 goto finish;
4353                         }
4354
4355                         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4356                         if (!reply) {
4357                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4358                                 r = -EIO;
4359                                 goto finish;
4360                         }
4361
4362                         if (!dbus_message_get_args(reply, &error,
4363                                                    DBUS_TYPE_STRING, &s,
4364                                                    DBUS_TYPE_INVALID)) {
4365                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4366                                 r = -EIO;
4367                                 goto finish;
4368                         }
4369
4370                         dbus_message_unref(m);
4371                         dbus_message_unref(reply);
4372                         m = reply = NULL;
4373
4374                         if (streq(s, "enabled") ||
4375                             streq(s, "enabled-runtime") ||
4376                             streq(s, "static"))
4377                                 enabled = true;
4378
4379                         if (!arg_quiet)
4380                                 puts(s);
4381                 }
4382         }
4383
4384         r = enabled ? 0 : 1;
4385
4386 finish:
4387         if (m)
4388                 dbus_message_unref(m);
4389
4390         if (reply)
4391                 dbus_message_unref(reply);
4392
4393         dbus_error_free(&error);
4394         return r;
4395 }
4396
4397 static int systemctl_help(void) {
4398
4399         pager_open_if_enabled();
4400
4401         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4402                "Query or send control commands to the systemd manager.\n\n"
4403                "  -h --help           Show this help\n"
4404                "     --version        Show package version\n"
4405                "  -t --type=TYPE      List only units of a particular type\n"
4406                "  -p --property=NAME  Show only properties by this name\n"
4407                "  -a --all            Show all units/properties, including dead/empty ones\n"
4408                "     --failed         Show only failed units\n"
4409                "     --full           Don't ellipsize unit names on output\n"
4410                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4411                "                      pending\n"
4412                "     --ignore-dependencies\n"
4413                "                      When queueing a new job, ignore all its dependencies\n"
4414                "     --kill-who=WHO   Who to send signal to\n"
4415                "  -s --signal=SIGNAL  Which signal to send\n"
4416                "  -H --host=[USER@]HOST\n"
4417                "                      Show information for remote host\n"
4418                "  -P --privileged     Acquire privileges before execution\n"
4419                "  -q --quiet          Suppress output\n"
4420                "     --no-block       Do not wait until operation finished\n"
4421                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4422                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4423                "                      configuration\n"
4424                "     --no-legend      Do not print a legend (column headers and hints)\n"
4425                "     --no-pager       Do not pipe output into a pager\n"
4426                "     --no-ask-password\n"
4427                "                      Do not ask for system passwords\n"
4428                "     --order          When generating graph for dot, show only order\n"
4429                "     --require        When generating graph for dot, show only requirement\n"
4430                "     --system         Connect to system manager\n"
4431                "     --user           Connect to user service manager\n"
4432                "     --global         Enable/disable unit files globally\n"
4433                "  -f --force          When enabling unit files, override existing symlinks\n"
4434                "                      When shutting down, execute action immediately\n"
4435                "     --root=PATH      Enable unit files in the specified root directory\n"
4436                "     --runtime        Enable unit files only temporarily until next reboot\n"
4437                "  -n --lines=INTEGER  Journal entries to show\n"
4438                "     --follow         Follow journal\n"
4439                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4440                "                      verbose, export, json, cat)\n\n"
4441                "Unit Commands:\n"
4442                "  list-units                      List loaded units\n"
4443                "  start [NAME...]                 Start (activate) one or more units\n"
4444                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4445                "  reload [NAME...]                Reload one or more units\n"
4446                "  restart [NAME...]               Start or restart one or more units\n"
4447                "  try-restart [NAME...]           Restart one or more units if active\n"
4448                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
4449                "                                  otherwise start or restart\n"
4450                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4451                "                                  otherwise restart if active\n"
4452                "  isolate [NAME]                  Start one unit and stop all others\n"
4453                "  kill [NAME...]                  Send signal to processes of a unit\n"
4454                "  is-active [NAME...]             Check whether units are active\n"
4455                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4456                "  show [NAME...|JOB...]           Show properties of one or more\n"
4457                "                                  units/jobs or the manager\n"
4458                "  help [NAME...|PID...]            Show manual for one or more units\n"
4459                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4460                "                                  units\n"
4461                "  load [NAME...]                  Load one or more units\n\n"
4462                "Unit File Commands:\n"
4463                "  list-unit-files                 List installed unit files\n"
4464                "  enable [NAME...]                Enable one or more unit files\n"
4465                "  disable [NAME...]               Disable one or more unit files\n"
4466                "  reenable [NAME...]              Reenable one or more unit files\n"
4467                "  preset [NAME...]                Enable/disable one or more unit files\n"
4468                "                                  based on preset configuration\n"
4469                "  mask [NAME...]                  Mask one or more units\n"
4470                "  unmask [NAME...]                Unmask one or more units\n"
4471                "  link [PATH...]                  Link one or more units files into\n"
4472                "                                  the search path\n"
4473                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4474                "Job Commands:\n"
4475                "  list-jobs                       List jobs\n"
4476                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4477                "Status Commands:\n"
4478                "  dump                            Dump server status\n"
4479                "  dot                             Dump dependency graph for dot(1)\n\n"
4480                "Snapshot Commands:\n"
4481                "  snapshot [NAME]                 Create a snapshot\n"
4482                "  delete [NAME...]                Remove one or more snapshots\n\n"
4483                "Environment Commands:\n"
4484                "  show-environment                Dump environment\n"
4485                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4486                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4487                "Manager Lifecycle Commands:\n"
4488                "  daemon-reload                   Reload systemd manager configuration\n"
4489                "  daemon-reexec                   Reexecute systemd manager\n\n"
4490                "System Commands:\n"
4491                "  default                         Enter system default mode\n"
4492                "  rescue                          Enter system rescue mode\n"
4493                "  emergency                       Enter system emergency mode\n"
4494                "  halt                            Shut down and halt the system\n"
4495                "  poweroff                        Shut down and power-off the system\n"
4496                "  reboot                          Shut down and reboot the system\n"
4497                "  kexec                           Shut down and reboot the system with kexec\n"
4498                "  exit                            Request user instance exit\n"
4499                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4500                "  suspend                         Suspend the system\n"
4501                "  hibernate                       Hibernate the system\n",
4502                program_invocation_short_name);
4503
4504         return 0;
4505 }
4506
4507 static int halt_help(void) {
4508
4509         printf("%s [OPTIONS...]\n\n"
4510                "%s the system.\n\n"
4511                "     --help      Show this help\n"
4512                "     --halt      Halt the machine\n"
4513                "  -p --poweroff  Switch off the machine\n"
4514                "     --reboot    Reboot the machine\n"
4515                "  -f --force     Force immediate halt/power-off/reboot\n"
4516                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4517                "  -d --no-wtmp   Don't write wtmp record\n"
4518                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
4519                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4520                program_invocation_short_name,
4521                arg_action == ACTION_REBOOT   ? "Reboot" :
4522                arg_action == ACTION_POWEROFF ? "Power off" :
4523                                                "Halt");
4524
4525         return 0;
4526 }
4527
4528 static int shutdown_help(void) {
4529
4530         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4531                "Shut down the system.\n\n"
4532                "     --help      Show this help\n"
4533                "  -H --halt      Halt the machine\n"
4534                "  -P --poweroff  Power-off the machine\n"
4535                "  -r --reboot    Reboot the machine\n"
4536                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4537                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4538                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4539                "  -c             Cancel a pending shutdown\n",
4540                program_invocation_short_name);
4541
4542         return 0;
4543 }
4544
4545 static int telinit_help(void) {
4546
4547         printf("%s [OPTIONS...] {COMMAND}\n\n"
4548                "Send control commands to the init daemon.\n\n"
4549                "     --help      Show this help\n"
4550                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4551                "Commands:\n"
4552                "  0              Power-off the machine\n"
4553                "  6              Reboot the machine\n"
4554                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4555                "  1, s, S        Enter rescue mode\n"
4556                "  q, Q           Reload init daemon configuration\n"
4557                "  u, U           Reexecute init daemon\n",
4558                program_invocation_short_name);
4559
4560         return 0;
4561 }
4562
4563 static int runlevel_help(void) {
4564
4565         printf("%s [OPTIONS...]\n\n"
4566                "Prints the previous and current runlevel of the init system.\n\n"
4567                "     --help      Show this help\n",
4568                program_invocation_short_name);
4569
4570         return 0;
4571 }
4572
4573 static int systemctl_parse_argv(int argc, char *argv[]) {
4574
4575         enum {
4576                 ARG_FAIL = 0x100,
4577                 ARG_IGNORE_DEPENDENCIES,
4578                 ARG_VERSION,
4579                 ARG_USER,
4580                 ARG_SYSTEM,
4581                 ARG_GLOBAL,
4582                 ARG_NO_BLOCK,
4583                 ARG_NO_LEGEND,
4584                 ARG_NO_PAGER,
4585                 ARG_NO_WALL,
4586                 ARG_ORDER,
4587                 ARG_REQUIRE,
4588                 ARG_ROOT,
4589                 ARG_FULL,
4590                 ARG_NO_RELOAD,
4591                 ARG_KILL_MODE,
4592                 ARG_KILL_WHO,
4593                 ARG_NO_ASK_PASSWORD,
4594                 ARG_FAILED,
4595                 ARG_RUNTIME,
4596                 ARG_FOLLOW,
4597                 ARG_FORCE
4598         };
4599
4600         static const struct option options[] = {
4601                 { "help",      no_argument,       NULL, 'h'           },
4602                 { "version",   no_argument,       NULL, ARG_VERSION   },
4603                 { "type",      required_argument, NULL, 't'           },
4604                 { "property",  required_argument, NULL, 'p'           },
4605                 { "all",       no_argument,       NULL, 'a'           },
4606                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4607                 { "full",      no_argument,       NULL, ARG_FULL      },
4608                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4609                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4610                 { "user",      no_argument,       NULL, ARG_USER      },
4611                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4612                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4613                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4614                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4615                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4616                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4617                 { "quiet",     no_argument,       NULL, 'q'           },
4618                 { "order",     no_argument,       NULL, ARG_ORDER     },
4619                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4620                 { "root",      required_argument, NULL, ARG_ROOT      },
4621                 { "force",     no_argument,       NULL, ARG_FORCE     },
4622                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4623                 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
4624                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4625                 { "signal",    required_argument, NULL, 's'           },
4626                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4627                 { "host",      required_argument, NULL, 'H'           },
4628                 { "privileged",no_argument,       NULL, 'P'           },
4629                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4630                 { "lines",     required_argument, NULL, 'n'           },
4631                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4632                 { "output",    required_argument, NULL, 'o'           },
4633                 { NULL,        0,                 NULL, 0             }
4634         };
4635
4636         int c;
4637
4638         assert(argc >= 0);
4639         assert(argv);
4640
4641         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4642
4643                 switch (c) {
4644
4645                 case 'h':
4646                         systemctl_help();
4647                         return 0;
4648
4649                 case ARG_VERSION:
4650                         puts(PACKAGE_STRING);
4651                         puts(DISTRIBUTION);
4652                         puts(SYSTEMD_FEATURES);
4653                         return 0;
4654
4655                 case 't':
4656                         if (unit_type_from_string(optarg) >= 0) {
4657                                 arg_type = optarg;
4658                                 break;
4659                         }
4660                         if (unit_load_state_from_string(optarg) >= 0) {
4661                                 arg_load_state = optarg;
4662                                 break;
4663                         }
4664                         log_error("Unkown unit type or load state '%s'.",
4665                                   optarg);
4666                         return -EINVAL;
4667                 case 'p': {
4668                         char **l;
4669
4670                         if (!(l = strv_append(arg_property, optarg)))
4671                                 return -ENOMEM;
4672
4673                         strv_free(arg_property);
4674                         arg_property = l;
4675
4676                         /* If the user asked for a particular
4677                          * property, show it to him, even if it is
4678                          * empty. */
4679                         arg_all = true;
4680                         break;
4681                 }
4682
4683                 case 'a':
4684                         arg_all = true;
4685                         break;
4686
4687                 case ARG_FAIL:
4688                         arg_job_mode = "fail";
4689                         break;
4690
4691                 case ARG_IGNORE_DEPENDENCIES:
4692                         arg_job_mode = "ignore-dependencies";
4693                         break;
4694
4695                 case ARG_USER:
4696                         arg_scope = UNIT_FILE_USER;
4697                         break;
4698
4699                 case ARG_SYSTEM:
4700                         arg_scope = UNIT_FILE_SYSTEM;
4701                         break;
4702
4703                 case ARG_GLOBAL:
4704                         arg_scope = UNIT_FILE_GLOBAL;
4705                         break;
4706
4707                 case ARG_NO_BLOCK:
4708                         arg_no_block = true;
4709                         break;
4710
4711                 case ARG_NO_LEGEND:
4712                         arg_no_legend = true;
4713                         break;
4714
4715                 case ARG_NO_PAGER:
4716                         arg_no_pager = true;
4717                         break;
4718
4719                 case ARG_NO_WALL:
4720                         arg_no_wall = true;
4721                         break;
4722
4723                 case ARG_ORDER:
4724                         arg_dot = DOT_ORDER;
4725                         break;
4726
4727                 case ARG_REQUIRE:
4728                         arg_dot = DOT_REQUIRE;
4729                         break;
4730
4731                 case ARG_ROOT:
4732                         arg_root = optarg;
4733                         break;
4734
4735                 case ARG_FULL:
4736                         arg_full = true;
4737                         break;
4738
4739                 case ARG_FAILED:
4740                         arg_failed = true;
4741                         break;
4742
4743                 case 'q':
4744                         arg_quiet = true;
4745                         break;
4746
4747                 case ARG_FORCE:
4748                         arg_force ++;
4749                         break;
4750
4751                 case ARG_FOLLOW:
4752                         arg_follow = true;
4753                         break;
4754
4755                 case 'f':
4756                         /* -f is short for both --follow and --force! */
4757                         arg_force ++;
4758                         arg_follow = true;
4759                         break;
4760
4761                 case ARG_NO_RELOAD:
4762                         arg_no_reload = true;
4763                         break;
4764
4765                 case ARG_KILL_WHO:
4766                         arg_kill_who = optarg;
4767                         break;
4768
4769                 case ARG_KILL_MODE:
4770                         arg_kill_mode = optarg;
4771                         break;
4772
4773                 case 's':
4774                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4775                                 log_error("Failed to parse signal string %s.", optarg);
4776                                 return -EINVAL;
4777                         }
4778                         break;
4779
4780                 case ARG_NO_ASK_PASSWORD:
4781                         arg_ask_password = false;
4782                         break;
4783
4784                 case 'P':
4785                         arg_transport = TRANSPORT_POLKIT;
4786                         break;
4787
4788                 case 'H':
4789                         arg_transport = TRANSPORT_SSH;
4790                         arg_host = optarg;
4791                         break;
4792
4793                 case ARG_RUNTIME:
4794                         arg_runtime = true;
4795                         break;
4796
4797                 case 'n':
4798                         if (safe_atou(optarg, &arg_lines) < 0) {
4799                                 log_error("Failed to parse lines '%s'", optarg);
4800                                 return -EINVAL;
4801                         }
4802                         break;
4803
4804                 case 'o':
4805                         arg_output = output_mode_from_string(optarg);
4806                         if (arg_output < 0) {
4807                                 log_error("Unknown output '%s'.", optarg);
4808                                 return -EINVAL;
4809                         }
4810                         break;
4811
4812                 case '?':
4813                         return -EINVAL;
4814
4815                 default:
4816                         log_error("Unknown option code '%c'.", c);
4817                         return -EINVAL;
4818                 }
4819         }
4820
4821         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4822                 log_error("Cannot access user instance remotely.");
4823                 return -EINVAL;
4824         }
4825
4826         return 1;
4827 }
4828
4829 static int halt_parse_argv(int argc, char *argv[]) {
4830
4831         enum {
4832                 ARG_HELP = 0x100,
4833                 ARG_HALT,
4834                 ARG_REBOOT,
4835                 ARG_NO_WALL
4836         };
4837
4838         static const struct option options[] = {
4839                 { "help",      no_argument,       NULL, ARG_HELP    },
4840                 { "halt",      no_argument,       NULL, ARG_HALT    },
4841                 { "poweroff",  no_argument,       NULL, 'p'         },
4842                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4843                 { "force",     no_argument,       NULL, 'f'         },
4844                 { "wtmp-only", no_argument,       NULL, 'w'         },
4845                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4846                 { "no-sync",   no_argument,       NULL, 'n'         },
4847                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4848                 { NULL,        0,                 NULL, 0           }
4849         };
4850
4851         int c, runlevel;
4852
4853         assert(argc >= 0);
4854         assert(argv);
4855
4856         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4857                 if (runlevel == '0' || runlevel == '6')
4858                         arg_force = 2;
4859
4860         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4861                 switch (c) {
4862
4863                 case ARG_HELP:
4864                         halt_help();
4865                         return 0;
4866
4867                 case ARG_HALT:
4868                         arg_action = ACTION_HALT;
4869                         break;
4870
4871                 case 'p':
4872                         if (arg_action != ACTION_REBOOT)
4873                                 arg_action = ACTION_POWEROFF;
4874                         break;
4875
4876                 case ARG_REBOOT:
4877                         arg_action = ACTION_REBOOT;
4878                         break;
4879
4880                 case 'f':
4881                         arg_force = 2;
4882                         break;
4883
4884                 case 'w':
4885                         arg_dry = true;
4886                         break;
4887
4888                 case 'd':
4889                         arg_no_wtmp = true;
4890                         break;
4891
4892                 case 'n':
4893                         arg_no_sync = true;
4894                         break;
4895
4896                 case ARG_NO_WALL:
4897                         arg_no_wall = true;
4898                         break;
4899
4900                 case 'i':
4901                 case 'h':
4902                         /* Compatibility nops */
4903                         break;
4904
4905                 case '?':
4906                         return -EINVAL;
4907
4908                 default:
4909                         log_error("Unknown option code '%c'.", c);
4910                         return -EINVAL;
4911                 }
4912         }
4913
4914         if (optind < argc) {
4915                 log_error("Too many arguments.");
4916                 return -EINVAL;
4917         }
4918
4919         return 1;
4920 }
4921
4922 static int parse_time_spec(const char *t, usec_t *_u) {
4923         assert(t);
4924         assert(_u);
4925
4926         if (streq(t, "now"))
4927                 *_u = 0;
4928         else if (!strchr(t, ':')) {
4929                 uint64_t u;
4930
4931                 if (safe_atou64(t, &u) < 0)
4932                         return -EINVAL;
4933
4934                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4935         } else {
4936                 char *e = NULL;
4937                 long hour, minute;
4938                 struct tm tm;
4939                 time_t s;
4940                 usec_t n;
4941
4942                 errno = 0;
4943                 hour = strtol(t, &e, 10);
4944                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4945                         return -EINVAL;
4946
4947                 minute = strtol(e+1, &e, 10);
4948                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4949                         return -EINVAL;
4950
4951                 n = now(CLOCK_REALTIME);
4952                 s = (time_t) (n / USEC_PER_SEC);
4953
4954                 zero(tm);
4955                 assert_se(localtime_r(&s, &tm));
4956
4957                 tm.tm_hour = (int) hour;
4958                 tm.tm_min = (int) minute;
4959                 tm.tm_sec = 0;
4960
4961                 assert_se(s = mktime(&tm));
4962
4963                 *_u = (usec_t) s * USEC_PER_SEC;
4964
4965                 while (*_u <= n)
4966                         *_u += USEC_PER_DAY;
4967         }
4968
4969         return 0;
4970 }
4971
4972 static int shutdown_parse_argv(int argc, char *argv[]) {
4973
4974         enum {
4975                 ARG_HELP = 0x100,
4976                 ARG_NO_WALL
4977         };
4978
4979         static const struct option options[] = {
4980                 { "help",      no_argument,       NULL, ARG_HELP    },
4981                 { "halt",      no_argument,       NULL, 'H'         },
4982                 { "poweroff",  no_argument,       NULL, 'P'         },
4983                 { "reboot",    no_argument,       NULL, 'r'         },
4984                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4985                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4986                 { NULL,        0,                 NULL, 0           }
4987         };
4988
4989         int c, r;
4990
4991         assert(argc >= 0);
4992         assert(argv);
4993
4994         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4995                 switch (c) {
4996
4997                 case ARG_HELP:
4998                         shutdown_help();
4999                         return 0;
5000
5001                 case 'H':
5002                         arg_action = ACTION_HALT;
5003                         break;
5004
5005                 case 'P':
5006                         arg_action = ACTION_POWEROFF;
5007                         break;
5008
5009                 case 'r':
5010                         if (kexec_loaded())
5011                                 arg_action = ACTION_KEXEC;
5012                         else
5013                                 arg_action = ACTION_REBOOT;
5014                         break;
5015
5016                 case 'K':
5017                         arg_action = ACTION_KEXEC;
5018                         break;
5019
5020                 case 'h':
5021                         if (arg_action != ACTION_HALT)
5022                                 arg_action = ACTION_POWEROFF;
5023                         break;
5024
5025                 case 'k':
5026                         arg_dry = true;
5027                         break;
5028
5029                 case ARG_NO_WALL:
5030                         arg_no_wall = true;
5031                         break;
5032
5033                 case 't':
5034                 case 'a':
5035                         /* Compatibility nops */
5036                         break;
5037
5038                 case 'c':
5039                         arg_action = ACTION_CANCEL_SHUTDOWN;
5040                         break;
5041
5042                 case '?':
5043                         return -EINVAL;
5044
5045                 default:
5046                         log_error("Unknown option code '%c'.", c);
5047                         return -EINVAL;
5048                 }
5049         }
5050
5051         if (argc > optind) {
5052                 r = parse_time_spec(argv[optind], &arg_when);
5053                 if (r < 0) {
5054                         log_error("Failed to parse time specification: %s", argv[optind]);
5055                         return r;
5056                 }
5057         } else
5058                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
5059
5060         /* We skip the time argument */
5061         if (argc > optind + 1)
5062                 arg_wall = argv + optind + 1;
5063
5064         optind = argc;
5065
5066         return 1;
5067 }
5068
5069 static int telinit_parse_argv(int argc, char *argv[]) {
5070
5071         enum {
5072                 ARG_HELP = 0x100,
5073                 ARG_NO_WALL
5074         };
5075
5076         static const struct option options[] = {
5077                 { "help",      no_argument,       NULL, ARG_HELP    },
5078                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5079                 { NULL,        0,                 NULL, 0           }
5080         };
5081
5082         static const struct {
5083                 char from;
5084                 enum action to;
5085         } table[] = {
5086                 { '0', ACTION_POWEROFF },
5087                 { '6', ACTION_REBOOT },
5088                 { '1', ACTION_RESCUE },
5089                 { '2', ACTION_RUNLEVEL2 },
5090                 { '3', ACTION_RUNLEVEL3 },
5091                 { '4', ACTION_RUNLEVEL4 },
5092                 { '5', ACTION_RUNLEVEL5 },
5093                 { 's', ACTION_RESCUE },
5094                 { 'S', ACTION_RESCUE },
5095                 { 'q', ACTION_RELOAD },
5096                 { 'Q', ACTION_RELOAD },
5097                 { 'u', ACTION_REEXEC },
5098                 { 'U', ACTION_REEXEC }
5099         };
5100
5101         unsigned i;
5102         int c;
5103
5104         assert(argc >= 0);
5105         assert(argv);
5106
5107         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5108                 switch (c) {
5109
5110                 case ARG_HELP:
5111                         telinit_help();
5112                         return 0;
5113
5114                 case ARG_NO_WALL:
5115                         arg_no_wall = true;
5116                         break;
5117
5118                 case '?':
5119                         return -EINVAL;
5120
5121                 default:
5122                         log_error("Unknown option code '%c'.", c);
5123                         return -EINVAL;
5124                 }
5125         }
5126
5127         if (optind >= argc) {
5128                 telinit_help();
5129                 return -EINVAL;
5130         }
5131
5132         if (optind + 1 < argc) {
5133                 log_error("Too many arguments.");
5134                 return -EINVAL;
5135         }
5136
5137         if (strlen(argv[optind]) != 1) {
5138                 log_error("Expected single character argument.");
5139                 return -EINVAL;
5140         }
5141
5142         for (i = 0; i < ELEMENTSOF(table); i++)
5143                 if (table[i].from == argv[optind][0])
5144                         break;
5145
5146         if (i >= ELEMENTSOF(table)) {
5147                 log_error("Unknown command '%s'.", argv[optind]);
5148                 return -EINVAL;
5149         }
5150
5151         arg_action = table[i].to;
5152
5153         optind ++;
5154
5155         return 1;
5156 }
5157
5158 static int runlevel_parse_argv(int argc, char *argv[]) {
5159
5160         enum {
5161                 ARG_HELP = 0x100,
5162         };
5163
5164         static const struct option options[] = {
5165                 { "help",      no_argument,       NULL, ARG_HELP    },
5166                 { NULL,        0,                 NULL, 0           }
5167         };
5168
5169         int c;
5170
5171         assert(argc >= 0);
5172         assert(argv);
5173
5174         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5175                 switch (c) {
5176
5177                 case ARG_HELP:
5178                         runlevel_help();
5179                         return 0;
5180
5181                 case '?':
5182                         return -EINVAL;
5183
5184                 default:
5185                         log_error("Unknown option code '%c'.", c);
5186                         return -EINVAL;
5187                 }
5188         }
5189
5190         if (optind < argc) {
5191                 log_error("Too many arguments.");
5192                 return -EINVAL;
5193         }
5194
5195         return 1;
5196 }
5197
5198 static int parse_argv(int argc, char *argv[]) {
5199         assert(argc >= 0);
5200         assert(argv);
5201
5202         if (program_invocation_short_name) {
5203
5204                 if (strstr(program_invocation_short_name, "halt")) {
5205                         arg_action = ACTION_HALT;
5206                         return halt_parse_argv(argc, argv);
5207                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5208                         arg_action = ACTION_POWEROFF;
5209                         return halt_parse_argv(argc, argv);
5210                 } else if (strstr(program_invocation_short_name, "reboot")) {
5211                         if (kexec_loaded())
5212                                 arg_action = ACTION_KEXEC;
5213                         else
5214                                 arg_action = ACTION_REBOOT;
5215                         return halt_parse_argv(argc, argv);
5216                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5217                         arg_action = ACTION_POWEROFF;
5218                         return shutdown_parse_argv(argc, argv);
5219                 } else if (strstr(program_invocation_short_name, "init")) {
5220
5221                         if (sd_booted() > 0) {
5222                                 arg_action = ACTION_INVALID;
5223                                 return telinit_parse_argv(argc, argv);
5224                         } else {
5225                                 /* Hmm, so some other init system is
5226                                  * running, we need to forward this
5227                                  * request to it. For now we simply
5228                                  * guess that it is Upstart. */
5229
5230                                 execv("/lib/upstart/telinit", argv);
5231
5232                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5233                                 return -EIO;
5234                         }
5235
5236                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5237                         arg_action = ACTION_RUNLEVEL;
5238                         return runlevel_parse_argv(argc, argv);
5239                 }
5240         }
5241
5242         arg_action = ACTION_SYSTEMCTL;
5243         return systemctl_parse_argv(argc, argv);
5244 }
5245
5246 static int action_to_runlevel(void) {
5247
5248         static const char table[_ACTION_MAX] = {
5249                 [ACTION_HALT] =      '0',
5250                 [ACTION_POWEROFF] =  '0',
5251                 [ACTION_REBOOT] =    '6',
5252                 [ACTION_RUNLEVEL2] = '2',
5253                 [ACTION_RUNLEVEL3] = '3',
5254                 [ACTION_RUNLEVEL4] = '4',
5255                 [ACTION_RUNLEVEL5] = '5',
5256                 [ACTION_RESCUE] =    '1'
5257         };
5258
5259         assert(arg_action < _ACTION_MAX);
5260
5261         return table[arg_action];
5262 }
5263
5264 static int talk_upstart(void) {
5265         DBusMessage *m = NULL, *reply = NULL;
5266         DBusError error;
5267         int previous, rl, r;
5268         char
5269                 env1_buf[] = "RUNLEVEL=X",
5270                 env2_buf[] = "PREVLEVEL=X";
5271         char *env1 = env1_buf, *env2 = env2_buf;
5272         const char *emit = "runlevel";
5273         dbus_bool_t b_false = FALSE;
5274         DBusMessageIter iter, sub;
5275         DBusConnection *bus;
5276
5277         dbus_error_init(&error);
5278
5279         if (!(rl = action_to_runlevel()))
5280                 return 0;
5281
5282         if (utmp_get_runlevel(&previous, NULL) < 0)
5283                 previous = 'N';
5284
5285         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5286                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5287                         r = 0;
5288                         goto finish;
5289                 }
5290
5291                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5292                 r = -EIO;
5293                 goto finish;
5294         }
5295
5296         if ((r = bus_check_peercred(bus)) < 0) {
5297                 log_error("Failed to verify owner of bus.");
5298                 goto finish;
5299         }
5300
5301         if (!(m = dbus_message_new_method_call(
5302                               "com.ubuntu.Upstart",
5303                               "/com/ubuntu/Upstart",
5304                               "com.ubuntu.Upstart0_6",
5305                               "EmitEvent"))) {
5306
5307                 log_error("Could not allocate message.");
5308                 r = -ENOMEM;
5309                 goto finish;
5310         }
5311
5312         dbus_message_iter_init_append(m, &iter);
5313
5314         env1_buf[sizeof(env1_buf)-2] = rl;
5315         env2_buf[sizeof(env2_buf)-2] = previous;
5316
5317         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5318             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5319             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5320             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5321             !dbus_message_iter_close_container(&iter, &sub) ||
5322             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5323                 log_error("Could not append arguments to message.");
5324                 r = -ENOMEM;
5325                 goto finish;
5326         }
5327
5328         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5329
5330                 if (error_is_no_service(&error)) {
5331                         r = -EADDRNOTAVAIL;
5332                         goto finish;
5333                 }
5334
5335                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5336                 r = -EIO;
5337                 goto finish;
5338         }
5339
5340         r = 1;
5341
5342 finish:
5343         if (m)
5344                 dbus_message_unref(m);
5345
5346         if (reply)
5347                 dbus_message_unref(reply);
5348
5349         if (bus) {
5350                 dbus_connection_flush(bus);
5351                 dbus_connection_close(bus);
5352                 dbus_connection_unref(bus);
5353         }
5354
5355         dbus_error_free(&error);
5356
5357         return r;
5358 }
5359
5360 static int talk_initctl(void) {
5361         struct init_request request;
5362         int r, fd;
5363         char rl;
5364
5365         if (!(rl = action_to_runlevel()))
5366                 return 0;
5367
5368         zero(request);
5369         request.magic = INIT_MAGIC;
5370         request.sleeptime = 0;
5371         request.cmd = INIT_CMD_RUNLVL;
5372         request.runlevel = rl;
5373
5374         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5375
5376                 if (errno == ENOENT)
5377                         return 0;
5378
5379                 log_error("Failed to open "INIT_FIFO": %m");
5380                 return -errno;
5381         }
5382
5383         errno = 0;
5384         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5385         close_nointr_nofail(fd);
5386
5387         if (r < 0) {
5388                 log_error("Failed to write to "INIT_FIFO": %m");
5389                 return errno ? -errno : -EIO;
5390         }
5391
5392         return 1;
5393 }
5394
5395 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5396
5397         static const struct {
5398                 const char* verb;
5399                 const enum {
5400                         MORE,
5401                         LESS,
5402                         EQUAL
5403                 } argc_cmp;
5404                 const int argc;
5405                 int (* const dispatch)(DBusConnection *bus, char **args);
5406         } verbs[] = {
5407                 { "list-units",            LESS,  1, list_units        },
5408                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5409                 { "list-jobs",             EQUAL, 1, list_jobs         },
5410                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5411                 { "load",                  MORE,  2, load_unit         },
5412                 { "cancel",                MORE,  2, cancel_job        },
5413                 { "start",                 MORE,  2, start_unit        },
5414                 { "stop",                  MORE,  2, start_unit        },
5415                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5416                 { "reload",                MORE,  2, start_unit        },
5417                 { "restart",               MORE,  2, start_unit        },
5418                 { "try-restart",           MORE,  2, start_unit        },
5419                 { "reload-or-restart",     MORE,  2, start_unit        },
5420                 { "reload-or-try-restart", MORE,  2, start_unit        },
5421                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5422                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5423                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5424                 { "isolate",               EQUAL, 2, start_unit        },
5425                 { "kill",                  MORE,  2, kill_unit         },
5426                 { "is-active",             MORE,  2, check_unit        },
5427                 { "check",                 MORE,  2, check_unit        },
5428                 { "show",                  MORE,  1, show              },
5429                 { "status",                MORE,  2, show              },
5430                 { "help",                  MORE,  2, show              },
5431                 { "dump",                  EQUAL, 1, dump              },
5432                 { "dot",                   EQUAL, 1, dot               },
5433                 { "snapshot",              LESS,  2, snapshot          },
5434                 { "delete",                MORE,  2, delete_snapshot   },
5435                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5436                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5437                 { "show-environment",      EQUAL, 1, show_enviroment   },
5438                 { "set-environment",       MORE,  2, set_environment   },
5439                 { "unset-environment",     MORE,  2, set_environment   },
5440                 { "halt",                  EQUAL, 1, start_special     },
5441                 { "poweroff",              EQUAL, 1, start_special     },
5442                 { "reboot",                EQUAL, 1, start_special     },
5443                 { "kexec",                 EQUAL, 1, start_special     },
5444                 { "suspend",               EQUAL, 1, start_special     },
5445                 { "hibernate",             EQUAL, 1, start_special     },
5446                 { "default",               EQUAL, 1, start_special     },
5447                 { "rescue",                EQUAL, 1, start_special     },
5448                 { "emergency",             EQUAL, 1, start_special     },
5449                 { "exit",                  EQUAL, 1, start_special     },
5450                 { "reset-failed",          MORE,  1, reset_failed      },
5451                 { "enable",                MORE,  2, enable_unit       },
5452                 { "disable",               MORE,  2, enable_unit       },
5453                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5454                 { "reenable",              MORE,  2, enable_unit       },
5455                 { "preset",                MORE,  2, enable_unit       },
5456                 { "mask",                  MORE,  2, enable_unit       },
5457                 { "unmask",                MORE,  2, enable_unit       },
5458                 { "link",                  MORE,  2, enable_unit       },
5459                 { "switch-root",           MORE,  2, switch_root       },
5460         };
5461
5462         int left;
5463         unsigned i;
5464
5465         assert(argc >= 0);
5466         assert(argv);
5467         assert(error);
5468
5469         left = argc - optind;
5470
5471         if (left <= 0)
5472                 /* Special rule: no arguments means "list-units" */
5473                 i = 0;
5474         else {
5475                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5476                         log_error("This command expects one or more "
5477                                   "unit names. Did you mean --help?");
5478                         return -EINVAL;
5479                 }
5480
5481                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5482                         if (streq(argv[optind], verbs[i].verb))
5483                                 break;
5484
5485                 if (i >= ELEMENTSOF(verbs)) {
5486                         log_error("Unknown operation '%s'.", argv[optind]);
5487                         return -EINVAL;
5488                 }
5489         }
5490
5491         switch (verbs[i].argc_cmp) {
5492
5493         case EQUAL:
5494                 if (left != verbs[i].argc) {
5495                         log_error("Invalid number of arguments.");
5496                         return -EINVAL;
5497                 }
5498
5499                 break;
5500
5501         case MORE:
5502                 if (left < verbs[i].argc) {
5503                         log_error("Too few arguments.");
5504                         return -EINVAL;
5505                 }
5506
5507                 break;
5508
5509         case LESS:
5510                 if (left > verbs[i].argc) {
5511                         log_error("Too many arguments.");
5512                         return -EINVAL;
5513                 }
5514
5515                 break;
5516
5517         default:
5518                 assert_not_reached("Unknown comparison operator.");
5519         }
5520
5521         /* Require a bus connection for all operations but
5522          * enable/disable */
5523         if (!streq(verbs[i].verb, "enable") &&
5524             !streq(verbs[i].verb, "disable") &&
5525             !streq(verbs[i].verb, "is-enabled") &&
5526             !streq(verbs[i].verb, "list-unit-files") &&
5527             !streq(verbs[i].verb, "reenable") &&
5528             !streq(verbs[i].verb, "preset") &&
5529             !streq(verbs[i].verb, "mask") &&
5530             !streq(verbs[i].verb, "unmask") &&
5531             !streq(verbs[i].verb, "link")) {
5532
5533                 if (running_in_chroot() > 0) {
5534                         log_info("Running in chroot, ignoring request.");
5535                         return 0;
5536                 }
5537
5538                 if (((!streq(verbs[i].verb, "reboot") &&
5539                       !streq(verbs[i].verb, "halt") &&
5540                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5541                         log_error("Failed to get D-Bus connection: %s",
5542                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5543                         return -EIO;
5544                 }
5545
5546         } else {
5547
5548                 if (!bus && !avoid_bus()) {
5549                         log_error("Failed to get D-Bus connection: %s",
5550                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5551                         return -EIO;
5552                 }
5553         }
5554
5555         return verbs[i].dispatch(bus, argv + optind);
5556 }
5557
5558 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5559         int fd;
5560         struct msghdr msghdr;
5561         struct iovec iovec[2];
5562         union sockaddr_union sockaddr;
5563         struct sd_shutdown_command c;
5564
5565         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5566         if (fd < 0)
5567                 return -errno;
5568
5569         zero(c);
5570         c.usec = t;
5571         c.mode = mode;
5572         c.dry_run = dry_run;
5573         c.warn_wall = warn;
5574
5575         zero(sockaddr);
5576         sockaddr.sa.sa_family = AF_UNIX;
5577         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5578
5579         zero(msghdr);
5580         msghdr.msg_name = &sockaddr;
5581         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5582
5583         zero(iovec);
5584         iovec[0].iov_base = (char*) &c;
5585         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5586
5587         if (isempty(message))
5588                 msghdr.msg_iovlen = 1;
5589         else {
5590                 iovec[1].iov_base = (char*) message;
5591                 iovec[1].iov_len = strlen(message);
5592                 msghdr.msg_iovlen = 2;
5593         }
5594         msghdr.msg_iov = iovec;
5595
5596         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5597                 close_nointr_nofail(fd);
5598                 return -errno;
5599         }
5600
5601         close_nointr_nofail(fd);
5602         return 0;
5603 }
5604
5605 static int reload_with_fallback(DBusConnection *bus) {
5606
5607         if (bus) {
5608                 /* First, try systemd via D-Bus. */
5609                 if (daemon_reload(bus, NULL) >= 0)
5610                         return 0;
5611         }
5612
5613         /* Nothing else worked, so let's try signals */
5614         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5615
5616         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5617                 log_error("kill() failed: %m");
5618                 return -errno;
5619         }
5620
5621         return 0;
5622 }
5623
5624 static int start_with_fallback(DBusConnection *bus) {
5625
5626         if (bus) {
5627                 /* First, try systemd via D-Bus. */
5628                 if (start_unit(bus, NULL) >= 0)
5629                         goto done;
5630         }
5631
5632         /* Hmm, talking to systemd via D-Bus didn't work. Then
5633          * let's try to talk to Upstart via D-Bus. */
5634         if (talk_upstart() > 0)
5635                 goto done;
5636
5637         /* Nothing else worked, so let's try
5638          * /dev/initctl */
5639         if (talk_initctl() > 0)
5640                 goto done;
5641
5642         log_error("Failed to talk to init daemon.");
5643         return -EIO;
5644
5645 done:
5646         warn_wall(arg_action);
5647         return 0;
5648 }
5649
5650 static void halt_now(enum action a) {
5651
5652        /* Make sure C-A-D is handled by the kernel from this
5653          * point on... */
5654         reboot(RB_ENABLE_CAD);
5655
5656         switch (a) {
5657
5658         case ACTION_HALT:
5659                 log_info("Halting.");
5660                 reboot(RB_HALT_SYSTEM);
5661                 break;
5662
5663         case ACTION_POWEROFF:
5664                 log_info("Powering off.");
5665                 reboot(RB_POWER_OFF);
5666                 break;
5667
5668         case ACTION_REBOOT:
5669                 log_info("Rebooting.");
5670                 reboot(RB_AUTOBOOT);
5671                 break;
5672
5673         default:
5674                 assert_not_reached("Unknown halt action.");
5675         }
5676
5677         assert_not_reached("Uh? This shouldn't happen.");
5678 }
5679
5680 static int halt_main(DBusConnection *bus) {
5681         int r;
5682
5683         if (geteuid() != 0) {
5684                 /* Try logind if we are a normal user and no special
5685                  * mode applies. Maybe PolicyKit allows us to shutdown
5686                  * the machine. */
5687
5688                 if (arg_when <= 0 &&
5689                     !arg_dry &&
5690                     !arg_force &&
5691                     (arg_action == ACTION_POWEROFF ||
5692                      arg_action == ACTION_REBOOT)) {
5693                         r = reboot_with_logind(bus, arg_action);
5694                         if (r >= 0)
5695                                 return r;
5696                 }
5697
5698                 log_error("Must be root.");
5699                 return -EPERM;
5700         }
5701
5702         if (arg_when > 0) {
5703                 char *m;
5704
5705                 m = strv_join(arg_wall, " ");
5706                 r = send_shutdownd(arg_when,
5707                                    arg_action == ACTION_HALT     ? 'H' :
5708                                    arg_action == ACTION_POWEROFF ? 'P' :
5709                                    arg_action == ACTION_KEXEC    ? 'K' :
5710                                                                    'r',
5711                                    arg_dry,
5712                                    !arg_no_wall,
5713                                    m);
5714                 free(m);
5715
5716                 if (r < 0)
5717                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5718                 else {
5719                         char date[FORMAT_TIMESTAMP_MAX];
5720
5721                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5722                                  format_timestamp(date, sizeof(date), arg_when));
5723                         return 0;
5724                 }
5725         }
5726
5727         if (!arg_dry && !arg_force)
5728                 return start_with_fallback(bus);
5729
5730         if (!arg_no_wtmp) {
5731                 if (sd_booted() > 0)
5732                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5733                 else {
5734                         r = utmp_put_shutdown();
5735                         if (r < 0)
5736                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5737                 }
5738         }
5739
5740         if (!arg_no_sync)
5741                 sync();
5742
5743         if (arg_dry)
5744                 return 0;
5745
5746         halt_now(arg_action);
5747         /* We should never reach this. */
5748         return -ENOSYS;
5749 }
5750
5751 static int runlevel_main(void) {
5752         int r, runlevel, previous;
5753
5754         r = utmp_get_runlevel(&runlevel, &previous);
5755         if (r < 0) {
5756                 puts("unknown");
5757                 return r;
5758         }
5759
5760         printf("%c %c\n",
5761                previous <= 0 ? 'N' : previous,
5762                runlevel <= 0 ? 'N' : runlevel);
5763
5764         return 0;
5765 }
5766
5767 int main(int argc, char*argv[]) {
5768         int r, retval = EXIT_FAILURE;
5769         DBusConnection *bus = NULL;
5770         DBusError error;
5771
5772         dbus_error_init(&error);
5773
5774         log_parse_environment();
5775         log_open();
5776
5777         r = parse_argv(argc, argv);
5778         if (r < 0)
5779                 goto finish;
5780         else if (r == 0) {
5781                 retval = EXIT_SUCCESS;
5782                 goto finish;
5783         }
5784
5785         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5786          * let's shortcut this */
5787         if (arg_action == ACTION_RUNLEVEL) {
5788                 r = runlevel_main();
5789                 retval = r < 0 ? EXIT_FAILURE : r;
5790                 goto finish;
5791         }
5792
5793         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5794                 log_info("Running in chroot, ignoring request.");
5795                 retval = 0;
5796                 goto finish;
5797         }
5798
5799         if (!avoid_bus()) {
5800                 if (arg_transport == TRANSPORT_NORMAL)
5801                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5802                 else if (arg_transport == TRANSPORT_POLKIT) {
5803                         bus_connect_system_polkit(&bus, &error);
5804                         private_bus = false;
5805                 } else if (arg_transport == TRANSPORT_SSH) {
5806                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5807                         private_bus = false;
5808                 } else
5809                         assert_not_reached("Uh, invalid transport...");
5810         }
5811
5812         switch (arg_action) {
5813
5814         case ACTION_SYSTEMCTL:
5815                 r = systemctl_main(bus, argc, argv, &error);
5816                 break;
5817
5818         case ACTION_HALT:
5819         case ACTION_POWEROFF:
5820         case ACTION_REBOOT:
5821         case ACTION_KEXEC:
5822                 r = halt_main(bus);
5823                 break;
5824
5825         case ACTION_RUNLEVEL2:
5826         case ACTION_RUNLEVEL3:
5827         case ACTION_RUNLEVEL4:
5828         case ACTION_RUNLEVEL5:
5829         case ACTION_RESCUE:
5830         case ACTION_EMERGENCY:
5831         case ACTION_DEFAULT:
5832                 r = start_with_fallback(bus);
5833                 break;
5834
5835         case ACTION_RELOAD:
5836         case ACTION_REEXEC:
5837                 r = reload_with_fallback(bus);
5838                 break;
5839
5840         case ACTION_CANCEL_SHUTDOWN:
5841                 r = send_shutdownd(0, 0, false, false, NULL);
5842                 break;
5843
5844         case ACTION_INVALID:
5845         case ACTION_RUNLEVEL:
5846         default:
5847                 assert_not_reached("Unknown action");
5848         }
5849
5850         retval = r < 0 ? EXIT_FAILURE : r;
5851
5852 finish:
5853         if (bus) {
5854                 dbus_connection_flush(bus);
5855                 dbus_connection_close(bus);
5856                 dbus_connection_unref(bus);
5857         }
5858
5859         dbus_error_free(&error);
5860
5861         dbus_shutdown();
5862
5863         strv_free(arg_property);
5864
5865         pager_close();
5866         ask_password_agent_close();
5867         polkit_agent_close();
5868
5869         return retval;
5870 }