chiark / gitweb /
systemctl: use color specification understood by dot
[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 int arg_signal = SIGTERM;
90 static const char *arg_root = NULL;
91 static usec_t arg_when = 0;
92 static enum action {
93         ACTION_INVALID,
94         ACTION_SYSTEMCTL,
95         ACTION_HALT,
96         ACTION_POWEROFF,
97         ACTION_REBOOT,
98         ACTION_KEXEC,
99         ACTION_EXIT,
100         ACTION_SUSPEND,
101         ACTION_HIBERNATE,
102         ACTION_RUNLEVEL2,
103         ACTION_RUNLEVEL3,
104         ACTION_RUNLEVEL4,
105         ACTION_RUNLEVEL5,
106         ACTION_RESCUE,
107         ACTION_EMERGENCY,
108         ACTION_DEFAULT,
109         ACTION_RELOAD,
110         ACTION_REEXEC,
111         ACTION_RUNLEVEL,
112         ACTION_CANCEL_SHUTDOWN,
113         _ACTION_MAX
114 } arg_action = ACTION_SYSTEMCTL;
115 static enum dot {
116         DOT_ALL,
117         DOT_ORDER,
118         DOT_REQUIRE
119 } arg_dot = DOT_ALL;
120 static enum transport {
121         TRANSPORT_NORMAL,
122         TRANSPORT_SSH,
123         TRANSPORT_POLKIT
124 } arg_transport = TRANSPORT_NORMAL;
125 static const char *arg_host = NULL;
126 static bool arg_follow = false;
127 static unsigned arg_lines = 10;
128 static OutputMode arg_output = OUTPUT_SHORT;
129
130 static bool private_bus = false;
131
132 static int daemon_reload(DBusConnection *bus, char **args);
133 static void halt_now(enum action a);
134
135 static bool on_tty(void) {
136         static int t = -1;
137
138         /* Note that this is invoked relatively early, before we start
139          * the pager. That means the value we return reflects whether
140          * we originally were started on a tty, not if we currently
141          * are. But this is intended, since we want colour and so on
142          * when run in our own pager. */
143
144         if (_unlikely_(t < 0))
145                 t = isatty(STDOUT_FILENO) > 0;
146
147         return t;
148 }
149
150 static void pager_open_if_enabled(void) {
151
152         /* Cache result before we open the pager */
153         on_tty();
154
155         if (arg_no_pager)
156                 return;
157
158         pager_open();
159 }
160
161 static void ask_password_agent_open_if_enabled(void) {
162
163         /* Open the password agent as a child process if necessary */
164
165         if (!arg_ask_password)
166                 return;
167
168         if (arg_scope != UNIT_FILE_SYSTEM)
169                 return;
170
171         ask_password_agent_open();
172 }
173
174 #ifdef HAVE_LOGIND
175 static void polkit_agent_open_if_enabled(void) {
176
177         /* Open the polkit agent as a child process if necessary */
178
179         if (!arg_ask_password)
180                 return;
181
182         if (arg_scope != UNIT_FILE_SYSTEM)
183                 return;
184
185         polkit_agent_open();
186 }
187 #endif
188
189 static const char *ansi_highlight_red(bool b) {
190
191         if (!on_tty())
192                 return "";
193
194         return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
195 }
196
197 static const char *ansi_highlight_green(bool b) {
198
199         if (!on_tty())
200                 return "";
201
202         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
203 }
204
205 static bool error_is_no_service(const DBusError *error) {
206         assert(error);
207
208         if (!dbus_error_is_set(error))
209                 return false;
210
211         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
212                 return true;
213
214         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
215                 return true;
216
217         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
218 }
219
220 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
221         assert(error);
222
223         if (!dbus_error_is_set(error))
224                 return r;
225
226         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
227             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
228             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
229             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
230                 return EXIT_NOPERMISSION;
231
232         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
233                 return EXIT_NOTINSTALLED;
234
235         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
236             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
237                 return EXIT_NOTIMPLEMENTED;
238
239         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
240                 return EXIT_NOTCONFIGURED;
241
242         if (r != 0)
243                 return r;
244
245         return EXIT_FAILURE;
246 }
247
248 static void warn_wall(enum action a) {
249         static const char *table[_ACTION_MAX] = {
250                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
251                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
252                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
253                 [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
254                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
255                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
256         };
257
258         if (arg_no_wall)
259                 return;
260
261         if (arg_wall) {
262                 char *p;
263
264                 p = strv_join(arg_wall, " ");
265                 if (!p) {
266                         log_error("Failed to join strings.");
267                         return;
268                 }
269
270                 if (*p) {
271                         utmp_wall(p, NULL);
272                         free(p);
273                         return;
274                 }
275
276                 free(p);
277         }
278
279         if (!table[a])
280                 return;
281
282         utmp_wall(table[a], NULL);
283 }
284
285 static bool avoid_bus(void) {
286
287         if (running_in_chroot() > 0)
288                 return true;
289
290         if (sd_booted() <= 0)
291                 return true;
292
293         if (!isempty(arg_root))
294                 return true;
295
296         if (arg_scope == UNIT_FILE_GLOBAL)
297                 return true;
298
299         return false;
300 }
301
302 struct unit_info {
303         const char *id;
304         const char *description;
305         const char *load_state;
306         const char *active_state;
307         const char *sub_state;
308         const char *following;
309         const char *unit_path;
310         uint32_t job_id;
311         const char *job_type;
312         const char *job_path;
313 };
314
315 static int compare_unit_info(const void *a, const void *b) {
316         const char *d1, *d2;
317         const struct unit_info *u = a, *v = b;
318
319         d1 = strrchr(u->id, '.');
320         d2 = strrchr(v->id, '.');
321
322         if (d1 && d2) {
323                 int r;
324
325                 if ((r = strcasecmp(d1, d2)) != 0)
326                         return r;
327         }
328
329         return strcasecmp(u->id, v->id);
330 }
331
332 static bool output_show_unit(const struct unit_info *u) {
333         const char *dot;
334
335         if (arg_failed)
336                 return streq(u->active_state, "failed");
337
338         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
339                               streq(dot+1, arg_type))) &&
340                 (!arg_load_state || streq(u->load_state, arg_load_state)) &&
341                 (arg_all || !(streq(u->active_state, "inactive")
342                               || u->following[0]) || u->job_id > 0);
343 }
344
345 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
346         unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
347         const struct unit_info *u;
348
349         max_id_len = sizeof("UNIT")-1;
350         active_len = sizeof("ACTIVE")-1;
351         sub_len = sizeof("SUB")-1;
352         job_len = sizeof("JOB")-1;
353         desc_len = 0;
354
355         for (u = unit_infos; u < unit_infos + c; u++) {
356                 if (!output_show_unit(u))
357                         continue;
358
359                 max_id_len = MAX(max_id_len, strlen(u->id));
360                 active_len = MAX(active_len, strlen(u->active_state));
361                 sub_len = MAX(sub_len, strlen(u->sub_state));
362                 if (u->job_id != 0)
363                         job_len = MAX(job_len, strlen(u->job_type));
364         }
365
366         if (!arg_full) {
367                 unsigned basic_len;
368                 id_len = MIN(max_id_len, 25);
369                 basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
370                 if (basic_len < (unsigned) columns()) {
371                         unsigned extra_len, incr;
372                         extra_len = columns() - basic_len;
373                         /* Either UNIT already got 25, or is fully satisfied.
374                          * Grant up to 25 to DESC now. */
375                         incr = MIN(extra_len, 25);
376                         desc_len += incr;
377                         extra_len -= incr;
378                         /* split the remaining space between UNIT and DESC,
379                          * but do not give UNIT more than it needs. */
380                         if (extra_len > 0) {
381                                 incr = MIN(extra_len / 2, max_id_len - id_len);
382                                 id_len += incr;
383                                 desc_len += extra_len - incr;
384                         }
385                 }
386         } else
387                 id_len = max_id_len;
388
389         if (!arg_no_legend) {
390                 printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
391                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
392                 if (!arg_full && arg_no_pager)
393                         printf("%.*s\n", desc_len, "DESCRIPTION");
394                 else
395                         printf("%s\n", "DESCRIPTION");
396         }
397
398         for (u = unit_infos; u < unit_infos + c; u++) {
399                 char *e;
400                 const char *on_loaded, *off_loaded;
401                 const char *on_active, *off_active;
402
403                 if (!output_show_unit(u))
404                         continue;
405
406                 n_shown++;
407
408                 if (streq(u->load_state, "error")) {
409                         on_loaded = ansi_highlight_red(true);
410                         off_loaded = ansi_highlight_red(false);
411                 } else
412                         on_loaded = off_loaded = "";
413
414                 if (streq(u->active_state, "failed")) {
415                         on_active = ansi_highlight_red(true);
416                         off_active = ansi_highlight_red(false);
417                 } else
418                         on_active = off_active = "";
419
420                 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
421
422                 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
423                        id_len, e ? e : u->id,
424                        on_loaded, u->load_state, off_loaded,
425                        on_active, active_len, u->active_state,
426                        sub_len, u->sub_state, off_active,
427                        job_len, u->job_id ? u->job_type : "");
428                 if (!arg_full && arg_no_pager)
429                         printf("%.*s\n", desc_len, u->description);
430                 else
431                         printf("%s\n", u->description);
432
433                 free(e);
434         }
435
436         if (!arg_no_legend) {
437                 printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
438                        "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
439                        "SUB    = The low-level unit activation state, values depend on unit type.\n"
440                        "JOB    = Pending job for the unit.\n");
441
442                 if (arg_all)
443                         printf("\n%u units listed.\n", n_shown);
444                 else
445                         printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
446         }
447 }
448
449 static int list_units(DBusConnection *bus, char **args) {
450         DBusMessage *m = NULL, *reply = NULL;
451         DBusError error;
452         int r;
453         DBusMessageIter iter, sub, sub2;
454         unsigned c = 0, n_units = 0;
455         struct unit_info *unit_infos = NULL;
456
457         dbus_error_init(&error);
458
459         assert(bus);
460
461         pager_open_if_enabled();
462
463         if (!(m = dbus_message_new_method_call(
464                               "org.freedesktop.systemd1",
465                               "/org/freedesktop/systemd1",
466                               "org.freedesktop.systemd1.Manager",
467                               "ListUnits"))) {
468                 log_error("Could not allocate message.");
469                 return -ENOMEM;
470         }
471
472         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
473                 log_error("Failed to issue method call: %s", bus_error_message(&error));
474                 r = -EIO;
475                 goto finish;
476         }
477
478         if (!dbus_message_iter_init(reply, &iter) ||
479             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
480             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
481                 log_error("Failed to parse reply.");
482                 r = -EIO;
483                 goto finish;
484         }
485
486         dbus_message_iter_recurse(&iter, &sub);
487
488         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
489                 struct unit_info *u;
490
491                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
492                         log_error("Failed to parse reply.");
493                         r = -EIO;
494                         goto finish;
495                 }
496
497                 if (c >= n_units) {
498                         struct unit_info *w;
499
500                         n_units = MAX(2*c, 16);
501                         w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
502
503                         if (!w) {
504                                 log_error("Failed to allocate unit array.");
505                                 r = -ENOMEM;
506                                 goto finish;
507                         }
508
509                         unit_infos = w;
510                 }
511
512                 u = unit_infos+c;
513
514                 dbus_message_iter_recurse(&sub, &sub2);
515
516                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
517                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
518                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
519                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
520                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
521                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
522                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
523                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
524                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
525                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
526                         log_error("Failed to parse reply.");
527                         r = -EIO;
528                         goto finish;
529                 }
530
531                 dbus_message_iter_next(&sub);
532                 c++;
533         }
534
535         if (c > 0) {
536                 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
537                 output_units_list(unit_infos, c);
538         }
539
540         r = 0;
541
542 finish:
543         if (m)
544                 dbus_message_unref(m);
545
546         if (reply)
547                 dbus_message_unref(reply);
548
549         free(unit_infos);
550
551         dbus_error_free(&error);
552
553         return r;
554 }
555
556 static int compare_unit_file_list(const void *a, const void *b) {
557         const char *d1, *d2;
558         const UnitFileList *u = a, *v = b;
559
560         d1 = strrchr(u->path, '.');
561         d2 = strrchr(v->path, '.');
562
563         if (d1 && d2) {
564                 int r;
565
566                 r = strcasecmp(d1, d2);
567                 if (r != 0)
568                         return r;
569         }
570
571         return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
572 }
573
574 static bool output_show_unit_file(const UnitFileList *u) {
575         const char *dot;
576
577         return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
578 }
579
580 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
581         unsigned max_id_len, id_cols, state_cols, n_shown = 0;
582         const UnitFileList *u;
583
584         max_id_len = sizeof("UNIT FILE")-1;
585         state_cols = sizeof("STATE")-1;
586         for (u = units; u < units + c; u++) {
587                 if (!output_show_unit_file(u))
588                         continue;
589
590                 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
591                 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
592         }
593
594         if (!arg_full) {
595                 unsigned basic_cols;
596                 id_cols = MIN(max_id_len, 25);
597                 basic_cols = 1 + id_cols + state_cols;
598                 if (basic_cols < (unsigned) columns())
599                         id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
600         } else
601                 id_cols = max_id_len;
602
603         if (!arg_no_legend)
604                 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
605
606         for (u = units; u < units + c; u++) {
607                 char *e;
608                 const char *on, *off;
609                 const char *id;
610
611                 if (!output_show_unit_file(u))
612                         continue;
613
614                 n_shown++;
615
616                 if (u->state == UNIT_FILE_MASKED ||
617                     u->state == UNIT_FILE_MASKED_RUNTIME ||
618                     u->state == UNIT_FILE_DISABLED) {
619                         on  = ansi_highlight_red(true);
620                         off = ansi_highlight_red(false);
621                 } else if (u->state == UNIT_FILE_ENABLED) {
622                         on  = ansi_highlight_green(true);
623                         off = ansi_highlight_green(false);
624                 } else
625                         on = off = "";
626
627                 id = path_get_file_name(u->path);
628
629                 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
630
631                 printf("%-*s %s%-*s%s\n",
632                        id_cols, e ? e : id,
633                        on, state_cols, unit_file_state_to_string(u->state), off);
634
635                 free(e);
636         }
637
638         if (!arg_no_legend)
639                 printf("\n%u unit files listed.\n", n_shown);
640 }
641
642 static int list_unit_files(DBusConnection *bus, char **args) {
643         DBusMessage *m = NULL, *reply = NULL;
644         DBusError error;
645         int r;
646         DBusMessageIter iter, sub, sub2;
647         unsigned c = 0, n_units = 0;
648         UnitFileList *units = NULL;
649
650         dbus_error_init(&error);
651
652         pager_open_if_enabled();
653
654         if (avoid_bus()) {
655                 Hashmap *h;
656                 UnitFileList *u;
657                 Iterator i;
658
659                 h = hashmap_new(string_hash_func, string_compare_func);
660                 if (!h) {
661                         log_error("Out of memory");
662                         return -ENOMEM;
663                 }
664
665                 r = unit_file_get_list(arg_scope, arg_root, h);
666                 if (r < 0) {
667                         unit_file_list_free(h);
668                         log_error("Failed to get unit file list: %s", strerror(-r));
669                         return r;
670                 }
671
672                 n_units = hashmap_size(h);
673                 units = new(UnitFileList, n_units);
674                 if (!units) {
675                         unit_file_list_free(h);
676                         log_error("Out of memory");
677                         return -ENOMEM;
678                 }
679
680                 HASHMAP_FOREACH(u, h, i) {
681                         memcpy(units + c++, u, sizeof(UnitFileList));
682                         free(u);
683                 }
684
685                 hashmap_free(h);
686         } else {
687                 assert(bus);
688
689                 m = dbus_message_new_method_call(
690                                 "org.freedesktop.systemd1",
691                                 "/org/freedesktop/systemd1",
692                                 "org.freedesktop.systemd1.Manager",
693                                 "ListUnitFiles");
694                 if (!m) {
695                         log_error("Could not allocate message.");
696                         return -ENOMEM;
697                 }
698
699                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
700                 if (!reply) {
701                         log_error("Failed to issue method call: %s", bus_error_message(&error));
702                         r = -EIO;
703                         goto finish;
704                 }
705
706                 if (!dbus_message_iter_init(reply, &iter) ||
707                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
708                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
709                         log_error("Failed to parse reply.");
710                         r = -EIO;
711                         goto finish;
712                 }
713
714                 dbus_message_iter_recurse(&iter, &sub);
715
716                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
717                         UnitFileList *u;
718                         const char *state;
719
720                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
721                                 log_error("Failed to parse reply.");
722                                 r = -EIO;
723                                 goto finish;
724                         }
725
726                         if (c >= n_units) {
727                                 UnitFileList *w;
728
729                                 n_units = MAX(2*c, 16);
730                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
731
732                                 if (!w) {
733                                         log_error("Failed to allocate unit array.");
734                                         r = -ENOMEM;
735                                         goto finish;
736                                 }
737
738                                 units = w;
739                         }
740
741                         u = units+c;
742
743                         dbus_message_iter_recurse(&sub, &sub2);
744
745                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
746                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
747                                 log_error("Failed to parse reply.");
748                                 r = -EIO;
749                                 goto finish;
750                         }
751
752                         u->state = unit_file_state_from_string(state);
753
754                         dbus_message_iter_next(&sub);
755                         c++;
756                 }
757         }
758
759         if (c > 0) {
760                 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
761                 output_unit_file_list(units, c);
762         }
763
764         r = 0;
765
766 finish:
767         if (m)
768                 dbus_message_unref(m);
769
770         if (reply)
771                 dbus_message_unref(reply);
772
773         free(units);
774
775         dbus_error_free(&error);
776
777         return r;
778 }
779
780 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
781         static const char * const colors[] = {
782                 "Requires",              "[color=\"black\"]",
783                 "RequiresOverridable",   "[color=\"black\"]",
784                 "Requisite",             "[color=\"darkblue\"]",
785                 "RequisiteOverridable",  "[color=\"darkblue\"]",
786                 "Wants",                 "[color=\"grey66\"]",
787                 "Conflicts",             "[color=\"red\"]",
788                 "ConflictedBy",          "[color=\"red\"]",
789                 "After",                 "[color=\"green\"]"
790         };
791
792         const char *c = NULL;
793         unsigned i;
794
795         assert(name);
796         assert(prop);
797         assert(iter);
798
799         for (i = 0; i < ELEMENTSOF(colors); i += 2)
800                 if (streq(colors[i], prop)) {
801                         c = colors[i+1];
802                         break;
803                 }
804
805         if (!c)
806                 return 0;
807
808         if (arg_dot != DOT_ALL)
809                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
810                         return 0;
811
812         switch (dbus_message_iter_get_arg_type(iter)) {
813
814         case DBUS_TYPE_ARRAY:
815
816                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
817                         DBusMessageIter sub;
818
819                         dbus_message_iter_recurse(iter, &sub);
820
821                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
822                                 const char *s;
823
824                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
825                                 dbus_message_iter_get_basic(&sub, &s);
826                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
827
828                                 dbus_message_iter_next(&sub);
829                         }
830
831                         return 0;
832                 }
833         }
834
835         return 0;
836 }
837
838 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
839         DBusMessage *m = NULL, *reply = NULL;
840         const char *interface = "org.freedesktop.systemd1.Unit";
841         int r;
842         DBusError error;
843         DBusMessageIter iter, sub, sub2, sub3;
844
845         assert(bus);
846         assert(path);
847
848         dbus_error_init(&error);
849
850         if (!(m = dbus_message_new_method_call(
851                               "org.freedesktop.systemd1",
852                               path,
853                               "org.freedesktop.DBus.Properties",
854                               "GetAll"))) {
855                 log_error("Could not allocate message.");
856                 r = -ENOMEM;
857                 goto finish;
858         }
859
860         if (!dbus_message_append_args(m,
861                                       DBUS_TYPE_STRING, &interface,
862                                       DBUS_TYPE_INVALID)) {
863                 log_error("Could not append arguments to message.");
864                 r = -ENOMEM;
865                 goto finish;
866         }
867
868         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
869                 log_error("Failed to issue method call: %s", bus_error_message(&error));
870                 r = -EIO;
871                 goto finish;
872         }
873
874         if (!dbus_message_iter_init(reply, &iter) ||
875             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
876             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
877                 log_error("Failed to parse reply.");
878                 r = -EIO;
879                 goto finish;
880         }
881
882         dbus_message_iter_recurse(&iter, &sub);
883
884         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
885                 const char *prop;
886
887                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
888                         log_error("Failed to parse reply.");
889                         r = -EIO;
890                         goto finish;
891                 }
892
893                 dbus_message_iter_recurse(&sub, &sub2);
894
895                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
896                         log_error("Failed to parse reply.");
897                         r = -EIO;
898                         goto finish;
899                 }
900
901                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
902                         log_error("Failed to parse reply.");
903                         r = -EIO;
904                         goto finish;
905                 }
906
907                 dbus_message_iter_recurse(&sub2, &sub3);
908
909                 if (dot_one_property(name, prop, &sub3)) {
910                         log_error("Failed to parse reply.");
911                         r = -EIO;
912                         goto finish;
913                 }
914
915                 dbus_message_iter_next(&sub);
916         }
917
918         r = 0;
919
920 finish:
921         if (m)
922                 dbus_message_unref(m);
923
924         if (reply)
925                 dbus_message_unref(reply);
926
927         dbus_error_free(&error);
928
929         return r;
930 }
931
932 static int dot(DBusConnection *bus, char **args) {
933         DBusMessage *m = NULL, *reply = NULL;
934         DBusError error;
935         int r;
936         DBusMessageIter iter, sub, sub2;
937
938         dbus_error_init(&error);
939
940         assert(bus);
941
942         if (!(m = dbus_message_new_method_call(
943                               "org.freedesktop.systemd1",
944                               "/org/freedesktop/systemd1",
945                               "org.freedesktop.systemd1.Manager",
946                               "ListUnits"))) {
947                 log_error("Could not allocate message.");
948                 return -ENOMEM;
949         }
950
951         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
952                 log_error("Failed to issue method call: %s", bus_error_message(&error));
953                 r = -EIO;
954                 goto finish;
955         }
956
957         if (!dbus_message_iter_init(reply, &iter) ||
958             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
959             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
960                 log_error("Failed to parse reply.");
961                 r = -EIO;
962                 goto finish;
963         }
964
965         printf("digraph systemd {\n");
966
967         dbus_message_iter_recurse(&iter, &sub);
968         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
969                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
970
971                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
972                         log_error("Failed to parse reply.");
973                         r = -EIO;
974                         goto finish;
975                 }
976
977                 dbus_message_iter_recurse(&sub, &sub2);
978
979                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
980                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
981                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
982                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
983                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
984                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
985                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
986                         log_error("Failed to parse reply.");
987                         r = -EIO;
988                         goto finish;
989                 }
990
991                 if ((r = dot_one(bus, id, unit_path)) < 0)
992                         goto finish;
993
994                 /* printf("\t\"%s\";\n", id); */
995                 dbus_message_iter_next(&sub);
996         }
997
998         printf("}\n");
999
1000         log_info("   Color legend: black     = Requires\n"
1001                  "                 dark blue = Requisite\n"
1002                  "                 dark grey = Wants\n"
1003                  "                 red       = Conflicts\n"
1004                  "                 green     = After\n");
1005
1006         if (on_tty())
1007                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
1008                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
1009
1010         r = 0;
1011
1012 finish:
1013         if (m)
1014                 dbus_message_unref(m);
1015
1016         if (reply)
1017                 dbus_message_unref(reply);
1018
1019         dbus_error_free(&error);
1020
1021         return r;
1022 }
1023
1024 static int list_jobs(DBusConnection *bus, char **args) {
1025         DBusMessage *m = NULL, *reply = NULL;
1026         DBusError error;
1027         int r;
1028         DBusMessageIter iter, sub, sub2;
1029         unsigned k = 0;
1030
1031         dbus_error_init(&error);
1032
1033         assert(bus);
1034
1035         pager_open_if_enabled();
1036
1037         if (!(m = dbus_message_new_method_call(
1038                               "org.freedesktop.systemd1",
1039                               "/org/freedesktop/systemd1",
1040                               "org.freedesktop.systemd1.Manager",
1041                               "ListJobs"))) {
1042                 log_error("Could not allocate message.");
1043                 return -ENOMEM;
1044         }
1045
1046         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1047                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1048                 r = -EIO;
1049                 goto finish;
1050         }
1051
1052         if (!dbus_message_iter_init(reply, &iter) ||
1053             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1054             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
1055                 log_error("Failed to parse reply.");
1056                 r = -EIO;
1057                 goto finish;
1058         }
1059
1060         dbus_message_iter_recurse(&iter, &sub);
1061
1062         if (on_tty())
1063                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1064
1065         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1066                 const char *name, *type, *state, *job_path, *unit_path;
1067                 uint32_t id;
1068                 char *e;
1069
1070                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1071                         log_error("Failed to parse reply.");
1072                         r = -EIO;
1073                         goto finish;
1074                 }
1075
1076                 dbus_message_iter_recurse(&sub, &sub2);
1077
1078                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1079                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1080                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1081                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1082                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1083                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1084                         log_error("Failed to parse reply.");
1085                         r = -EIO;
1086                         goto finish;
1087                 }
1088
1089                 e = arg_full ? NULL : ellipsize(name, 25, 33);
1090                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1091                 free(e);
1092
1093                 k++;
1094
1095                 dbus_message_iter_next(&sub);
1096         }
1097
1098         if (on_tty())
1099                 printf("\n%u jobs listed.\n", k);
1100
1101         r = 0;
1102
1103 finish:
1104         if (m)
1105                 dbus_message_unref(m);
1106
1107         if (reply)
1108                 dbus_message_unref(reply);
1109
1110         dbus_error_free(&error);
1111
1112         return r;
1113 }
1114
1115 static int load_unit(DBusConnection *bus, char **args) {
1116         DBusMessage *m = NULL;
1117         DBusError error;
1118         int r;
1119         char **name;
1120
1121         dbus_error_init(&error);
1122
1123         assert(bus);
1124         assert(args);
1125
1126         STRV_FOREACH(name, args+1) {
1127                 DBusMessage *reply;
1128                 bool b;
1129                 char *n;
1130
1131                 if (!(m = dbus_message_new_method_call(
1132                                       "org.freedesktop.systemd1",
1133                                       "/org/freedesktop/systemd1",
1134                                       "org.freedesktop.systemd1.Manager",
1135                                       "LoadUnit"))) {
1136                         log_error("Could not allocate message.");
1137                         r = -ENOMEM;
1138                         goto finish;
1139                 }
1140
1141                 n = unit_name_mangle(*name);
1142                 b = dbus_message_append_args(m,
1143                                              DBUS_TYPE_STRING, n ? &n : name,
1144                                              DBUS_TYPE_INVALID);
1145                 free(n);
1146                 if (!b) {
1147                         log_error("Could not append arguments to message.");
1148                         r = -ENOMEM;
1149                         goto finish;
1150                 }
1151
1152                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1153                 if (!reply) {
1154                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1155                         r = -EIO;
1156                         goto finish;
1157                 }
1158
1159                 dbus_message_unref(m);
1160                 dbus_message_unref(reply);
1161
1162                 m = reply = NULL;
1163         }
1164
1165         r = 0;
1166
1167 finish:
1168         if (m)
1169                 dbus_message_unref(m);
1170
1171         dbus_error_free(&error);
1172
1173         return r;
1174 }
1175
1176 static int cancel_job(DBusConnection *bus, char **args) {
1177         DBusMessage *m = NULL, *reply = NULL;
1178         DBusError error;
1179         int r;
1180         char **name;
1181
1182         dbus_error_init(&error);
1183
1184         assert(bus);
1185         assert(args);
1186
1187         if (strv_length(args) <= 1)
1188                 return daemon_reload(bus, args);
1189
1190         STRV_FOREACH(name, args+1) {
1191                 unsigned id;
1192                 const char *path;
1193
1194                 if (!(m = dbus_message_new_method_call(
1195                                       "org.freedesktop.systemd1",
1196                                       "/org/freedesktop/systemd1",
1197                                       "org.freedesktop.systemd1.Manager",
1198                                       "GetJob"))) {
1199                         log_error("Could not allocate message.");
1200                         r = -ENOMEM;
1201                         goto finish;
1202                 }
1203
1204                 if ((r = safe_atou(*name, &id)) < 0) {
1205                         log_error("Failed to parse job id: %s", strerror(-r));
1206                         goto finish;
1207                 }
1208
1209                 assert_cc(sizeof(uint32_t) == sizeof(id));
1210                 if (!dbus_message_append_args(m,
1211                                               DBUS_TYPE_UINT32, &id,
1212                                               DBUS_TYPE_INVALID)) {
1213                         log_error("Could not append arguments to message.");
1214                         r = -ENOMEM;
1215                         goto finish;
1216                 }
1217
1218                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1219                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1220                         r = -EIO;
1221                         goto finish;
1222                 }
1223
1224                 if (!dbus_message_get_args(reply, &error,
1225                                            DBUS_TYPE_OBJECT_PATH, &path,
1226                                            DBUS_TYPE_INVALID)) {
1227                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1228                         r = -EIO;
1229                         goto finish;
1230                 }
1231
1232                 dbus_message_unref(m);
1233                 if (!(m = dbus_message_new_method_call(
1234                                       "org.freedesktop.systemd1",
1235                                       path,
1236                                       "org.freedesktop.systemd1.Job",
1237                                       "Cancel"))) {
1238                         log_error("Could not allocate message.");
1239                         r = -ENOMEM;
1240                         goto finish;
1241                 }
1242
1243                 dbus_message_unref(reply);
1244                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1245                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1246                         r = -EIO;
1247                         goto finish;
1248                 }
1249
1250                 dbus_message_unref(m);
1251                 dbus_message_unref(reply);
1252                 m = reply = NULL;
1253         }
1254
1255         r = 0;
1256
1257 finish:
1258         if (m)
1259                 dbus_message_unref(m);
1260
1261         if (reply)
1262                 dbus_message_unref(reply);
1263
1264         dbus_error_free(&error);
1265
1266         return r;
1267 }
1268
1269 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1270         DBusMessage *m = NULL, *reply = NULL;
1271         dbus_bool_t b = FALSE;
1272         DBusMessageIter iter, sub;
1273         const char
1274                 *interface = "org.freedesktop.systemd1.Unit",
1275                 *property = "NeedDaemonReload",
1276                 *path;
1277         char *n;
1278         bool k;
1279
1280         /* We ignore all errors here, since this is used to show a warning only */
1281
1282         m = dbus_message_new_method_call(
1283                               "org.freedesktop.systemd1",
1284                               "/org/freedesktop/systemd1",
1285                               "org.freedesktop.systemd1.Manager",
1286                               "GetUnit");
1287         if (!m)
1288                 goto finish;
1289
1290         n = unit_name_mangle(unit);
1291         k = dbus_message_append_args(m,
1292                                      DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
1293                                      DBUS_TYPE_INVALID);
1294         free(n);
1295         if (!k)
1296                 goto finish;
1297
1298         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL);
1299         if (!reply)
1300                 goto finish;
1301
1302         if (!dbus_message_get_args(reply, NULL,
1303                                    DBUS_TYPE_OBJECT_PATH, &path,
1304                                    DBUS_TYPE_INVALID))
1305                 goto finish;
1306
1307         dbus_message_unref(m);
1308         m = dbus_message_new_method_call(
1309                         "org.freedesktop.systemd1",
1310                         path,
1311                         "org.freedesktop.DBus.Properties",
1312                         "Get");
1313         if (!m)
1314                 goto finish;
1315
1316         if (!dbus_message_append_args(m,
1317                                       DBUS_TYPE_STRING, &interface,
1318                                       DBUS_TYPE_STRING, &property,
1319                                       DBUS_TYPE_INVALID)) {
1320                 goto finish;
1321         }
1322
1323         dbus_message_unref(reply);
1324         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL);
1325         if (!reply)
1326                 goto finish;
1327
1328         if (!dbus_message_iter_init(reply, &iter) ||
1329             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1330                 goto finish;
1331
1332         dbus_message_iter_recurse(&iter, &sub);
1333
1334         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1335                 goto finish;
1336
1337         dbus_message_iter_get_basic(&sub, &b);
1338
1339 finish:
1340         if (m)
1341                 dbus_message_unref(m);
1342
1343         if (reply)
1344                 dbus_message_unref(reply);
1345
1346         return b;
1347 }
1348
1349 typedef struct WaitData {
1350         Set *set;
1351         char *result;
1352 } WaitData;
1353
1354 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1355         DBusError error;
1356         WaitData *d = data;
1357
1358         assert(connection);
1359         assert(message);
1360         assert(d);
1361
1362         dbus_error_init(&error);
1363
1364         log_debug("Got D-Bus request: %s.%s() on %s",
1365                   dbus_message_get_interface(message),
1366                   dbus_message_get_member(message),
1367                   dbus_message_get_path(message));
1368
1369         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1370                 log_error("Warning! D-Bus connection terminated.");
1371                 dbus_connection_close(connection);
1372
1373         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1374                 uint32_t id;
1375                 const char *path, *result, *unit;
1376                 dbus_bool_t success = true;
1377
1378                 if (dbus_message_get_args(message, &error,
1379                                           DBUS_TYPE_UINT32, &id,
1380                                           DBUS_TYPE_OBJECT_PATH, &path,
1381                                           DBUS_TYPE_STRING, &unit,
1382                                           DBUS_TYPE_STRING, &result,
1383                                           DBUS_TYPE_INVALID)) {
1384                         char *p;
1385
1386                         p = set_remove(d->set, (char*) path);
1387                         free(p);
1388
1389                         if (*result)
1390                                 d->result = strdup(result);
1391
1392                         goto finish;
1393                 }
1394 #ifndef LEGACY
1395                 dbus_error_free(&error);
1396                 if (dbus_message_get_args(message, &error,
1397                                           DBUS_TYPE_UINT32, &id,
1398                                           DBUS_TYPE_OBJECT_PATH, &path,
1399                                           DBUS_TYPE_STRING, &result,
1400                                           DBUS_TYPE_INVALID)) {
1401                         char *p;
1402
1403                         /* Compatibility with older systemd versions <
1404                          * 183 during upgrades. This should be dropped
1405                          * one day. */
1406                         p = set_remove(d->set, (char*) path);
1407                         free(p);
1408
1409                         if (*result)
1410                                 d->result = strdup(result);
1411
1412                         goto finish;
1413                 }
1414
1415                 dbus_error_free(&error);
1416                 if (dbus_message_get_args(message, &error,
1417                                           DBUS_TYPE_UINT32, &id,
1418                                           DBUS_TYPE_OBJECT_PATH, &path,
1419                                           DBUS_TYPE_BOOLEAN, &success,
1420                                           DBUS_TYPE_INVALID)) {
1421                         char *p;
1422
1423                         /* Compatibility with older systemd versions <
1424                          * 19 during upgrades. This should be dropped
1425                          * one day */
1426
1427                         p = set_remove(d->set, (char*) path);
1428                         free(p);
1429
1430                         if (!success)
1431                                 d->result = strdup("failed");
1432
1433                         goto finish;
1434                 }
1435 #endif
1436
1437                 log_error("Failed to parse message: %s", bus_error_message(&error));
1438         }
1439
1440 finish:
1441         dbus_error_free(&error);
1442         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1443 }
1444
1445 static int enable_wait_for_jobs(DBusConnection *bus) {
1446         DBusError error;
1447
1448         assert(bus);
1449
1450         if (private_bus)
1451                 return 0;
1452
1453         dbus_error_init(&error);
1454         dbus_bus_add_match(bus,
1455                            "type='signal',"
1456                            "sender='org.freedesktop.systemd1',"
1457                            "interface='org.freedesktop.systemd1.Manager',"
1458                            "member='JobRemoved',"
1459                            "path='/org/freedesktop/systemd1'",
1460                            &error);
1461
1462         if (dbus_error_is_set(&error)) {
1463                 log_error("Failed to add match: %s", bus_error_message(&error));
1464                 dbus_error_free(&error);
1465                 return -EIO;
1466         }
1467
1468         /* This is slightly dirty, since we don't undo the match registrations. */
1469         return 0;
1470 }
1471
1472 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1473         int r;
1474         WaitData d;
1475
1476         assert(bus);
1477         assert(s);
1478
1479         zero(d);
1480         d.set = s;
1481
1482         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1483                 log_error("Failed to add filter.");
1484                 r = -ENOMEM;
1485                 goto finish;
1486         }
1487
1488         while (!set_isempty(s) &&
1489                dbus_connection_read_write_dispatch(bus, -1))
1490                 ;
1491
1492         if (!arg_quiet && d.result) {
1493                 if (streq(d.result, "timeout"))
1494                         log_error("Job timed out.");
1495                 else if (streq(d.result, "canceled"))
1496                         log_error("Job canceled.");
1497                 else if (streq(d.result, "dependency"))
1498                         log_error("A dependency job failed. See system journal for details.");
1499                 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1500                         log_error("Job failed. See system journal and 'systemctl status' for details.");
1501         }
1502
1503         if (streq_ptr(d.result, "timeout"))
1504                 r = -ETIME;
1505         else if (streq_ptr(d.result, "canceled"))
1506                 r = -ECANCELED;
1507         else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1508                 r = -EIO;
1509         else
1510                 r = 0;
1511
1512         free(d.result);
1513
1514 finish:
1515         /* This is slightly dirty, since we don't undo the filter registration. */
1516
1517         return r;
1518 }
1519
1520 static int check_one_unit(DBusConnection *bus, char *name, bool quiet) {
1521         DBusMessage *m = NULL, *reply = NULL;
1522         DBusError error;
1523         DBusMessageIter iter, sub;
1524         const char
1525                 *interface = "org.freedesktop.systemd1.Unit",
1526                 *property = "ActiveState";
1527         const char *path = NULL;
1528         const char *state;
1529         int r = 3; /* According to LSB: "program is not running" */
1530         char *n;
1531         bool b;
1532
1533         assert(bus);
1534         assert(name);
1535
1536         dbus_error_init(&error);
1537
1538         m = dbus_message_new_method_call(
1539                               "org.freedesktop.systemd1",
1540                               "/org/freedesktop/systemd1",
1541                               "org.freedesktop.systemd1.Manager",
1542                               "GetUnit");
1543         if (!m) {
1544                 log_error("Could not allocate message.");
1545                 r = -ENOMEM;
1546                 goto finish;
1547         }
1548
1549         n = unit_name_mangle(name);
1550         b = dbus_message_append_args(m,
1551                                      DBUS_TYPE_STRING, n ? &n : &name,
1552                                      DBUS_TYPE_INVALID);
1553         free(n);
1554         if (!b) {
1555                 log_error("Could not append arguments to message.");
1556                 r = -ENOMEM;
1557                 goto finish;
1558         }
1559
1560         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1561         if (!reply) {
1562                 /* Hmm, cannot figure out anything about this unit... */
1563                 if (!quiet)
1564                         puts("unknown");
1565
1566                 goto finish;
1567         }
1568
1569         if (!dbus_message_get_args(reply, &error,
1570                                    DBUS_TYPE_OBJECT_PATH, &path,
1571                                    DBUS_TYPE_INVALID)) {
1572                 log_error("Failed to parse reply: %s", bus_error_message(&error));
1573                 r = -EIO;
1574                 goto finish;
1575         }
1576
1577         dbus_message_unref(m);
1578         m = dbus_message_new_method_call(
1579                               "org.freedesktop.systemd1",
1580                               path,
1581                               "org.freedesktop.DBus.Properties",
1582                               "Get");
1583         if (!m) {
1584                 log_error("Could not allocate message.");
1585                 r = -ENOMEM;
1586                 goto finish;
1587         }
1588
1589         if (!dbus_message_append_args(m,
1590                                       DBUS_TYPE_STRING, &interface,
1591                                       DBUS_TYPE_STRING, &property,
1592                                       DBUS_TYPE_INVALID)) {
1593                 log_error("Could not append arguments to message.");
1594                 r = -ENOMEM;
1595                 goto finish;
1596         }
1597
1598         dbus_message_unref(reply);
1599         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1600         if (!reply) {
1601                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1602                 r = -EIO;
1603                 goto finish;
1604         }
1605
1606         if (!dbus_message_iter_init(reply, &iter) ||
1607             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1608                 log_error("Failed to parse reply.");
1609                 r = -EIO;
1610                 goto finish;
1611         }
1612
1613         dbus_message_iter_recurse(&iter, &sub);
1614
1615         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1616                 log_error("Failed to parse reply.");
1617                 r = -EIO;
1618                 goto finish;
1619         }
1620
1621         dbus_message_iter_get_basic(&sub, &state);
1622
1623         if (!quiet)
1624                 puts(state);
1625
1626         if (streq(state, "active") || streq(state, "reloading"))
1627                 r = 0;
1628
1629 finish:
1630         if (m)
1631                 dbus_message_unref(m);
1632
1633         if (reply)
1634                 dbus_message_unref(reply);
1635
1636         dbus_error_free(&error);
1637
1638         return r;
1639 }
1640
1641 static void check_triggering_units(
1642                 DBusConnection *bus,
1643                 const char *unit_name) {
1644
1645         DBusError error;
1646         DBusMessage *m = NULL, *reply = NULL;
1647         DBusMessageIter iter, sub;
1648         char *service_trigger = NULL;
1649         const char *interface = "org.freedesktop.systemd1.Unit",
1650                    *triggered_by_property = "TriggeredBy";
1651
1652         char *unit_path = NULL, *n = NULL;
1653         bool print_warning_label = true;
1654
1655         dbus_error_init(&error);
1656
1657         n = unit_name_mangle(unit_name);
1658         unit_path = unit_dbus_path_from_name(n ? n : unit_name);
1659         free(n);
1660         if (!unit_path) {
1661                 log_error("Could not allocate dbus path.");
1662                 goto finish;
1663         }
1664
1665         m = dbus_message_new_method_call("org.freedesktop.systemd1",
1666                                          unit_path,
1667                                          "org.freedesktop.DBus.Properties",
1668                                          "Get");
1669         if (!m) {
1670                 log_error("Could not allocate message.");
1671                 goto finish;
1672         }
1673
1674         if (!dbus_message_append_args(m,
1675                                       DBUS_TYPE_STRING, &interface,
1676                                       DBUS_TYPE_STRING, &triggered_by_property,
1677                                       DBUS_TYPE_INVALID)) {
1678                 log_error("Could not append arguments to message.");
1679                 goto finish;
1680         }
1681
1682         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1683         if (!reply) {
1684                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1685                 goto finish;
1686         }
1687
1688         if (!dbus_message_iter_init(reply, &iter) ||
1689             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1690                 log_error("Failed to parse reply: %s", bus_error_message(&error));
1691                 goto finish;
1692
1693         }
1694
1695         dbus_message_iter_recurse(&iter, &sub);
1696         dbus_message_iter_recurse(&sub, &iter);
1697         sub = iter;
1698
1699         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1700                 int r;
1701
1702                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1703                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1704                         goto finish;
1705                 }
1706
1707                 dbus_message_iter_get_basic(&sub, &service_trigger);
1708
1709                 r = check_one_unit(bus, service_trigger, true);
1710                 if (r < 0)
1711                         goto finish;
1712                 if (r == 0) {
1713                         if (print_warning_label) {
1714                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1715                                 print_warning_label = false;
1716                         }
1717                         log_warning("  %s", service_trigger);
1718                 }
1719
1720                 dbus_message_iter_next(&sub);
1721         }
1722 finish:
1723         if (m)
1724                 dbus_message_unref(m);
1725
1726         if (reply)
1727                 dbus_message_unref(reply);
1728
1729         dbus_error_free(&error);
1730
1731         free(unit_path);
1732 }
1733
1734 static int start_unit_one(
1735                 DBusConnection *bus,
1736                 const char *method,
1737                 const char *name,
1738                 const char *mode,
1739                 DBusError *error,
1740                 Set *s) {
1741
1742         DBusMessage *m = NULL, *reply = NULL;
1743         const char *path;
1744         int r;
1745         char *n;
1746         bool b;
1747
1748         assert(bus);
1749         assert(method);
1750         assert(name);
1751         assert(mode);
1752         assert(error);
1753         assert(arg_no_block || s);
1754
1755         m = dbus_message_new_method_call(
1756                         "org.freedesktop.systemd1",
1757                         "/org/freedesktop/systemd1",
1758                         "org.freedesktop.systemd1.Manager",
1759                         method);
1760         if (!m) {
1761                 log_error("Could not allocate message.");
1762                 r = -ENOMEM;
1763                 goto finish;
1764         }
1765
1766         n = unit_name_mangle(name);
1767         b = dbus_message_append_args(m,
1768                                      DBUS_TYPE_STRING, n ? (const char **) &n : &name,
1769                                      DBUS_TYPE_STRING, &mode,
1770                                      DBUS_TYPE_INVALID);
1771         free(n);
1772         if (!b) {
1773                 log_error("Could not append arguments to message.");
1774                 r = -ENOMEM;
1775                 goto finish;
1776         }
1777
1778         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
1779         if (!reply) {
1780
1781                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1782                         /* There's always a fallback possible for
1783                          * legacy actions. */
1784                         r = -EADDRNOTAVAIL;
1785                         goto finish;
1786                 }
1787
1788                 log_error("Failed to issue method call: %s", bus_error_message(error));
1789                 r = -EIO;
1790                 goto finish;
1791         }
1792
1793         if (!dbus_message_get_args(reply, error,
1794                                    DBUS_TYPE_OBJECT_PATH, &path,
1795                                    DBUS_TYPE_INVALID)) {
1796                 log_error("Failed to parse reply: %s", bus_error_message(error));
1797                 r = -EIO;
1798                 goto finish;
1799         }
1800
1801         if (need_daemon_reload(bus, name))
1802                 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1803                             arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1804
1805         if (!arg_no_block) {
1806                 char *p;
1807
1808                 if (!(p = strdup(path))) {
1809                         log_error("Failed to duplicate path.");
1810                         r = -ENOMEM;
1811                         goto finish;
1812                 }
1813
1814                 if ((r = set_put(s, p)) < 0) {
1815                         free(p);
1816                         log_error("Failed to add path to set.");
1817                         goto finish;
1818                 }
1819         }
1820
1821         /* When stopping a unit warn if it can still be triggered by
1822          * another active unit (socket, path, timer) */
1823         if (!arg_quiet && streq(method, "StopUnit"))
1824                 check_triggering_units(bus, name);
1825
1826         r = 0;
1827
1828 finish:
1829         if (m)
1830                 dbus_message_unref(m);
1831
1832         if (reply)
1833                 dbus_message_unref(reply);
1834
1835         return r;
1836 }
1837
1838 static enum action verb_to_action(const char *verb) {
1839         if (streq(verb, "halt"))
1840                 return ACTION_HALT;
1841         else if (streq(verb, "poweroff"))
1842                 return ACTION_POWEROFF;
1843         else if (streq(verb, "reboot"))
1844                 return ACTION_REBOOT;
1845         else if (streq(verb, "kexec"))
1846                 return ACTION_KEXEC;
1847         else if (streq(verb, "rescue"))
1848                 return ACTION_RESCUE;
1849         else if (streq(verb, "emergency"))
1850                 return ACTION_EMERGENCY;
1851         else if (streq(verb, "default"))
1852                 return ACTION_DEFAULT;
1853         else if (streq(verb, "exit"))
1854                 return ACTION_EXIT;
1855         else if (streq(verb, "suspend"))
1856                 return ACTION_SUSPEND;
1857         else if (streq(verb, "hibernate"))
1858                 return ACTION_HIBERNATE;
1859         else
1860                 return ACTION_INVALID;
1861 }
1862
1863 static int start_unit(DBusConnection *bus, char **args) {
1864
1865         static const char * const table[_ACTION_MAX] = {
1866                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1867                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1868                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1869                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1870                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1871                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1872                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1873                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1874                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1875                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1876                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1877                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1878                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1879                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
1880         };
1881
1882         int r, ret = 0;
1883         const char *method, *mode, *one_name;
1884         Set *s = NULL;
1885         DBusError error;
1886         char **name;
1887
1888         dbus_error_init(&error);
1889
1890         assert(bus);
1891
1892         ask_password_agent_open_if_enabled();
1893
1894         if (arg_action == ACTION_SYSTEMCTL) {
1895                 method =
1896                         streq(args[0], "stop") ||
1897                         streq(args[0], "condstop")              ? "StopUnit" :
1898                         streq(args[0], "reload")                ? "ReloadUnit" :
1899                         streq(args[0], "restart")               ? "RestartUnit" :
1900
1901                         streq(args[0], "try-restart")           ||
1902                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1903
1904                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1905
1906                         streq(args[0], "reload-or-try-restart") ||
1907                         streq(args[0], "condreload") ||
1908
1909                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1910                                                                   "StartUnit";
1911
1912                 mode =
1913                         (streq(args[0], "isolate") ||
1914                          streq(args[0], "rescue")  ||
1915                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1916
1917                 one_name = table[verb_to_action(args[0])];
1918
1919         } else {
1920                 assert(arg_action < ELEMENTSOF(table));
1921                 assert(table[arg_action]);
1922
1923                 method = "StartUnit";
1924
1925                 mode = (arg_action == ACTION_EMERGENCY ||
1926                         arg_action == ACTION_RESCUE ||
1927                         arg_action == ACTION_RUNLEVEL2 ||
1928                         arg_action == ACTION_RUNLEVEL3 ||
1929                         arg_action == ACTION_RUNLEVEL4 ||
1930                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1931
1932                 one_name = table[arg_action];
1933         }
1934
1935         if (!arg_no_block) {
1936                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1937                         log_error("Could not watch jobs: %s", strerror(-ret));
1938                         goto finish;
1939                 }
1940
1941                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1942                         log_error("Failed to allocate set.");
1943                         ret = -ENOMEM;
1944                         goto finish;
1945                 }
1946         }
1947
1948         if (one_name) {
1949                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1950                         goto finish;
1951         } else {
1952                 STRV_FOREACH(name, args+1)
1953                         if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1954                                 ret = translate_bus_error_to_exit_status(r, &error);
1955                                 dbus_error_free(&error);
1956                         }
1957         }
1958
1959         if (!arg_no_block)
1960                 if ((r = wait_for_jobs(bus, s)) < 0) {
1961                         ret = r;
1962                         goto finish;
1963                 }
1964
1965 finish:
1966         if (s)
1967                 set_free_free(s);
1968
1969         dbus_error_free(&error);
1970
1971         return ret;
1972 }
1973
1974 /* Ask systemd-logind, which might grant access to unprivileged users
1975  * through PolicyKit */
1976 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1977 #ifdef HAVE_LOGIND
1978         const char *method;
1979         DBusMessage *m = NULL, *reply = NULL;
1980         DBusError error;
1981         dbus_bool_t interactive = true;
1982         int r;
1983
1984         dbus_error_init(&error);
1985
1986         polkit_agent_open_if_enabled();
1987
1988         switch (a) {
1989
1990         case ACTION_REBOOT:
1991                 method = "Reboot";
1992                 break;
1993
1994         case ACTION_POWEROFF:
1995                 method = "PowerOff";
1996                 break;
1997
1998         case ACTION_SUSPEND:
1999                 method = "Suspend";
2000                 break;
2001
2002         case ACTION_HIBERNATE:
2003                 method = "Hibernate";
2004                 break;
2005
2006         default:
2007                 return -EINVAL;
2008         }
2009
2010         m = dbus_message_new_method_call(
2011                                 "org.freedesktop.login1",
2012                                 "/org/freedesktop/login1",
2013                                 "org.freedesktop.login1.Manager",
2014                                 method);
2015         if (!m) {
2016                 log_error("Could not allocate message.");
2017                 r = -ENOMEM;
2018                 goto finish;
2019         }
2020
2021         if (!dbus_message_append_args(m,
2022                                       DBUS_TYPE_BOOLEAN, &interactive,
2023                                       DBUS_TYPE_INVALID)) {
2024                 log_error("Could not append arguments to message.");
2025                 r = -ENOMEM;
2026                 goto finish;
2027         }
2028
2029         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2030         if (!reply) {
2031                 if (error_is_no_service(&error)) {
2032                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
2033                         r = -ENOENT;
2034                         goto finish;
2035                 }
2036
2037                 if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2038                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
2039                         r = -EACCES;
2040                         goto finish;
2041                 }
2042
2043                 log_info("Failed to issue method call: %s", bus_error_message(&error));
2044                 r = -EIO;
2045                 goto finish;
2046         }
2047
2048         r = 0;
2049
2050 finish:
2051         if (m)
2052                 dbus_message_unref(m);
2053
2054         if (reply)
2055                 dbus_message_unref(reply);
2056
2057         dbus_error_free(&error);
2058
2059         return r;
2060 #else
2061         return -ENOSYS;
2062 #endif
2063 }
2064
2065 static int start_special(DBusConnection *bus, char **args) {
2066         enum action a;
2067         int r;
2068
2069         assert(args);
2070
2071         a = verb_to_action(args[0]);
2072
2073         if (arg_force >= 2 && geteuid() != 0) {
2074                 log_error("Must be root.");
2075                 return -EPERM;
2076         }
2077
2078         if (arg_force >= 2 &&
2079             (a == ACTION_HALT ||
2080              a == ACTION_POWEROFF ||
2081              a == ACTION_REBOOT))
2082                 halt_now(a);
2083
2084         if (arg_force >= 1 &&
2085             (a == ACTION_HALT ||
2086              a == ACTION_POWEROFF ||
2087              a == ACTION_REBOOT ||
2088              a == ACTION_KEXEC ||
2089              a == ACTION_EXIT))
2090                 return daemon_reload(bus, args);
2091
2092         /* first try logind, to allow authentication with polkit */
2093         if (geteuid() != 0 &&
2094             (a == ACTION_POWEROFF ||
2095              a == ACTION_REBOOT ||
2096              a == ACTION_SUSPEND ||
2097              a == ACTION_HIBERNATE)) {
2098                 r = reboot_with_logind(bus, a);
2099                 if (r >= 0)
2100                         return r;
2101         }
2102
2103         r = start_unit(bus, args);
2104         if (r >= 0)
2105                 warn_wall(a);
2106
2107         return r;
2108 }
2109
2110 static int check_unit(DBusConnection *bus, char **args) {
2111         char **name;
2112         int r = 3; /* According to LSB: "program is not running" */
2113
2114         assert(bus);
2115         assert(args);
2116
2117         STRV_FOREACH(name, args+1) {
2118                 int state = check_one_unit(bus, *name, arg_quiet);
2119                 if (state < 0)
2120                         return state;
2121                 if (state == 0)
2122                         r = 0;
2123         }
2124
2125         return r;
2126 }
2127
2128 static int kill_unit(DBusConnection *bus, char **args) {
2129         DBusMessage *m = NULL;
2130         int r = 0;
2131         DBusError error;
2132         char **name;
2133
2134         assert(bus);
2135         assert(args);
2136
2137         dbus_error_init(&error);
2138
2139         if (!arg_kill_who)
2140                 arg_kill_who = "all";
2141
2142         STRV_FOREACH(name, args+1) {
2143                 DBusMessage *reply;
2144                 char *n;
2145                 bool b;
2146
2147                 m = dbus_message_new_method_call(
2148                                 "org.freedesktop.systemd1",
2149                                 "/org/freedesktop/systemd1",
2150                                 "org.freedesktop.systemd1.Manager",
2151                                 "KillUnit");
2152                 if (!m) {
2153                         log_error("Could not allocate message.");
2154                         r = -ENOMEM;
2155                         goto finish;
2156                 }
2157
2158                 n = unit_name_mangle(*name);
2159                 b = dbus_message_append_args(m,
2160                                              DBUS_TYPE_STRING, n ? &n : name,
2161                                              DBUS_TYPE_STRING, &arg_kill_who,
2162                                              DBUS_TYPE_INT32, &arg_signal,
2163                                              DBUS_TYPE_INVALID);
2164                 free(n);
2165                 if (!b) {
2166                         log_error("Could not append arguments to message.");
2167                         r = -ENOMEM;
2168                         goto finish;
2169                 }
2170
2171                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2172                 if (!reply) {
2173                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2174                         dbus_error_free(&error);
2175                         r = -EIO;
2176                 }
2177
2178                 dbus_message_unref(m);
2179
2180                 if (reply)
2181                         dbus_message_unref(reply);
2182                 m = reply = NULL;
2183         }
2184
2185 finish:
2186         if (m)
2187                 dbus_message_unref(m);
2188
2189         dbus_error_free(&error);
2190
2191         return r;
2192 }
2193
2194 typedef struct ExecStatusInfo {
2195         char *name;
2196
2197         char *path;
2198         char **argv;
2199
2200         bool ignore;
2201
2202         usec_t start_timestamp;
2203         usec_t exit_timestamp;
2204         pid_t pid;
2205         int code;
2206         int status;
2207
2208         LIST_FIELDS(struct ExecStatusInfo, exec);
2209 } ExecStatusInfo;
2210
2211 static void exec_status_info_free(ExecStatusInfo *i) {
2212         assert(i);
2213
2214         free(i->name);
2215         free(i->path);
2216         strv_free(i->argv);
2217         free(i);
2218 }
2219
2220 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2221         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2222         DBusMessageIter sub2, sub3;
2223         const char*path;
2224         unsigned n;
2225         uint32_t pid;
2226         int32_t code, status;
2227         dbus_bool_t ignore;
2228
2229         assert(i);
2230         assert(i);
2231
2232         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2233                 return -EIO;
2234
2235         dbus_message_iter_recurse(sub, &sub2);
2236
2237         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2238                 return -EIO;
2239
2240         if (!(i->path = strdup(path)))
2241                 return -ENOMEM;
2242
2243         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2244             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2245                 return -EIO;
2246
2247         n = 0;
2248         dbus_message_iter_recurse(&sub2, &sub3);
2249         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2250                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2251                 dbus_message_iter_next(&sub3);
2252                 n++;
2253         }
2254
2255
2256         if (!(i->argv = new0(char*, n+1)))
2257                 return -ENOMEM;
2258
2259         n = 0;
2260         dbus_message_iter_recurse(&sub2, &sub3);
2261         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2262                 const char *s;
2263
2264                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2265                 dbus_message_iter_get_basic(&sub3, &s);
2266                 dbus_message_iter_next(&sub3);
2267
2268                 if (!(i->argv[n++] = strdup(s)))
2269                         return -ENOMEM;
2270         }
2271
2272         if (!dbus_message_iter_next(&sub2) ||
2273             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2274             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2275             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2276             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2277             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2278             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2279             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2280             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2281                 return -EIO;
2282
2283         i->ignore = ignore;
2284         i->start_timestamp = (usec_t) start_timestamp;
2285         i->exit_timestamp = (usec_t) exit_timestamp;
2286         i->pid = (pid_t) pid;
2287         i->code = code;
2288         i->status = status;
2289
2290         return 0;
2291 }
2292
2293 typedef struct UnitStatusInfo {
2294         const char *id;
2295         const char *load_state;
2296         const char *active_state;
2297         const char *sub_state;
2298         const char *unit_file_state;
2299
2300         const char *description;
2301         const char *following;
2302
2303         char **documentation;
2304
2305         const char *fragment_path;
2306         const char *source_path;
2307         const char *default_control_group;
2308
2309         const char *load_error;
2310         const char *result;
2311
2312         usec_t inactive_exit_timestamp;
2313         usec_t inactive_exit_timestamp_monotonic;
2314         usec_t active_enter_timestamp;
2315         usec_t active_exit_timestamp;
2316         usec_t inactive_enter_timestamp;
2317
2318         bool need_daemon_reload;
2319
2320         /* Service */
2321         pid_t main_pid;
2322         pid_t control_pid;
2323         const char *status_text;
2324         bool running:1;
2325
2326         usec_t start_timestamp;
2327         usec_t exit_timestamp;
2328
2329         int exit_code, exit_status;
2330
2331         usec_t condition_timestamp;
2332         bool condition_result;
2333
2334         /* Socket */
2335         unsigned n_accepted;
2336         unsigned n_connections;
2337         bool accept;
2338
2339         /* Device */
2340         const char *sysfs_path;
2341
2342         /* Mount, Automount */
2343         const char *where;
2344
2345         /* Swap */
2346         const char *what;
2347
2348         LIST_HEAD(ExecStatusInfo, exec);
2349 } UnitStatusInfo;
2350
2351 static void print_status_info(UnitStatusInfo *i) {
2352         ExecStatusInfo *p;
2353         const char *on, *off, *ss;
2354         usec_t timestamp;
2355         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2356         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2357         const char *path;
2358
2359         assert(i);
2360
2361         /* This shows pretty information about a unit. See
2362          * print_property() for a low-level property printer */
2363
2364         printf("%s", strna(i->id));
2365
2366         if (i->description && !streq_ptr(i->id, i->description))
2367                 printf(" - %s", i->description);
2368
2369         printf("\n");
2370
2371         if (i->following)
2372                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2373
2374         if (streq_ptr(i->load_state, "error")) {
2375                 on = ansi_highlight_red(true);
2376                 off = ansi_highlight_red(false);
2377         } else
2378                 on = off = "";
2379
2380         path = i->source_path ? i->source_path : i->fragment_path;
2381
2382         if (i->load_error)
2383                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2384         else if (path && i->unit_file_state)
2385                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2386         else if (path)
2387                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2388         else
2389                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2390
2391         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2392
2393         if (streq_ptr(i->active_state, "failed")) {
2394                 on = ansi_highlight_red(true);
2395                 off = ansi_highlight_red(false);
2396         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2397                 on = ansi_highlight_green(true);
2398                 off = ansi_highlight_green(false);
2399         } else
2400                 on = off = "";
2401
2402         if (ss)
2403                 printf("\t  Active: %s%s (%s)%s",
2404                        on,
2405                        strna(i->active_state),
2406                        ss,
2407                        off);
2408         else
2409                 printf("\t  Active: %s%s%s",
2410                        on,
2411                        strna(i->active_state),
2412                        off);
2413
2414         if (!isempty(i->result) && !streq(i->result, "success"))
2415                 printf(" (Result: %s)", i->result);
2416
2417         timestamp = (streq_ptr(i->active_state, "active")      ||
2418                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2419                     (streq_ptr(i->active_state, "inactive")    ||
2420                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2421                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2422                                                                   i->active_exit_timestamp;
2423
2424         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2425         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2426
2427         if (s1)
2428                 printf(" since %s; %s\n", s2, s1);
2429         else if (s2)
2430                 printf(" since %s\n", s2);
2431         else
2432                 printf("\n");
2433
2434         if (!i->condition_result && i->condition_timestamp > 0) {
2435                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2436                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2437
2438                 if (s1)
2439                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2440                 else if (s2)
2441                         printf("\t          start condition failed at %s\n", s2);
2442         }
2443
2444         if (i->sysfs_path)
2445                 printf("\t  Device: %s\n", i->sysfs_path);
2446         if (i->where)
2447                 printf("\t   Where: %s\n", i->where);
2448         if (i->what)
2449                 printf("\t    What: %s\n", i->what);
2450
2451         if (!strv_isempty(i->documentation)) {
2452                 char **t;
2453                 bool first = true;
2454
2455                 STRV_FOREACH(t, i->documentation) {
2456                         if (first) {
2457                                 printf("\t    Docs: %s\n", *t);
2458                                 first = false;
2459                         } else
2460                                 printf("\t          %s\n", *t);
2461                 }
2462         }
2463
2464         if (i->accept)
2465                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2466
2467         LIST_FOREACH(exec, p, i->exec) {
2468                 char *t;
2469                 bool good;
2470
2471                 /* Only show exited processes here */
2472                 if (p->code == 0)
2473                         continue;
2474
2475                 t = strv_join(p->argv, " ");
2476                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2477                 free(t);
2478
2479                 good = is_clean_exit_lsb(p->code, p->status);
2480                 if (!good) {
2481                         on = ansi_highlight_red(true);
2482                         off = ansi_highlight_red(false);
2483                 } else
2484                         on = off = "";
2485
2486                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2487
2488                 if (p->code == CLD_EXITED) {
2489                         const char *c;
2490
2491                         printf("status=%i", p->status);
2492
2493                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2494                         if (c)
2495                                 printf("/%s", c);
2496
2497                 } else
2498                         printf("signal=%s", signal_to_string(p->status));
2499
2500                 printf(")%s\n", off);
2501
2502                 if (i->main_pid == p->pid &&
2503                     i->start_timestamp == p->start_timestamp &&
2504                     i->exit_timestamp == p->start_timestamp)
2505                         /* Let's not show this twice */
2506                         i->main_pid = 0;
2507
2508                 if (p->pid == i->control_pid)
2509                         i->control_pid = 0;
2510         }
2511
2512         if (i->main_pid > 0 || i->control_pid > 0) {
2513                 printf("\t");
2514
2515                 if (i->main_pid > 0) {
2516                         printf("Main PID: %u", (unsigned) i->main_pid);
2517
2518                         if (i->running) {
2519                                 char *t = NULL;
2520                                 get_process_comm(i->main_pid, &t);
2521                                 if (t) {
2522                                         printf(" (%s)", t);
2523                                         free(t);
2524                                 }
2525                         } else if (i->exit_code > 0) {
2526                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2527
2528                                 if (i->exit_code == CLD_EXITED) {
2529                                         const char *c;
2530
2531                                         printf("status=%i", i->exit_status);
2532
2533                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2534                                         if (c)
2535                                                 printf("/%s", c);
2536
2537                                 } else
2538                                         printf("signal=%s", signal_to_string(i->exit_status));
2539                                 printf(")");
2540                         }
2541                 }
2542
2543                 if (i->main_pid > 0 && i->control_pid > 0)
2544                         printf(";");
2545
2546                 if (i->control_pid > 0) {
2547                         char *t = NULL;
2548
2549                         printf(" Control: %u", (unsigned) i->control_pid);
2550
2551                         get_process_comm(i->control_pid, &t);
2552                         if (t) {
2553                                 printf(" (%s)", t);
2554                                 free(t);
2555                         }
2556                 }
2557
2558                 printf("\n");
2559         }
2560
2561         if (i->status_text)
2562                 printf("\t  Status: \"%s\"\n", i->status_text);
2563
2564         if (i->default_control_group) {
2565                 unsigned c;
2566
2567                 printf("\t  CGroup: %s\n", i->default_control_group);
2568
2569                 if (arg_transport != TRANSPORT_SSH) {
2570                         unsigned k = 0;
2571                         pid_t extra[2];
2572
2573                         c = columns();
2574                         if (c > 18)
2575                                 c -= 18;
2576                         else
2577                                 c = 0;
2578
2579                         if (i->main_pid > 0)
2580                                 extra[k++] = i->main_pid;
2581
2582                         if (i->control_pid > 0)
2583                                 extra[k++] = i->control_pid;
2584
2585                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2586                 }
2587         }
2588
2589         if (i->id && arg_transport != TRANSPORT_SSH) {
2590                 int flags = (arg_lines*OUTPUT_SHOW_ALL |
2591                              arg_follow*OUTPUT_FOLLOW |
2592                              !arg_quiet*OUTPUT_WARN_CUTOFF);
2593                 printf("\n");
2594                 show_journal_by_unit(i->id, arg_output, 0,
2595                                      i->inactive_exit_timestamp_monotonic,
2596                                      arg_lines, flags);
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_WHO,
4592                 ARG_NO_ASK_PASSWORD,
4593                 ARG_FAILED,
4594                 ARG_RUNTIME,
4595                 ARG_FOLLOW,
4596                 ARG_FORCE
4597         };
4598
4599         static const struct option options[] = {
4600                 { "help",      no_argument,       NULL, 'h'           },
4601                 { "version",   no_argument,       NULL, ARG_VERSION   },
4602                 { "type",      required_argument, NULL, 't'           },
4603                 { "property",  required_argument, NULL, 'p'           },
4604                 { "all",       no_argument,       NULL, 'a'           },
4605                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4606                 { "full",      no_argument,       NULL, ARG_FULL      },
4607                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4608                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4609                 { "user",      no_argument,       NULL, ARG_USER      },
4610                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4611                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4612                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4613                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4614                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4615                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4616                 { "quiet",     no_argument,       NULL, 'q'           },
4617                 { "order",     no_argument,       NULL, ARG_ORDER     },
4618                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4619                 { "root",      required_argument, NULL, ARG_ROOT      },
4620                 { "force",     no_argument,       NULL, ARG_FORCE     },
4621                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4622                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4623                 { "signal",    required_argument, NULL, 's'           },
4624                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4625                 { "host",      required_argument, NULL, 'H'           },
4626                 { "privileged",no_argument,       NULL, 'P'           },
4627                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4628                 { "lines",     required_argument, NULL, 'n'           },
4629                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4630                 { "output",    required_argument, NULL, 'o'           },
4631                 { NULL,        0,                 NULL, 0             }
4632         };
4633
4634         int c;
4635
4636         assert(argc >= 0);
4637         assert(argv);
4638
4639         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4640
4641                 switch (c) {
4642
4643                 case 'h':
4644                         systemctl_help();
4645                         return 0;
4646
4647                 case ARG_VERSION:
4648                         puts(PACKAGE_STRING);
4649                         puts(DISTRIBUTION);
4650                         puts(SYSTEMD_FEATURES);
4651                         return 0;
4652
4653                 case 't':
4654                         if (unit_type_from_string(optarg) >= 0) {
4655                                 arg_type = optarg;
4656                                 break;
4657                         }
4658                         if (unit_load_state_from_string(optarg) >= 0) {
4659                                 arg_load_state = optarg;
4660                                 break;
4661                         }
4662                         log_error("Unkown unit type or load state '%s'.",
4663                                   optarg);
4664                         return -EINVAL;
4665                 case 'p': {
4666                         char **l;
4667
4668                         if (!(l = strv_append(arg_property, optarg)))
4669                                 return -ENOMEM;
4670
4671                         strv_free(arg_property);
4672                         arg_property = l;
4673
4674                         /* If the user asked for a particular
4675                          * property, show it to him, even if it is
4676                          * empty. */
4677                         arg_all = true;
4678                         break;
4679                 }
4680
4681                 case 'a':
4682                         arg_all = true;
4683                         break;
4684
4685                 case ARG_FAIL:
4686                         arg_job_mode = "fail";
4687                         break;
4688
4689                 case ARG_IGNORE_DEPENDENCIES:
4690                         arg_job_mode = "ignore-dependencies";
4691                         break;
4692
4693                 case ARG_USER:
4694                         arg_scope = UNIT_FILE_USER;
4695                         break;
4696
4697                 case ARG_SYSTEM:
4698                         arg_scope = UNIT_FILE_SYSTEM;
4699                         break;
4700
4701                 case ARG_GLOBAL:
4702                         arg_scope = UNIT_FILE_GLOBAL;
4703                         break;
4704
4705                 case ARG_NO_BLOCK:
4706                         arg_no_block = true;
4707                         break;
4708
4709                 case ARG_NO_LEGEND:
4710                         arg_no_legend = true;
4711                         break;
4712
4713                 case ARG_NO_PAGER:
4714                         arg_no_pager = true;
4715                         break;
4716
4717                 case ARG_NO_WALL:
4718                         arg_no_wall = true;
4719                         break;
4720
4721                 case ARG_ORDER:
4722                         arg_dot = DOT_ORDER;
4723                         break;
4724
4725                 case ARG_REQUIRE:
4726                         arg_dot = DOT_REQUIRE;
4727                         break;
4728
4729                 case ARG_ROOT:
4730                         arg_root = optarg;
4731                         break;
4732
4733                 case ARG_FULL:
4734                         arg_full = true;
4735                         break;
4736
4737                 case ARG_FAILED:
4738                         arg_failed = true;
4739                         break;
4740
4741                 case 'q':
4742                         arg_quiet = true;
4743                         break;
4744
4745                 case ARG_FORCE:
4746                         arg_force ++;
4747                         break;
4748
4749                 case ARG_FOLLOW:
4750                         arg_follow = true;
4751                         break;
4752
4753                 case 'f':
4754                         /* -f is short for both --follow and --force! */
4755                         arg_force ++;
4756                         arg_follow = true;
4757                         break;
4758
4759                 case ARG_NO_RELOAD:
4760                         arg_no_reload = true;
4761                         break;
4762
4763                 case ARG_KILL_WHO:
4764                         arg_kill_who = optarg;
4765                         break;
4766
4767                 case 's':
4768                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4769                                 log_error("Failed to parse signal string %s.", optarg);
4770                                 return -EINVAL;
4771                         }
4772                         break;
4773
4774                 case ARG_NO_ASK_PASSWORD:
4775                         arg_ask_password = false;
4776                         break;
4777
4778                 case 'P':
4779                         arg_transport = TRANSPORT_POLKIT;
4780                         break;
4781
4782                 case 'H':
4783                         arg_transport = TRANSPORT_SSH;
4784                         arg_host = optarg;
4785                         break;
4786
4787                 case ARG_RUNTIME:
4788                         arg_runtime = true;
4789                         break;
4790
4791                 case 'n':
4792                         if (safe_atou(optarg, &arg_lines) < 0) {
4793                                 log_error("Failed to parse lines '%s'", optarg);
4794                                 return -EINVAL;
4795                         }
4796                         break;
4797
4798                 case 'o':
4799                         arg_output = output_mode_from_string(optarg);
4800                         if (arg_output < 0) {
4801                                 log_error("Unknown output '%s'.", optarg);
4802                                 return -EINVAL;
4803                         }
4804                         break;
4805
4806                 case '?':
4807                         return -EINVAL;
4808
4809                 default:
4810                         log_error("Unknown option code '%c'.", c);
4811                         return -EINVAL;
4812                 }
4813         }
4814
4815         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4816                 log_error("Cannot access user instance remotely.");
4817                 return -EINVAL;
4818         }
4819
4820         return 1;
4821 }
4822
4823 static int halt_parse_argv(int argc, char *argv[]) {
4824
4825         enum {
4826                 ARG_HELP = 0x100,
4827                 ARG_HALT,
4828                 ARG_REBOOT,
4829                 ARG_NO_WALL
4830         };
4831
4832         static const struct option options[] = {
4833                 { "help",      no_argument,       NULL, ARG_HELP    },
4834                 { "halt",      no_argument,       NULL, ARG_HALT    },
4835                 { "poweroff",  no_argument,       NULL, 'p'         },
4836                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4837                 { "force",     no_argument,       NULL, 'f'         },
4838                 { "wtmp-only", no_argument,       NULL, 'w'         },
4839                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4840                 { "no-sync",   no_argument,       NULL, 'n'         },
4841                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4842                 { NULL,        0,                 NULL, 0           }
4843         };
4844
4845         int c, runlevel;
4846
4847         assert(argc >= 0);
4848         assert(argv);
4849
4850         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4851                 if (runlevel == '0' || runlevel == '6')
4852                         arg_force = 2;
4853
4854         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4855                 switch (c) {
4856
4857                 case ARG_HELP:
4858                         halt_help();
4859                         return 0;
4860
4861                 case ARG_HALT:
4862                         arg_action = ACTION_HALT;
4863                         break;
4864
4865                 case 'p':
4866                         if (arg_action != ACTION_REBOOT)
4867                                 arg_action = ACTION_POWEROFF;
4868                         break;
4869
4870                 case ARG_REBOOT:
4871                         arg_action = ACTION_REBOOT;
4872                         break;
4873
4874                 case 'f':
4875                         arg_force = 2;
4876                         break;
4877
4878                 case 'w':
4879                         arg_dry = true;
4880                         break;
4881
4882                 case 'd':
4883                         arg_no_wtmp = true;
4884                         break;
4885
4886                 case 'n':
4887                         arg_no_sync = true;
4888                         break;
4889
4890                 case ARG_NO_WALL:
4891                         arg_no_wall = true;
4892                         break;
4893
4894                 case 'i':
4895                 case 'h':
4896                         /* Compatibility nops */
4897                         break;
4898
4899                 case '?':
4900                         return -EINVAL;
4901
4902                 default:
4903                         log_error("Unknown option code '%c'.", c);
4904                         return -EINVAL;
4905                 }
4906         }
4907
4908         if (optind < argc) {
4909                 log_error("Too many arguments.");
4910                 return -EINVAL;
4911         }
4912
4913         return 1;
4914 }
4915
4916 static int parse_time_spec(const char *t, usec_t *_u) {
4917         assert(t);
4918         assert(_u);
4919
4920         if (streq(t, "now"))
4921                 *_u = 0;
4922         else if (!strchr(t, ':')) {
4923                 uint64_t u;
4924
4925                 if (safe_atou64(t, &u) < 0)
4926                         return -EINVAL;
4927
4928                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4929         } else {
4930                 char *e = NULL;
4931                 long hour, minute;
4932                 struct tm tm;
4933                 time_t s;
4934                 usec_t n;
4935
4936                 errno = 0;
4937                 hour = strtol(t, &e, 10);
4938                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4939                         return -EINVAL;
4940
4941                 minute = strtol(e+1, &e, 10);
4942                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4943                         return -EINVAL;
4944
4945                 n = now(CLOCK_REALTIME);
4946                 s = (time_t) (n / USEC_PER_SEC);
4947
4948                 zero(tm);
4949                 assert_se(localtime_r(&s, &tm));
4950
4951                 tm.tm_hour = (int) hour;
4952                 tm.tm_min = (int) minute;
4953                 tm.tm_sec = 0;
4954
4955                 assert_se(s = mktime(&tm));
4956
4957                 *_u = (usec_t) s * USEC_PER_SEC;
4958
4959                 while (*_u <= n)
4960                         *_u += USEC_PER_DAY;
4961         }
4962
4963         return 0;
4964 }
4965
4966 static int shutdown_parse_argv(int argc, char *argv[]) {
4967
4968         enum {
4969                 ARG_HELP = 0x100,
4970                 ARG_NO_WALL
4971         };
4972
4973         static const struct option options[] = {
4974                 { "help",      no_argument,       NULL, ARG_HELP    },
4975                 { "halt",      no_argument,       NULL, 'H'         },
4976                 { "poweroff",  no_argument,       NULL, 'P'         },
4977                 { "reboot",    no_argument,       NULL, 'r'         },
4978                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4979                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4980                 { NULL,        0,                 NULL, 0           }
4981         };
4982
4983         int c, r;
4984
4985         assert(argc >= 0);
4986         assert(argv);
4987
4988         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4989                 switch (c) {
4990
4991                 case ARG_HELP:
4992                         shutdown_help();
4993                         return 0;
4994
4995                 case 'H':
4996                         arg_action = ACTION_HALT;
4997                         break;
4998
4999                 case 'P':
5000                         arg_action = ACTION_POWEROFF;
5001                         break;
5002
5003                 case 'r':
5004                         if (kexec_loaded())
5005                                 arg_action = ACTION_KEXEC;
5006                         else
5007                                 arg_action = ACTION_REBOOT;
5008                         break;
5009
5010                 case 'K':
5011                         arg_action = ACTION_KEXEC;
5012                         break;
5013
5014                 case 'h':
5015                         if (arg_action != ACTION_HALT)
5016                                 arg_action = ACTION_POWEROFF;
5017                         break;
5018
5019                 case 'k':
5020                         arg_dry = true;
5021                         break;
5022
5023                 case ARG_NO_WALL:
5024                         arg_no_wall = true;
5025                         break;
5026
5027                 case 't':
5028                 case 'a':
5029                         /* Compatibility nops */
5030                         break;
5031
5032                 case 'c':
5033                         arg_action = ACTION_CANCEL_SHUTDOWN;
5034                         break;
5035
5036                 case '?':
5037                         return -EINVAL;
5038
5039                 default:
5040                         log_error("Unknown option code '%c'.", c);
5041                         return -EINVAL;
5042                 }
5043         }
5044
5045         if (argc > optind) {
5046                 r = parse_time_spec(argv[optind], &arg_when);
5047                 if (r < 0) {
5048                         log_error("Failed to parse time specification: %s", argv[optind]);
5049                         return r;
5050                 }
5051         } else
5052                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
5053
5054         /* We skip the time argument */
5055         if (argc > optind + 1)
5056                 arg_wall = argv + optind + 1;
5057
5058         optind = argc;
5059
5060         return 1;
5061 }
5062
5063 static int telinit_parse_argv(int argc, char *argv[]) {
5064
5065         enum {
5066                 ARG_HELP = 0x100,
5067                 ARG_NO_WALL
5068         };
5069
5070         static const struct option options[] = {
5071                 { "help",      no_argument,       NULL, ARG_HELP    },
5072                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5073                 { NULL,        0,                 NULL, 0           }
5074         };
5075
5076         static const struct {
5077                 char from;
5078                 enum action to;
5079         } table[] = {
5080                 { '0', ACTION_POWEROFF },
5081                 { '6', ACTION_REBOOT },
5082                 { '1', ACTION_RESCUE },
5083                 { '2', ACTION_RUNLEVEL2 },
5084                 { '3', ACTION_RUNLEVEL3 },
5085                 { '4', ACTION_RUNLEVEL4 },
5086                 { '5', ACTION_RUNLEVEL5 },
5087                 { 's', ACTION_RESCUE },
5088                 { 'S', ACTION_RESCUE },
5089                 { 'q', ACTION_RELOAD },
5090                 { 'Q', ACTION_RELOAD },
5091                 { 'u', ACTION_REEXEC },
5092                 { 'U', ACTION_REEXEC }
5093         };
5094
5095         unsigned i;
5096         int c;
5097
5098         assert(argc >= 0);
5099         assert(argv);
5100
5101         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5102                 switch (c) {
5103
5104                 case ARG_HELP:
5105                         telinit_help();
5106                         return 0;
5107
5108                 case ARG_NO_WALL:
5109                         arg_no_wall = true;
5110                         break;
5111
5112                 case '?':
5113                         return -EINVAL;
5114
5115                 default:
5116                         log_error("Unknown option code '%c'.", c);
5117                         return -EINVAL;
5118                 }
5119         }
5120
5121         if (optind >= argc) {
5122                 telinit_help();
5123                 return -EINVAL;
5124         }
5125
5126         if (optind + 1 < argc) {
5127                 log_error("Too many arguments.");
5128                 return -EINVAL;
5129         }
5130
5131         if (strlen(argv[optind]) != 1) {
5132                 log_error("Expected single character argument.");
5133                 return -EINVAL;
5134         }
5135
5136         for (i = 0; i < ELEMENTSOF(table); i++)
5137                 if (table[i].from == argv[optind][0])
5138                         break;
5139
5140         if (i >= ELEMENTSOF(table)) {
5141                 log_error("Unknown command '%s'.", argv[optind]);
5142                 return -EINVAL;
5143         }
5144
5145         arg_action = table[i].to;
5146
5147         optind ++;
5148
5149         return 1;
5150 }
5151
5152 static int runlevel_parse_argv(int argc, char *argv[]) {
5153
5154         enum {
5155                 ARG_HELP = 0x100,
5156         };
5157
5158         static const struct option options[] = {
5159                 { "help",      no_argument,       NULL, ARG_HELP    },
5160                 { NULL,        0,                 NULL, 0           }
5161         };
5162
5163         int c;
5164
5165         assert(argc >= 0);
5166         assert(argv);
5167
5168         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5169                 switch (c) {
5170
5171                 case ARG_HELP:
5172                         runlevel_help();
5173                         return 0;
5174
5175                 case '?':
5176                         return -EINVAL;
5177
5178                 default:
5179                         log_error("Unknown option code '%c'.", c);
5180                         return -EINVAL;
5181                 }
5182         }
5183
5184         if (optind < argc) {
5185                 log_error("Too many arguments.");
5186                 return -EINVAL;
5187         }
5188
5189         return 1;
5190 }
5191
5192 static int parse_argv(int argc, char *argv[]) {
5193         assert(argc >= 0);
5194         assert(argv);
5195
5196         if (program_invocation_short_name) {
5197
5198                 if (strstr(program_invocation_short_name, "halt")) {
5199                         arg_action = ACTION_HALT;
5200                         return halt_parse_argv(argc, argv);
5201                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5202                         arg_action = ACTION_POWEROFF;
5203                         return halt_parse_argv(argc, argv);
5204                 } else if (strstr(program_invocation_short_name, "reboot")) {
5205                         if (kexec_loaded())
5206                                 arg_action = ACTION_KEXEC;
5207                         else
5208                                 arg_action = ACTION_REBOOT;
5209                         return halt_parse_argv(argc, argv);
5210                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5211                         arg_action = ACTION_POWEROFF;
5212                         return shutdown_parse_argv(argc, argv);
5213                 } else if (strstr(program_invocation_short_name, "init")) {
5214
5215                         if (sd_booted() > 0) {
5216                                 arg_action = ACTION_INVALID;
5217                                 return telinit_parse_argv(argc, argv);
5218                         } else {
5219                                 /* Hmm, so some other init system is
5220                                  * running, we need to forward this
5221                                  * request to it. For now we simply
5222                                  * guess that it is Upstart. */
5223
5224                                 execv("/lib/upstart/telinit", argv);
5225
5226                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5227                                 return -EIO;
5228                         }
5229
5230                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5231                         arg_action = ACTION_RUNLEVEL;
5232                         return runlevel_parse_argv(argc, argv);
5233                 }
5234         }
5235
5236         arg_action = ACTION_SYSTEMCTL;
5237         return systemctl_parse_argv(argc, argv);
5238 }
5239
5240 static int action_to_runlevel(void) {
5241
5242         static const char table[_ACTION_MAX] = {
5243                 [ACTION_HALT] =      '0',
5244                 [ACTION_POWEROFF] =  '0',
5245                 [ACTION_REBOOT] =    '6',
5246                 [ACTION_RUNLEVEL2] = '2',
5247                 [ACTION_RUNLEVEL3] = '3',
5248                 [ACTION_RUNLEVEL4] = '4',
5249                 [ACTION_RUNLEVEL5] = '5',
5250                 [ACTION_RESCUE] =    '1'
5251         };
5252
5253         assert(arg_action < _ACTION_MAX);
5254
5255         return table[arg_action];
5256 }
5257
5258 static int talk_upstart(void) {
5259         DBusMessage *m = NULL, *reply = NULL;
5260         DBusError error;
5261         int previous, rl, r;
5262         char
5263                 env1_buf[] = "RUNLEVEL=X",
5264                 env2_buf[] = "PREVLEVEL=X";
5265         char *env1 = env1_buf, *env2 = env2_buf;
5266         const char *emit = "runlevel";
5267         dbus_bool_t b_false = FALSE;
5268         DBusMessageIter iter, sub;
5269         DBusConnection *bus;
5270
5271         dbus_error_init(&error);
5272
5273         if (!(rl = action_to_runlevel()))
5274                 return 0;
5275
5276         if (utmp_get_runlevel(&previous, NULL) < 0)
5277                 previous = 'N';
5278
5279         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5280                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5281                         r = 0;
5282                         goto finish;
5283                 }
5284
5285                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5286                 r = -EIO;
5287                 goto finish;
5288         }
5289
5290         if ((r = bus_check_peercred(bus)) < 0) {
5291                 log_error("Failed to verify owner of bus.");
5292                 goto finish;
5293         }
5294
5295         if (!(m = dbus_message_new_method_call(
5296                               "com.ubuntu.Upstart",
5297                               "/com/ubuntu/Upstart",
5298                               "com.ubuntu.Upstart0_6",
5299                               "EmitEvent"))) {
5300
5301                 log_error("Could not allocate message.");
5302                 r = -ENOMEM;
5303                 goto finish;
5304         }
5305
5306         dbus_message_iter_init_append(m, &iter);
5307
5308         env1_buf[sizeof(env1_buf)-2] = rl;
5309         env2_buf[sizeof(env2_buf)-2] = previous;
5310
5311         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5312             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5313             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5314             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5315             !dbus_message_iter_close_container(&iter, &sub) ||
5316             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5317                 log_error("Could not append arguments to message.");
5318                 r = -ENOMEM;
5319                 goto finish;
5320         }
5321
5322         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5323
5324                 if (error_is_no_service(&error)) {
5325                         r = -EADDRNOTAVAIL;
5326                         goto finish;
5327                 }
5328
5329                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5330                 r = -EIO;
5331                 goto finish;
5332         }
5333
5334         r = 1;
5335
5336 finish:
5337         if (m)
5338                 dbus_message_unref(m);
5339
5340         if (reply)
5341                 dbus_message_unref(reply);
5342
5343         if (bus) {
5344                 dbus_connection_flush(bus);
5345                 dbus_connection_close(bus);
5346                 dbus_connection_unref(bus);
5347         }
5348
5349         dbus_error_free(&error);
5350
5351         return r;
5352 }
5353
5354 static int talk_initctl(void) {
5355         struct init_request request;
5356         int r, fd;
5357         char rl;
5358
5359         if (!(rl = action_to_runlevel()))
5360                 return 0;
5361
5362         zero(request);
5363         request.magic = INIT_MAGIC;
5364         request.sleeptime = 0;
5365         request.cmd = INIT_CMD_RUNLVL;
5366         request.runlevel = rl;
5367
5368         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5369
5370                 if (errno == ENOENT)
5371                         return 0;
5372
5373                 log_error("Failed to open "INIT_FIFO": %m");
5374                 return -errno;
5375         }
5376
5377         errno = 0;
5378         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5379         close_nointr_nofail(fd);
5380
5381         if (r < 0) {
5382                 log_error("Failed to write to "INIT_FIFO": %m");
5383                 return errno ? -errno : -EIO;
5384         }
5385
5386         return 1;
5387 }
5388
5389 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5390
5391         static const struct {
5392                 const char* verb;
5393                 const enum {
5394                         MORE,
5395                         LESS,
5396                         EQUAL
5397                 } argc_cmp;
5398                 const int argc;
5399                 int (* const dispatch)(DBusConnection *bus, char **args);
5400         } verbs[] = {
5401                 { "list-units",            LESS,  1, list_units        },
5402                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5403                 { "list-jobs",             EQUAL, 1, list_jobs         },
5404                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5405                 { "load",                  MORE,  2, load_unit         },
5406                 { "cancel",                MORE,  2, cancel_job        },
5407                 { "start",                 MORE,  2, start_unit        },
5408                 { "stop",                  MORE,  2, start_unit        },
5409                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5410                 { "reload",                MORE,  2, start_unit        },
5411                 { "restart",               MORE,  2, start_unit        },
5412                 { "try-restart",           MORE,  2, start_unit        },
5413                 { "reload-or-restart",     MORE,  2, start_unit        },
5414                 { "reload-or-try-restart", MORE,  2, start_unit        },
5415                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5416                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5417                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5418                 { "isolate",               EQUAL, 2, start_unit        },
5419                 { "kill",                  MORE,  2, kill_unit         },
5420                 { "is-active",             MORE,  2, check_unit        },
5421                 { "check",                 MORE,  2, check_unit        },
5422                 { "show",                  MORE,  1, show              },
5423                 { "status",                MORE,  2, show              },
5424                 { "help",                  MORE,  2, show              },
5425                 { "dump",                  EQUAL, 1, dump              },
5426                 { "dot",                   EQUAL, 1, dot               },
5427                 { "snapshot",              LESS,  2, snapshot          },
5428                 { "delete",                MORE,  2, delete_snapshot   },
5429                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5430                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5431                 { "show-environment",      EQUAL, 1, show_enviroment   },
5432                 { "set-environment",       MORE,  2, set_environment   },
5433                 { "unset-environment",     MORE,  2, set_environment   },
5434                 { "halt",                  EQUAL, 1, start_special     },
5435                 { "poweroff",              EQUAL, 1, start_special     },
5436                 { "reboot",                EQUAL, 1, start_special     },
5437                 { "kexec",                 EQUAL, 1, start_special     },
5438                 { "suspend",               EQUAL, 1, start_special     },
5439                 { "hibernate",             EQUAL, 1, start_special     },
5440                 { "default",               EQUAL, 1, start_special     },
5441                 { "rescue",                EQUAL, 1, start_special     },
5442                 { "emergency",             EQUAL, 1, start_special     },
5443                 { "exit",                  EQUAL, 1, start_special     },
5444                 { "reset-failed",          MORE,  1, reset_failed      },
5445                 { "enable",                MORE,  2, enable_unit       },
5446                 { "disable",               MORE,  2, enable_unit       },
5447                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5448                 { "reenable",              MORE,  2, enable_unit       },
5449                 { "preset",                MORE,  2, enable_unit       },
5450                 { "mask",                  MORE,  2, enable_unit       },
5451                 { "unmask",                MORE,  2, enable_unit       },
5452                 { "link",                  MORE,  2, enable_unit       },
5453                 { "switch-root",           MORE,  2, switch_root       },
5454         };
5455
5456         int left;
5457         unsigned i;
5458
5459         assert(argc >= 0);
5460         assert(argv);
5461         assert(error);
5462
5463         left = argc - optind;
5464
5465         if (left <= 0)
5466                 /* Special rule: no arguments means "list-units" */
5467                 i = 0;
5468         else {
5469                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5470                         log_error("This command expects one or more "
5471                                   "unit names. Did you mean --help?");
5472                         return -EINVAL;
5473                 }
5474
5475                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5476                         if (streq(argv[optind], verbs[i].verb))
5477                                 break;
5478
5479                 if (i >= ELEMENTSOF(verbs)) {
5480                         log_error("Unknown operation '%s'.", argv[optind]);
5481                         return -EINVAL;
5482                 }
5483         }
5484
5485         switch (verbs[i].argc_cmp) {
5486
5487         case EQUAL:
5488                 if (left != verbs[i].argc) {
5489                         log_error("Invalid number of arguments.");
5490                         return -EINVAL;
5491                 }
5492
5493                 break;
5494
5495         case MORE:
5496                 if (left < verbs[i].argc) {
5497                         log_error("Too few arguments.");
5498                         return -EINVAL;
5499                 }
5500
5501                 break;
5502
5503         case LESS:
5504                 if (left > verbs[i].argc) {
5505                         log_error("Too many arguments.");
5506                         return -EINVAL;
5507                 }
5508
5509                 break;
5510
5511         default:
5512                 assert_not_reached("Unknown comparison operator.");
5513         }
5514
5515         /* Require a bus connection for all operations but
5516          * enable/disable */
5517         if (!streq(verbs[i].verb, "enable") &&
5518             !streq(verbs[i].verb, "disable") &&
5519             !streq(verbs[i].verb, "is-enabled") &&
5520             !streq(verbs[i].verb, "list-unit-files") &&
5521             !streq(verbs[i].verb, "reenable") &&
5522             !streq(verbs[i].verb, "preset") &&
5523             !streq(verbs[i].verb, "mask") &&
5524             !streq(verbs[i].verb, "unmask") &&
5525             !streq(verbs[i].verb, "link")) {
5526
5527                 if (running_in_chroot() > 0) {
5528                         log_info("Running in chroot, ignoring request.");
5529                         return 0;
5530                 }
5531
5532                 if (((!streq(verbs[i].verb, "reboot") &&
5533                       !streq(verbs[i].verb, "halt") &&
5534                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5535                         log_error("Failed to get D-Bus connection: %s",
5536                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5537                         return -EIO;
5538                 }
5539
5540         } else {
5541
5542                 if (!bus && !avoid_bus()) {
5543                         log_error("Failed to get D-Bus connection: %s",
5544                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5545                         return -EIO;
5546                 }
5547         }
5548
5549         return verbs[i].dispatch(bus, argv + optind);
5550 }
5551
5552 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5553         int fd;
5554         struct msghdr msghdr;
5555         struct iovec iovec[2];
5556         union sockaddr_union sockaddr;
5557         struct sd_shutdown_command c;
5558
5559         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5560         if (fd < 0)
5561                 return -errno;
5562
5563         zero(c);
5564         c.usec = t;
5565         c.mode = mode;
5566         c.dry_run = dry_run;
5567         c.warn_wall = warn;
5568
5569         zero(sockaddr);
5570         sockaddr.sa.sa_family = AF_UNIX;
5571         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5572
5573         zero(msghdr);
5574         msghdr.msg_name = &sockaddr;
5575         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5576
5577         zero(iovec);
5578         iovec[0].iov_base = (char*) &c;
5579         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5580
5581         if (isempty(message))
5582                 msghdr.msg_iovlen = 1;
5583         else {
5584                 iovec[1].iov_base = (char*) message;
5585                 iovec[1].iov_len = strlen(message);
5586                 msghdr.msg_iovlen = 2;
5587         }
5588         msghdr.msg_iov = iovec;
5589
5590         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5591                 close_nointr_nofail(fd);
5592                 return -errno;
5593         }
5594
5595         close_nointr_nofail(fd);
5596         return 0;
5597 }
5598
5599 static int reload_with_fallback(DBusConnection *bus) {
5600
5601         if (bus) {
5602                 /* First, try systemd via D-Bus. */
5603                 if (daemon_reload(bus, NULL) >= 0)
5604                         return 0;
5605         }
5606
5607         /* Nothing else worked, so let's try signals */
5608         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5609
5610         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5611                 log_error("kill() failed: %m");
5612                 return -errno;
5613         }
5614
5615         return 0;
5616 }
5617
5618 static int start_with_fallback(DBusConnection *bus) {
5619
5620         if (bus) {
5621                 /* First, try systemd via D-Bus. */
5622                 if (start_unit(bus, NULL) >= 0)
5623                         goto done;
5624         }
5625
5626         /* Hmm, talking to systemd via D-Bus didn't work. Then
5627          * let's try to talk to Upstart via D-Bus. */
5628         if (talk_upstart() > 0)
5629                 goto done;
5630
5631         /* Nothing else worked, so let's try
5632          * /dev/initctl */
5633         if (talk_initctl() > 0)
5634                 goto done;
5635
5636         log_error("Failed to talk to init daemon.");
5637         return -EIO;
5638
5639 done:
5640         warn_wall(arg_action);
5641         return 0;
5642 }
5643
5644 static _noreturn_ void halt_now(enum action a) {
5645
5646        /* Make sure C-A-D is handled by the kernel from this
5647          * point on... */
5648         reboot(RB_ENABLE_CAD);
5649
5650         switch (a) {
5651
5652         case ACTION_HALT:
5653                 log_info("Halting.");
5654                 reboot(RB_HALT_SYSTEM);
5655                 break;
5656
5657         case ACTION_POWEROFF:
5658                 log_info("Powering off.");
5659                 reboot(RB_POWER_OFF);
5660                 break;
5661
5662         case ACTION_REBOOT:
5663                 log_info("Rebooting.");
5664                 reboot(RB_AUTOBOOT);
5665                 break;
5666
5667         default:
5668                 assert_not_reached("Unknown halt action.");
5669         }
5670
5671         assert_not_reached("Uh? This shouldn't happen.");
5672 }
5673
5674 static int halt_main(DBusConnection *bus) {
5675         int r;
5676
5677         if (geteuid() != 0) {
5678                 /* Try logind if we are a normal user and no special
5679                  * mode applies. Maybe PolicyKit allows us to shutdown
5680                  * the machine. */
5681
5682                 if (arg_when <= 0 &&
5683                     !arg_dry &&
5684                     !arg_force &&
5685                     (arg_action == ACTION_POWEROFF ||
5686                      arg_action == ACTION_REBOOT)) {
5687                         r = reboot_with_logind(bus, arg_action);
5688                         if (r >= 0)
5689                                 return r;
5690                 }
5691
5692                 log_error("Must be root.");
5693                 return -EPERM;
5694         }
5695
5696         if (arg_when > 0) {
5697                 char *m;
5698
5699                 m = strv_join(arg_wall, " ");
5700                 r = send_shutdownd(arg_when,
5701                                    arg_action == ACTION_HALT     ? 'H' :
5702                                    arg_action == ACTION_POWEROFF ? 'P' :
5703                                    arg_action == ACTION_KEXEC    ? 'K' :
5704                                                                    'r',
5705                                    arg_dry,
5706                                    !arg_no_wall,
5707                                    m);
5708                 free(m);
5709
5710                 if (r < 0)
5711                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5712                 else {
5713                         char date[FORMAT_TIMESTAMP_MAX];
5714
5715                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5716                                  format_timestamp(date, sizeof(date), arg_when));
5717                         return 0;
5718                 }
5719         }
5720
5721         if (!arg_dry && !arg_force)
5722                 return start_with_fallback(bus);
5723
5724         if (!arg_no_wtmp) {
5725                 if (sd_booted() > 0)
5726                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5727                 else {
5728                         r = utmp_put_shutdown();
5729                         if (r < 0)
5730                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5731                 }
5732         }
5733
5734         if (!arg_no_sync)
5735                 sync();
5736
5737         if (arg_dry)
5738                 return 0;
5739
5740         halt_now(arg_action);
5741         /* We should never reach this. */
5742         return -ENOSYS;
5743 }
5744
5745 static int runlevel_main(void) {
5746         int r, runlevel, previous;
5747
5748         r = utmp_get_runlevel(&runlevel, &previous);
5749         if (r < 0) {
5750                 puts("unknown");
5751                 return r;
5752         }
5753
5754         printf("%c %c\n",
5755                previous <= 0 ? 'N' : previous,
5756                runlevel <= 0 ? 'N' : runlevel);
5757
5758         return 0;
5759 }
5760
5761 int main(int argc, char*argv[]) {
5762         int r, retval = EXIT_FAILURE;
5763         DBusConnection *bus = NULL;
5764         DBusError error;
5765
5766         dbus_error_init(&error);
5767
5768         log_parse_environment();
5769         log_open();
5770
5771         r = parse_argv(argc, argv);
5772         if (r < 0)
5773                 goto finish;
5774         else if (r == 0) {
5775                 retval = EXIT_SUCCESS;
5776                 goto finish;
5777         }
5778
5779         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5780          * let's shortcut this */
5781         if (arg_action == ACTION_RUNLEVEL) {
5782                 r = runlevel_main();
5783                 retval = r < 0 ? EXIT_FAILURE : r;
5784                 goto finish;
5785         }
5786
5787         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5788                 log_info("Running in chroot, ignoring request.");
5789                 retval = 0;
5790                 goto finish;
5791         }
5792
5793         if (!avoid_bus()) {
5794                 if (arg_transport == TRANSPORT_NORMAL)
5795                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5796                 else if (arg_transport == TRANSPORT_POLKIT) {
5797                         bus_connect_system_polkit(&bus, &error);
5798                         private_bus = false;
5799                 } else if (arg_transport == TRANSPORT_SSH) {
5800                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5801                         private_bus = false;
5802                 } else
5803                         assert_not_reached("Uh, invalid transport...");
5804         }
5805
5806         switch (arg_action) {
5807
5808         case ACTION_SYSTEMCTL:
5809                 r = systemctl_main(bus, argc, argv, &error);
5810                 break;
5811
5812         case ACTION_HALT:
5813         case ACTION_POWEROFF:
5814         case ACTION_REBOOT:
5815         case ACTION_KEXEC:
5816                 r = halt_main(bus);
5817                 break;
5818
5819         case ACTION_RUNLEVEL2:
5820         case ACTION_RUNLEVEL3:
5821         case ACTION_RUNLEVEL4:
5822         case ACTION_RUNLEVEL5:
5823         case ACTION_RESCUE:
5824         case ACTION_EMERGENCY:
5825         case ACTION_DEFAULT:
5826                 r = start_with_fallback(bus);
5827                 break;
5828
5829         case ACTION_RELOAD:
5830         case ACTION_REEXEC:
5831                 r = reload_with_fallback(bus);
5832                 break;
5833
5834         case ACTION_CANCEL_SHUTDOWN:
5835                 r = send_shutdownd(0, 0, false, false, NULL);
5836                 break;
5837
5838         case ACTION_INVALID:
5839         case ACTION_RUNLEVEL:
5840         default:
5841                 assert_not_reached("Unknown action");
5842         }
5843
5844         retval = r < 0 ? EXIT_FAILURE : r;
5845
5846 finish:
5847         if (bus) {
5848                 dbus_connection_flush(bus);
5849                 dbus_connection_close(bus);
5850                 dbus_connection_unref(bus);
5851         }
5852
5853         dbus_error_free(&error);
5854
5855         dbus_shutdown();
5856
5857         strv_free(arg_property);
5858
5859         pager_close();
5860         ask_password_agent_close();
5861         polkit_agent_close();
5862
5863         return retval;
5864 }