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