chiark / gitweb /
journal: expose and make use of cutoff times of journal
[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 check_one_unit(DBusConnection *bus, char *name, bool quiet) {
1504         DBusMessage *m = NULL, *reply = NULL;
1505         DBusError error;
1506         DBusMessageIter iter, sub;
1507         const char
1508                 *interface = "org.freedesktop.systemd1.Unit",
1509                 *property = "ActiveState";
1510         const char *path = NULL;
1511         const char *state;
1512         int r = 3; /* According to LSB: "program is not running" */
1513
1514         assert(bus);
1515         assert(name);
1516
1517         dbus_error_init(&error);
1518
1519         m = dbus_message_new_method_call(
1520                               "org.freedesktop.systemd1",
1521                               "/org/freedesktop/systemd1",
1522                               "org.freedesktop.systemd1.Manager",
1523                               "GetUnit");
1524         if (!m) {
1525                 log_error("Could not allocate message.");
1526                 r = -ENOMEM;
1527                 goto finish;
1528         }
1529
1530         if (!dbus_message_append_args(m,
1531                                       DBUS_TYPE_STRING, &name,
1532                                       DBUS_TYPE_INVALID)) {
1533                 log_error("Could not append arguments to message.");
1534                 r = -ENOMEM;
1535                 goto finish;
1536         }
1537
1538         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1539         if (!reply) {
1540                 /* Hmm, cannot figure out anything about this unit... */
1541                 if (!quiet)
1542                         puts("unknown");
1543
1544                 goto finish;
1545         }
1546
1547         if (!dbus_message_get_args(reply, &error,
1548                                    DBUS_TYPE_OBJECT_PATH, &path,
1549                                    DBUS_TYPE_INVALID)) {
1550                 log_error("Failed to parse reply: %s", bus_error_message(&error));
1551                 r = -EIO;
1552                 goto finish;
1553         }
1554
1555         dbus_message_unref(m);
1556         m = dbus_message_new_method_call(
1557                               "org.freedesktop.systemd1",
1558                               path,
1559                               "org.freedesktop.DBus.Properties",
1560                               "Get");
1561         if (!m) {
1562                 log_error("Could not allocate message.");
1563                 r = -ENOMEM;
1564                 goto finish;
1565         }
1566
1567         if (!dbus_message_append_args(m,
1568                                       DBUS_TYPE_STRING, &interface,
1569                                       DBUS_TYPE_STRING, &property,
1570                                       DBUS_TYPE_INVALID)) {
1571                 log_error("Could not append arguments to message.");
1572                 r = -ENOMEM;
1573                 goto finish;
1574         }
1575
1576         dbus_message_unref(reply);
1577         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1578         if (!reply) {
1579                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1580                 r = -EIO;
1581                 goto finish;
1582         }
1583
1584         if (!dbus_message_iter_init(reply, &iter) ||
1585             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1586                 log_error("Failed to parse reply.");
1587                 r = -EIO;
1588                 goto finish;
1589         }
1590
1591         dbus_message_iter_recurse(&iter, &sub);
1592
1593         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1594                 log_error("Failed to parse reply.");
1595                 r = -EIO;
1596                 goto finish;
1597         }
1598
1599         dbus_message_iter_get_basic(&sub, &state);
1600
1601         if (!quiet)
1602                 puts(state);
1603
1604         if (streq(state, "active") || streq(state, "reloading"))
1605                 r = 0;
1606
1607 finish:
1608         if (m)
1609                 dbus_message_unref(m);
1610
1611         if (reply)
1612                 dbus_message_unref(reply);
1613
1614         dbus_error_free(&error);
1615
1616         return r;
1617 }
1618
1619 static void check_triggering_units(
1620                 DBusConnection *bus,
1621                 const char *unit_name) {
1622
1623         DBusError error;
1624         DBusMessage *m = NULL, *reply = NULL;
1625         DBusMessageIter iter, sub;
1626         char *service_trigger = NULL;
1627         const char *interface = "org.freedesktop.systemd1.Unit",
1628                    *triggered_by_property = "TriggeredBy";
1629
1630         char *unit_path = NULL;
1631         bool print_warning_label = true;
1632
1633         dbus_error_init(&error);
1634
1635         unit_path = unit_dbus_path_from_name(unit_name);
1636         if (!unit_path) {
1637                 log_error("Could not allocate dbus path.");
1638                 goto finish;
1639         }
1640
1641         m = dbus_message_new_method_call("org.freedesktop.systemd1",
1642                                          unit_path,
1643                                          "org.freedesktop.DBus.Properties",
1644                                          "Get");
1645         if (!m) {
1646                 log_error("Could not allocate message.");
1647                 goto finish;
1648         }
1649
1650         if (!dbus_message_append_args(m,
1651                                       DBUS_TYPE_STRING, &interface,
1652                                       DBUS_TYPE_STRING, &triggered_by_property,
1653                                       DBUS_TYPE_INVALID)) {
1654                 log_error("Could not append arguments to message.");
1655                 goto finish;
1656         }
1657
1658         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1659         if (!reply) {
1660                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1661                 goto finish;
1662         }
1663
1664         if (!dbus_message_iter_init(reply, &iter) ||
1665             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1666                 log_error("Failed to parse reply: %s", bus_error_message(&error));
1667                 goto finish;
1668
1669         }
1670
1671         dbus_message_iter_recurse(&iter, &sub);
1672         dbus_message_iter_recurse(&sub, &iter);
1673         sub = iter;
1674
1675         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1676                 int r;
1677
1678                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1679                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1680                         goto finish;
1681                 }
1682
1683                 dbus_message_iter_get_basic(&sub, &service_trigger);
1684
1685                 r = check_one_unit(bus, service_trigger, true);
1686                 if (r < 0)
1687                         goto finish;
1688                 if (r == 0) {
1689                         if (print_warning_label) {
1690                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1691                                 print_warning_label = false;
1692                         }
1693                         log_warning("  %s", service_trigger);
1694                 }
1695
1696                 dbus_message_iter_next(&sub);
1697         }
1698 finish:
1699         if (m)
1700                 dbus_message_unref(m);
1701
1702         if (reply)
1703                 dbus_message_unref(reply);
1704
1705         dbus_error_free(&error);
1706
1707         free(unit_path);
1708 }
1709
1710 static int start_unit_one(
1711                 DBusConnection *bus,
1712                 const char *method,
1713                 const char *name,
1714                 const char *mode,
1715                 DBusError *error,
1716                 Set *s) {
1717
1718         DBusMessage *m = NULL, *reply = NULL;
1719         const char *path;
1720         int r;
1721
1722         assert(bus);
1723         assert(method);
1724         assert(name);
1725         assert(mode);
1726         assert(error);
1727         assert(arg_no_block || s);
1728
1729         if (!(m = dbus_message_new_method_call(
1730                               "org.freedesktop.systemd1",
1731                               "/org/freedesktop/systemd1",
1732                               "org.freedesktop.systemd1.Manager",
1733                               method))) {
1734                 log_error("Could not allocate message.");
1735                 r = -ENOMEM;
1736                 goto finish;
1737         }
1738
1739         if (!dbus_message_append_args(m,
1740                                       DBUS_TYPE_STRING, &name,
1741                                       DBUS_TYPE_STRING, &mode,
1742                                       DBUS_TYPE_INVALID)) {
1743                 log_error("Could not append arguments to message.");
1744                 r = -ENOMEM;
1745                 goto finish;
1746         }
1747
1748         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1749
1750                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1751                         /* There's always a fallback possible for
1752                          * legacy actions. */
1753                         r = -EADDRNOTAVAIL;
1754                         goto finish;
1755                 }
1756
1757                 log_error("Failed to issue method call: %s", bus_error_message(error));
1758                 r = -EIO;
1759                 goto finish;
1760         }
1761
1762         if (!dbus_message_get_args(reply, error,
1763                                    DBUS_TYPE_OBJECT_PATH, &path,
1764                                    DBUS_TYPE_INVALID)) {
1765                 log_error("Failed to parse reply: %s", bus_error_message(error));
1766                 r = -EIO;
1767                 goto finish;
1768         }
1769
1770         if (need_daemon_reload(bus, name))
1771                 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1772                             arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1773
1774         if (!arg_no_block) {
1775                 char *p;
1776
1777                 if (!(p = strdup(path))) {
1778                         log_error("Failed to duplicate path.");
1779                         r = -ENOMEM;
1780                         goto finish;
1781                 }
1782
1783                 if ((r = set_put(s, p)) < 0) {
1784                         free(p);
1785                         log_error("Failed to add path to set.");
1786                         goto finish;
1787                 }
1788         }
1789
1790         /* When stopping a unit warn if it can still be triggered by
1791          * another active unit (socket, path, timer) */
1792         if (!arg_quiet && streq(method, "StopUnit"))
1793                 check_triggering_units(bus, name);
1794
1795         r = 0;
1796
1797 finish:
1798         if (m)
1799                 dbus_message_unref(m);
1800
1801         if (reply)
1802                 dbus_message_unref(reply);
1803
1804         return r;
1805 }
1806
1807 static enum action verb_to_action(const char *verb) {
1808         if (streq(verb, "halt"))
1809                 return ACTION_HALT;
1810         else if (streq(verb, "poweroff"))
1811                 return ACTION_POWEROFF;
1812         else if (streq(verb, "reboot"))
1813                 return ACTION_REBOOT;
1814         else if (streq(verb, "kexec"))
1815                 return ACTION_KEXEC;
1816         else if (streq(verb, "rescue"))
1817                 return ACTION_RESCUE;
1818         else if (streq(verb, "emergency"))
1819                 return ACTION_EMERGENCY;
1820         else if (streq(verb, "default"))
1821                 return ACTION_DEFAULT;
1822         else if (streq(verb, "exit"))
1823                 return ACTION_EXIT;
1824         else if (streq(verb, "suspend"))
1825                 return ACTION_SUSPEND;
1826         else if (streq(verb, "hibernate"))
1827                 return ACTION_HIBERNATE;
1828         else
1829                 return ACTION_INVALID;
1830 }
1831
1832 static int start_unit(DBusConnection *bus, char **args) {
1833
1834         static const char * const table[_ACTION_MAX] = {
1835                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1836                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1837                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1838                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1839                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1840                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1841                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1842                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1843                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1844                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1845                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1846                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1847                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1848                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
1849         };
1850
1851         int r, ret = 0;
1852         const char *method, *mode, *one_name;
1853         Set *s = NULL;
1854         DBusError error;
1855         char **name;
1856
1857         dbus_error_init(&error);
1858
1859         assert(bus);
1860
1861         ask_password_agent_open_if_enabled();
1862
1863         if (arg_action == ACTION_SYSTEMCTL) {
1864                 method =
1865                         streq(args[0], "stop") ||
1866                         streq(args[0], "condstop")              ? "StopUnit" :
1867                         streq(args[0], "reload")                ? "ReloadUnit" :
1868                         streq(args[0], "restart")               ? "RestartUnit" :
1869
1870                         streq(args[0], "try-restart")           ||
1871                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1872
1873                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1874
1875                         streq(args[0], "reload-or-try-restart") ||
1876                         streq(args[0], "condreload") ||
1877
1878                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1879                                                                   "StartUnit";
1880
1881                 mode =
1882                         (streq(args[0], "isolate") ||
1883                          streq(args[0], "rescue")  ||
1884                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1885
1886                 one_name = table[verb_to_action(args[0])];
1887
1888         } else {
1889                 assert(arg_action < ELEMENTSOF(table));
1890                 assert(table[arg_action]);
1891
1892                 method = "StartUnit";
1893
1894                 mode = (arg_action == ACTION_EMERGENCY ||
1895                         arg_action == ACTION_RESCUE ||
1896                         arg_action == ACTION_RUNLEVEL2 ||
1897                         arg_action == ACTION_RUNLEVEL3 ||
1898                         arg_action == ACTION_RUNLEVEL4 ||
1899                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1900
1901                 one_name = table[arg_action];
1902         }
1903
1904         if (!arg_no_block) {
1905                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1906                         log_error("Could not watch jobs: %s", strerror(-ret));
1907                         goto finish;
1908                 }
1909
1910                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1911                         log_error("Failed to allocate set.");
1912                         ret = -ENOMEM;
1913                         goto finish;
1914                 }
1915         }
1916
1917         if (one_name) {
1918                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1919                         goto finish;
1920         } else {
1921                 STRV_FOREACH(name, args+1)
1922                         if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1923                                 ret = translate_bus_error_to_exit_status(r, &error);
1924                                 dbus_error_free(&error);
1925                         }
1926         }
1927
1928         if (!arg_no_block)
1929                 if ((r = wait_for_jobs(bus, s)) < 0) {
1930                         ret = r;
1931                         goto finish;
1932                 }
1933
1934 finish:
1935         if (s)
1936                 set_free_free(s);
1937
1938         dbus_error_free(&error);
1939
1940         return ret;
1941 }
1942
1943 /* Ask systemd-logind, which might grant access to unprivileged users
1944  * through PolicyKit */
1945 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1946 #ifdef HAVE_LOGIND
1947         const char *method;
1948         DBusMessage *m = NULL, *reply = NULL;
1949         DBusError error;
1950         dbus_bool_t interactive = true;
1951         int r;
1952
1953         dbus_error_init(&error);
1954
1955         polkit_agent_open_if_enabled();
1956
1957         switch (a) {
1958
1959         case ACTION_REBOOT:
1960                 method = "Reboot";
1961                 break;
1962
1963         case ACTION_POWEROFF:
1964                 method = "PowerOff";
1965                 break;
1966
1967         case ACTION_SUSPEND:
1968                 method = "Suspend";
1969                 break;
1970
1971         case ACTION_HIBERNATE:
1972                 method = "Hibernate";
1973                 break;
1974
1975         default:
1976                 return -EINVAL;
1977         }
1978
1979         m = dbus_message_new_method_call(
1980                                 "org.freedesktop.login1",
1981                                 "/org/freedesktop/login1",
1982                                 "org.freedesktop.login1.Manager",
1983                                 method);
1984         if (!m) {
1985                 log_error("Could not allocate message.");
1986                 r = -ENOMEM;
1987                 goto finish;
1988         }
1989
1990         if (!dbus_message_append_args(m,
1991                                       DBUS_TYPE_BOOLEAN, &interactive,
1992                                       DBUS_TYPE_INVALID)) {
1993                 log_error("Could not append arguments to message.");
1994                 r = -ENOMEM;
1995                 goto finish;
1996         }
1997
1998         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1999         if (!reply) {
2000                 if (error_is_no_service(&error)) {
2001                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
2002                         r = -ENOENT;
2003                         goto finish;
2004                 }
2005
2006                 if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2007                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
2008                         r = -EACCES;
2009                         goto finish;
2010                 }
2011
2012                 log_info("Failed to issue method call: %s", bus_error_message(&error));
2013                 r = -EIO;
2014                 goto finish;
2015         }
2016
2017         r = 0;
2018
2019 finish:
2020         if (m)
2021                 dbus_message_unref(m);
2022
2023         if (reply)
2024                 dbus_message_unref(reply);
2025
2026         dbus_error_free(&error);
2027
2028         return r;
2029 #else
2030         return -ENOSYS;
2031 #endif
2032 }
2033
2034 static int start_special(DBusConnection *bus, char **args) {
2035         enum action a;
2036         int r;
2037
2038         assert(args);
2039
2040         a = verb_to_action(args[0]);
2041
2042         if (arg_force >= 2 && geteuid() != 0) {
2043                 log_error("Must be root.");
2044                 return -EPERM;
2045         }
2046
2047         if (arg_force >= 2 &&
2048             (a == ACTION_HALT ||
2049              a == ACTION_POWEROFF ||
2050              a == ACTION_REBOOT))
2051                 halt_now(a);
2052
2053         if (arg_force >= 1 &&
2054             (a == ACTION_HALT ||
2055              a == ACTION_POWEROFF ||
2056              a == ACTION_REBOOT ||
2057              a == ACTION_KEXEC ||
2058              a == ACTION_EXIT))
2059                 return daemon_reload(bus, args);
2060
2061         /* first try logind, to allow authentication with polkit */
2062         if (geteuid() != 0 &&
2063             (a == ACTION_POWEROFF ||
2064              a == ACTION_REBOOT ||
2065              a == ACTION_SUSPEND ||
2066              a == ACTION_HIBERNATE)) {
2067                 r = reboot_with_logind(bus, a);
2068                 if (r >= 0)
2069                         return r;
2070         }
2071
2072         r = start_unit(bus, args);
2073         if (r >= 0)
2074                 warn_wall(a);
2075
2076         return r;
2077 }
2078
2079 static int check_unit(DBusConnection *bus, char **args) {
2080         char **name;
2081         int r = 3; /* According to LSB: "program is not running" */
2082
2083         assert(bus);
2084         assert(args);
2085
2086         STRV_FOREACH(name, args+1) {
2087                 int state = check_one_unit(bus, *name, arg_quiet);
2088                 if (state < 0)
2089                         return state;
2090                 if (state == 0)
2091                         r = 0;
2092         }
2093
2094         return r;
2095 }
2096
2097 static int kill_unit(DBusConnection *bus, char **args) {
2098         DBusMessage *m = NULL;
2099         int r = 0;
2100         DBusError error;
2101         char **name;
2102
2103         assert(bus);
2104         assert(args);
2105
2106         dbus_error_init(&error);
2107
2108         if (!arg_kill_who)
2109                 arg_kill_who = "all";
2110
2111         if (!arg_kill_mode)
2112                 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
2113
2114         STRV_FOREACH(name, args+1) {
2115                 DBusMessage *reply;
2116
2117                 if (!(m = dbus_message_new_method_call(
2118                                       "org.freedesktop.systemd1",
2119                                       "/org/freedesktop/systemd1",
2120                                       "org.freedesktop.systemd1.Manager",
2121                                       "KillUnit"))) {
2122                         log_error("Could not allocate message.");
2123                         r = -ENOMEM;
2124                         goto finish;
2125                 }
2126
2127                 if (!dbus_message_append_args(m,
2128                                               DBUS_TYPE_STRING, name,
2129                                               DBUS_TYPE_STRING, &arg_kill_who,
2130                                               DBUS_TYPE_STRING, &arg_kill_mode,
2131                                               DBUS_TYPE_INT32, &arg_signal,
2132                                               DBUS_TYPE_INVALID)) {
2133                         log_error("Could not append arguments to message.");
2134                         r = -ENOMEM;
2135                         goto finish;
2136                 }
2137
2138                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2139                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2140                         dbus_error_free(&error);
2141                         r = -EIO;
2142                 }
2143
2144                 dbus_message_unref(m);
2145
2146                 if (reply)
2147                         dbus_message_unref(reply);
2148                 m = reply = NULL;
2149         }
2150
2151 finish:
2152         if (m)
2153                 dbus_message_unref(m);
2154
2155         dbus_error_free(&error);
2156
2157         return r;
2158 }
2159
2160 typedef struct ExecStatusInfo {
2161         char *name;
2162
2163         char *path;
2164         char **argv;
2165
2166         bool ignore;
2167
2168         usec_t start_timestamp;
2169         usec_t exit_timestamp;
2170         pid_t pid;
2171         int code;
2172         int status;
2173
2174         LIST_FIELDS(struct ExecStatusInfo, exec);
2175 } ExecStatusInfo;
2176
2177 static void exec_status_info_free(ExecStatusInfo *i) {
2178         assert(i);
2179
2180         free(i->name);
2181         free(i->path);
2182         strv_free(i->argv);
2183         free(i);
2184 }
2185
2186 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2187         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2188         DBusMessageIter sub2, sub3;
2189         const char*path;
2190         unsigned n;
2191         uint32_t pid;
2192         int32_t code, status;
2193         dbus_bool_t ignore;
2194
2195         assert(i);
2196         assert(i);
2197
2198         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2199                 return -EIO;
2200
2201         dbus_message_iter_recurse(sub, &sub2);
2202
2203         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2204                 return -EIO;
2205
2206         if (!(i->path = strdup(path)))
2207                 return -ENOMEM;
2208
2209         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2210             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2211                 return -EIO;
2212
2213         n = 0;
2214         dbus_message_iter_recurse(&sub2, &sub3);
2215         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2216                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2217                 dbus_message_iter_next(&sub3);
2218                 n++;
2219         }
2220
2221
2222         if (!(i->argv = new0(char*, n+1)))
2223                 return -ENOMEM;
2224
2225         n = 0;
2226         dbus_message_iter_recurse(&sub2, &sub3);
2227         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2228                 const char *s;
2229
2230                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2231                 dbus_message_iter_get_basic(&sub3, &s);
2232                 dbus_message_iter_next(&sub3);
2233
2234                 if (!(i->argv[n++] = strdup(s)))
2235                         return -ENOMEM;
2236         }
2237
2238         if (!dbus_message_iter_next(&sub2) ||
2239             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2240             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2241             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2242             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2243             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2244             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2245             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2246             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2247                 return -EIO;
2248
2249         i->ignore = ignore;
2250         i->start_timestamp = (usec_t) start_timestamp;
2251         i->exit_timestamp = (usec_t) exit_timestamp;
2252         i->pid = (pid_t) pid;
2253         i->code = code;
2254         i->status = status;
2255
2256         return 0;
2257 }
2258
2259 typedef struct UnitStatusInfo {
2260         const char *id;
2261         const char *load_state;
2262         const char *active_state;
2263         const char *sub_state;
2264         const char *unit_file_state;
2265
2266         const char *description;
2267         const char *following;
2268
2269         char **documentation;
2270
2271         const char *fragment_path;
2272         const char *source_path;
2273         const char *default_control_group;
2274
2275         const char *load_error;
2276         const char *result;
2277
2278         usec_t inactive_exit_timestamp;
2279         usec_t inactive_exit_timestamp_monotonic;
2280         usec_t active_enter_timestamp;
2281         usec_t active_exit_timestamp;
2282         usec_t inactive_enter_timestamp;
2283
2284         bool need_daemon_reload;
2285
2286         /* Service */
2287         pid_t main_pid;
2288         pid_t control_pid;
2289         const char *status_text;
2290         bool running:1;
2291
2292         usec_t start_timestamp;
2293         usec_t exit_timestamp;
2294
2295         int exit_code, exit_status;
2296
2297         usec_t condition_timestamp;
2298         bool condition_result;
2299
2300         /* Socket */
2301         unsigned n_accepted;
2302         unsigned n_connections;
2303         bool accept;
2304
2305         /* Device */
2306         const char *sysfs_path;
2307
2308         /* Mount, Automount */
2309         const char *where;
2310
2311         /* Swap */
2312         const char *what;
2313
2314         LIST_HEAD(ExecStatusInfo, exec);
2315 } UnitStatusInfo;
2316
2317 static void print_status_info(UnitStatusInfo *i) {
2318         ExecStatusInfo *p;
2319         const char *on, *off, *ss;
2320         usec_t timestamp;
2321         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2322         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2323         const char *path;
2324
2325         assert(i);
2326
2327         /* This shows pretty information about a unit. See
2328          * print_property() for a low-level property printer */
2329
2330         printf("%s", strna(i->id));
2331
2332         if (i->description && !streq_ptr(i->id, i->description))
2333                 printf(" - %s", i->description);
2334
2335         printf("\n");
2336
2337         if (i->following)
2338                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2339
2340         if (streq_ptr(i->load_state, "error")) {
2341                 on = ansi_highlight_red(true);
2342                 off = ansi_highlight_red(false);
2343         } else
2344                 on = off = "";
2345
2346         path = i->source_path ? i->source_path : i->fragment_path;
2347
2348         if (i->load_error)
2349                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2350         else if (path && i->unit_file_state)
2351                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2352         else if (path)
2353                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2354         else
2355                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2356
2357         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2358
2359         if (streq_ptr(i->active_state, "failed")) {
2360                 on = ansi_highlight_red(true);
2361                 off = ansi_highlight_red(false);
2362         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2363                 on = ansi_highlight_green(true);
2364                 off = ansi_highlight_green(false);
2365         } else
2366                 on = off = "";
2367
2368         if (ss)
2369                 printf("\t  Active: %s%s (%s)%s",
2370                        on,
2371                        strna(i->active_state),
2372                        ss,
2373                        off);
2374         else
2375                 printf("\t  Active: %s%s%s",
2376                        on,
2377                        strna(i->active_state),
2378                        off);
2379
2380         if (!isempty(i->result) && !streq(i->result, "success"))
2381                 printf(" (Result: %s)", i->result);
2382
2383         timestamp = (streq_ptr(i->active_state, "active")      ||
2384                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2385                     (streq_ptr(i->active_state, "inactive")    ||
2386                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2387                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2388                                                                   i->active_exit_timestamp;
2389
2390         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2391         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2392
2393         if (s1)
2394                 printf(" since %s; %s\n", s2, s1);
2395         else if (s2)
2396                 printf(" since %s\n", s2);
2397         else
2398                 printf("\n");
2399
2400         if (!i->condition_result && i->condition_timestamp > 0) {
2401                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2402                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2403
2404                 if (s1)
2405                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2406                 else if (s2)
2407                         printf("\t          start condition failed at %s\n", s2);
2408         }
2409
2410         if (i->sysfs_path)
2411                 printf("\t  Device: %s\n", i->sysfs_path);
2412         if (i->where)
2413                 printf("\t   Where: %s\n", i->where);
2414         if (i->what)
2415                 printf("\t    What: %s\n", i->what);
2416
2417         if (!strv_isempty(i->documentation)) {
2418                 char **t;
2419                 bool first = true;
2420
2421                 STRV_FOREACH(t, i->documentation) {
2422                         if (first) {
2423                                 printf("\t    Docs: %s\n", *t);
2424                                 first = false;
2425                         } else
2426                                 printf("\t          %s\n", *t);
2427                 }
2428         }
2429
2430         if (i->accept)
2431                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2432
2433         LIST_FOREACH(exec, p, i->exec) {
2434                 char *t;
2435                 bool good;
2436
2437                 /* Only show exited processes here */
2438                 if (p->code == 0)
2439                         continue;
2440
2441                 t = strv_join(p->argv, " ");
2442                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2443                 free(t);
2444
2445                 good = is_clean_exit_lsb(p->code, p->status);
2446                 if (!good) {
2447                         on = ansi_highlight_red(true);
2448                         off = ansi_highlight_red(false);
2449                 } else
2450                         on = off = "";
2451
2452                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2453
2454                 if (p->code == CLD_EXITED) {
2455                         const char *c;
2456
2457                         printf("status=%i", p->status);
2458
2459                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2460                         if (c)
2461                                 printf("/%s", c);
2462
2463                 } else
2464                         printf("signal=%s", signal_to_string(p->status));
2465
2466                 printf(")%s\n", off);
2467
2468                 if (i->main_pid == p->pid &&
2469                     i->start_timestamp == p->start_timestamp &&
2470                     i->exit_timestamp == p->start_timestamp)
2471                         /* Let's not show this twice */
2472                         i->main_pid = 0;
2473
2474                 if (p->pid == i->control_pid)
2475                         i->control_pid = 0;
2476         }
2477
2478         if (i->main_pid > 0 || i->control_pid > 0) {
2479                 printf("\t");
2480
2481                 if (i->main_pid > 0) {
2482                         printf("Main PID: %u", (unsigned) i->main_pid);
2483
2484                         if (i->running) {
2485                                 char *t = NULL;
2486                                 get_process_comm(i->main_pid, &t);
2487                                 if (t) {
2488                                         printf(" (%s)", t);
2489                                         free(t);
2490                                 }
2491                         } else if (i->exit_code > 0) {
2492                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2493
2494                                 if (i->exit_code == CLD_EXITED) {
2495                                         const char *c;
2496
2497                                         printf("status=%i", i->exit_status);
2498
2499                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2500                                         if (c)
2501                                                 printf("/%s", c);
2502
2503                                 } else
2504                                         printf("signal=%s", signal_to_string(i->exit_status));
2505                                 printf(")");
2506                         }
2507                 }
2508
2509                 if (i->main_pid > 0 && i->control_pid > 0)
2510                         printf(";");
2511
2512                 if (i->control_pid > 0) {
2513                         char *t = NULL;
2514
2515                         printf(" Control: %u", (unsigned) i->control_pid);
2516
2517                         get_process_comm(i->control_pid, &t);
2518                         if (t) {
2519                                 printf(" (%s)", t);
2520                                 free(t);
2521                         }
2522                 }
2523
2524                 printf("\n");
2525         }
2526
2527         if (i->status_text)
2528                 printf("\t  Status: \"%s\"\n", i->status_text);
2529
2530         if (i->default_control_group) {
2531                 unsigned c;
2532
2533                 printf("\t  CGroup: %s\n", i->default_control_group);
2534
2535                 if (arg_transport != TRANSPORT_SSH) {
2536                         unsigned k = 0;
2537                         pid_t extra[2];
2538
2539                         c = columns();
2540                         if (c > 18)
2541                                 c -= 18;
2542                         else
2543                                 c = 0;
2544
2545                         if (i->main_pid > 0)
2546                                 extra[k++] = i->main_pid;
2547
2548                         if (i->control_pid > 0)
2549                                 extra[k++] = i->control_pid;
2550
2551                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2552                 }
2553         }
2554
2555         if (i->id && arg_transport != TRANSPORT_SSH) {
2556                 printf("\n");
2557                 show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow, !arg_quiet);
2558         }
2559
2560         if (i->need_daemon_reload)
2561                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2562                        ansi_highlight_red(true),
2563                        ansi_highlight_red(false),
2564                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2565 }
2566
2567 static void show_unit_help(UnitStatusInfo *i) {
2568         char **p;
2569
2570         assert(i);
2571
2572         if (!i->documentation) {
2573                 log_info("Documentation for %s not known.", i->id);
2574                 return;
2575         }
2576
2577         STRV_FOREACH(p, i->documentation) {
2578
2579                 if (startswith(*p, "man:")) {
2580                         size_t k;
2581                         char *e = NULL;
2582                         char *page = NULL, *section = NULL;
2583                         const char *args[4] = { "man", NULL, NULL, NULL };
2584                         pid_t pid;
2585
2586                         k = strlen(*p);
2587
2588                         if ((*p)[k-1] == ')')
2589                                 e = strrchr(*p, '(');
2590
2591                         if (e) {
2592                                 page = strndup((*p) + 4, e - *p - 4);
2593                                 if (!page) {
2594                                         log_error("Out of memory.");
2595                                         return;
2596                                 }
2597
2598                                 section = strndup(e + 1, *p + k - e - 2);
2599                                 if (!section) {
2600                                         free(page);
2601                                         log_error("Out of memory");
2602                                         return;
2603                                 }
2604
2605                                 args[1] = section;
2606                                 args[2] = page;
2607                         } else
2608                                 args[1] = *p + 4;
2609
2610                         pid = fork();
2611                         if (pid < 0) {
2612                                 log_error("Failed to fork: %m");
2613                                 free(page);
2614                                 free(section);
2615                                 continue;
2616                         }
2617
2618                         if (pid == 0) {
2619                                 /* Child */
2620                                 execvp(args[0], (char**) args);
2621                                 log_error("Failed to execute man: %m");
2622                                 _exit(EXIT_FAILURE);
2623                         }
2624
2625                         free(page);
2626                         free(section);
2627
2628                         wait_for_terminate(pid, NULL);
2629                 } else
2630                         log_info("Can't show %s.", *p);
2631         }
2632 }
2633
2634 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2635
2636         assert(name);
2637         assert(iter);
2638         assert(i);
2639
2640         switch (dbus_message_iter_get_arg_type(iter)) {
2641
2642         case DBUS_TYPE_STRING: {
2643                 const char *s;
2644
2645                 dbus_message_iter_get_basic(iter, &s);
2646
2647                 if (!isempty(s)) {
2648                         if (streq(name, "Id"))
2649                                 i->id = s;
2650                         else if (streq(name, "LoadState"))
2651                                 i->load_state = s;
2652                         else if (streq(name, "ActiveState"))
2653                                 i->active_state = s;
2654                         else if (streq(name, "SubState"))
2655                                 i->sub_state = s;
2656                         else if (streq(name, "Description"))
2657                                 i->description = s;
2658                         else if (streq(name, "FragmentPath"))
2659                                 i->fragment_path = s;
2660                         else if (streq(name, "SourcePath"))
2661                                 i->source_path = s;
2662                         else if (streq(name, "DefaultControlGroup"))
2663                                 i->default_control_group = s;
2664                         else if (streq(name, "StatusText"))
2665                                 i->status_text = s;
2666                         else if (streq(name, "SysFSPath"))
2667                                 i->sysfs_path = s;
2668                         else if (streq(name, "Where"))
2669                                 i->where = s;
2670                         else if (streq(name, "What"))
2671                                 i->what = s;
2672                         else if (streq(name, "Following"))
2673                                 i->following = s;
2674                         else if (streq(name, "UnitFileState"))
2675                                 i->unit_file_state = s;
2676                         else if (streq(name, "Result"))
2677                                 i->result = s;
2678                 }
2679
2680                 break;
2681         }
2682
2683         case DBUS_TYPE_BOOLEAN: {
2684                 dbus_bool_t b;
2685
2686                 dbus_message_iter_get_basic(iter, &b);
2687
2688                 if (streq(name, "Accept"))
2689                         i->accept = b;
2690                 else if (streq(name, "NeedDaemonReload"))
2691                         i->need_daemon_reload = b;
2692                 else if (streq(name, "ConditionResult"))
2693                         i->condition_result = b;
2694
2695                 break;
2696         }
2697
2698         case DBUS_TYPE_UINT32: {
2699                 uint32_t u;
2700
2701                 dbus_message_iter_get_basic(iter, &u);
2702
2703                 if (streq(name, "MainPID")) {
2704                         if (u > 0) {
2705                                 i->main_pid = (pid_t) u;
2706                                 i->running = true;
2707                         }
2708                 } else if (streq(name, "ControlPID"))
2709                         i->control_pid = (pid_t) u;
2710                 else if (streq(name, "ExecMainPID")) {
2711                         if (u > 0)
2712                                 i->main_pid = (pid_t) u;
2713                 } else if (streq(name, "NAccepted"))
2714                         i->n_accepted = u;
2715                 else if (streq(name, "NConnections"))
2716                         i->n_connections = u;
2717
2718                 break;
2719         }
2720
2721         case DBUS_TYPE_INT32: {
2722                 int32_t j;
2723
2724                 dbus_message_iter_get_basic(iter, &j);
2725
2726                 if (streq(name, "ExecMainCode"))
2727                         i->exit_code = (int) j;
2728                 else if (streq(name, "ExecMainStatus"))
2729                         i->exit_status = (int) j;
2730
2731                 break;
2732         }
2733
2734         case DBUS_TYPE_UINT64: {
2735                 uint64_t u;
2736
2737                 dbus_message_iter_get_basic(iter, &u);
2738
2739                 if (streq(name, "ExecMainStartTimestamp"))
2740                         i->start_timestamp = (usec_t) u;
2741                 else if (streq(name, "ExecMainExitTimestamp"))
2742                         i->exit_timestamp = (usec_t) u;
2743                 else if (streq(name, "ActiveEnterTimestamp"))
2744                         i->active_enter_timestamp = (usec_t) u;
2745                 else if (streq(name, "InactiveEnterTimestamp"))
2746                         i->inactive_enter_timestamp = (usec_t) u;
2747                 else if (streq(name, "InactiveExitTimestamp"))
2748                         i->inactive_exit_timestamp = (usec_t) u;
2749                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2750                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2751                 else if (streq(name, "ActiveExitTimestamp"))
2752                         i->active_exit_timestamp = (usec_t) u;
2753                 else if (streq(name, "ConditionTimestamp"))
2754                         i->condition_timestamp = (usec_t) u;
2755
2756                 break;
2757         }
2758
2759         case DBUS_TYPE_ARRAY: {
2760
2761                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2762                     startswith(name, "Exec")) {
2763                         DBusMessageIter sub;
2764
2765                         dbus_message_iter_recurse(iter, &sub);
2766                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2767                                 ExecStatusInfo *info;
2768                                 int r;
2769
2770                                 if (!(info = new0(ExecStatusInfo, 1)))
2771                                         return -ENOMEM;
2772
2773                                 if (!(info->name = strdup(name))) {
2774                                         free(info);
2775                                         return -ENOMEM;
2776                                 }
2777
2778                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2779                                         free(info);
2780                                         return r;
2781                                 }
2782
2783                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2784
2785                                 dbus_message_iter_next(&sub);
2786                         }
2787                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2788                            streq(name, "Documentation")) {
2789
2790                         DBusMessageIter sub;
2791
2792                         dbus_message_iter_recurse(iter, &sub);
2793                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2794                                 const char *s;
2795                                 char **l;
2796
2797                                 dbus_message_iter_get_basic(&sub, &s);
2798
2799                                 l = strv_append(i->documentation, s);
2800                                 if (!l)
2801                                         return -ENOMEM;
2802
2803                                 strv_free(i->documentation);
2804                                 i->documentation = l;
2805
2806                                 dbus_message_iter_next(&sub);
2807                         }
2808                 }
2809
2810                 break;
2811         }
2812
2813         case DBUS_TYPE_STRUCT: {
2814
2815                 if (streq(name, "LoadError")) {
2816                         DBusMessageIter sub;
2817                         const char *n, *message;
2818                         int r;
2819
2820                         dbus_message_iter_recurse(iter, &sub);
2821
2822                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2823                         if (r < 0)
2824                                 return r;
2825
2826                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2827                         if (r < 0)
2828                                 return r;
2829
2830                         if (!isempty(message))
2831                                 i->load_error = message;
2832                 }
2833
2834                 break;
2835         }
2836         }
2837
2838         return 0;
2839 }
2840
2841 static int print_property(const char *name, DBusMessageIter *iter) {
2842         assert(name);
2843         assert(iter);
2844
2845         /* This is a low-level property printer, see
2846          * print_status_info() for the nicer output */
2847
2848         if (arg_property && !strv_find(arg_property, name))
2849                 return 0;
2850
2851         switch (dbus_message_iter_get_arg_type(iter)) {
2852
2853         case DBUS_TYPE_STRUCT: {
2854                 DBusMessageIter sub;
2855                 dbus_message_iter_recurse(iter, &sub);
2856
2857                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2858                         uint32_t u;
2859
2860                         dbus_message_iter_get_basic(&sub, &u);
2861
2862                         if (u)
2863                                 printf("%s=%u\n", name, (unsigned) u);
2864                         else if (arg_all)
2865                                 printf("%s=\n", name);
2866
2867                         return 0;
2868                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2869                         const char *s;
2870
2871                         dbus_message_iter_get_basic(&sub, &s);
2872
2873                         if (arg_all || s[0])
2874                                 printf("%s=%s\n", name, s);
2875
2876                         return 0;
2877                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2878                         const char *a = NULL, *b = NULL;
2879
2880                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2881                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2882
2883                         if (arg_all || !isempty(a) || !isempty(b))
2884                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2885
2886                         return 0;
2887                 }
2888
2889                 break;
2890         }
2891
2892         case DBUS_TYPE_ARRAY:
2893
2894                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2895                         DBusMessageIter sub, sub2;
2896
2897                         dbus_message_iter_recurse(iter, &sub);
2898                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2899                                 const char *path;
2900                                 dbus_bool_t ignore;
2901
2902                                 dbus_message_iter_recurse(&sub, &sub2);
2903
2904                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2905                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2906                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2907
2908                                 dbus_message_iter_next(&sub);
2909                         }
2910
2911                         return 0;
2912
2913                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2914                         DBusMessageIter sub, sub2;
2915
2916                         dbus_message_iter_recurse(iter, &sub);
2917                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2918                                 const char *type, *path;
2919
2920                                 dbus_message_iter_recurse(&sub, &sub2);
2921
2922                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2923                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2924                                         printf("%s=%s\n", type, path);
2925
2926                                 dbus_message_iter_next(&sub);
2927                         }
2928
2929                         return 0;
2930
2931                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2932                         DBusMessageIter sub, sub2;
2933
2934                         dbus_message_iter_recurse(iter, &sub);
2935                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2936                                 const char *base;
2937                                 uint64_t value, next_elapse;
2938
2939                                 dbus_message_iter_recurse(&sub, &sub2);
2940
2941                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2942                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2943                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2944                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2945
2946                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2947                                                base,
2948                                                format_timespan(timespan1, sizeof(timespan1), value),
2949                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2950                                 }
2951
2952                                 dbus_message_iter_next(&sub);
2953                         }
2954
2955                         return 0;
2956
2957                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2958                         DBusMessageIter sub, sub2;
2959
2960                         dbus_message_iter_recurse(iter, &sub);
2961                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2962                                 const char *controller, *attr, *value;
2963
2964                                 dbus_message_iter_recurse(&sub, &sub2);
2965
2966                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2967                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2968                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2969
2970                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2971                                                controller,
2972                                                attr,
2973                                                value);
2974                                 }
2975
2976                                 dbus_message_iter_next(&sub);
2977                         }
2978
2979                         return 0;
2980
2981                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2982                         DBusMessageIter sub;
2983
2984                         dbus_message_iter_recurse(iter, &sub);
2985                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2986                                 ExecStatusInfo info;
2987
2988                                 zero(info);
2989                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2990                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2991                                         char *t;
2992
2993                                         t = strv_join(info.argv, " ");
2994
2995                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2996                                                name,
2997                                                strna(info.path),
2998                                                strna(t),
2999                                                yes_no(info.ignore),
3000                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3001                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3002                                                (unsigned) info. pid,
3003                                                sigchld_code_to_string(info.code),
3004                                                info.status,
3005                                                info.code == CLD_EXITED ? "" : "/",
3006                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3007
3008                                         free(t);
3009                                 }
3010
3011                                 free(info.path);
3012                                 strv_free(info.argv);
3013
3014                                 dbus_message_iter_next(&sub);
3015                         }
3016
3017                         return 0;
3018                 }
3019
3020                 break;
3021         }
3022
3023         if (generic_print_property(name, iter, arg_all) > 0)
3024                 return 0;
3025
3026         if (arg_all)
3027                 printf("%s=[unprintable]\n", name);
3028
3029         return 0;
3030 }
3031
3032 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3033         DBusMessage *m = NULL, *reply = NULL;
3034         const char *interface = "";
3035         int r;
3036         DBusError error;
3037         DBusMessageIter iter, sub, sub2, sub3;
3038         UnitStatusInfo info;
3039         ExecStatusInfo *p;
3040
3041         assert(bus);
3042         assert(path);
3043         assert(new_line);
3044
3045         zero(info);
3046         dbus_error_init(&error);
3047
3048         if (!(m = dbus_message_new_method_call(
3049                               "org.freedesktop.systemd1",
3050                               path,
3051                               "org.freedesktop.DBus.Properties",
3052                               "GetAll"))) {
3053                 log_error("Could not allocate message.");
3054                 r = -ENOMEM;
3055                 goto finish;
3056         }
3057
3058         if (!dbus_message_append_args(m,
3059                                       DBUS_TYPE_STRING, &interface,
3060                                       DBUS_TYPE_INVALID)) {
3061                 log_error("Could not append arguments to message.");
3062                 r = -ENOMEM;
3063                 goto finish;
3064         }
3065
3066         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3067                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3068                 r = -EIO;
3069                 goto finish;
3070         }
3071
3072         if (!dbus_message_iter_init(reply, &iter) ||
3073             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3074             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3075                 log_error("Failed to parse reply.");
3076                 r = -EIO;
3077                 goto finish;
3078         }
3079
3080         dbus_message_iter_recurse(&iter, &sub);
3081
3082         if (*new_line)
3083                 printf("\n");
3084
3085         *new_line = true;
3086
3087         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3088                 const char *name;
3089
3090                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
3091                         log_error("Failed to parse reply.");
3092                         r = -EIO;
3093                         goto finish;
3094                 }
3095
3096                 dbus_message_iter_recurse(&sub, &sub2);
3097
3098                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
3099                         log_error("Failed to parse reply.");
3100                         r = -EIO;
3101                         goto finish;
3102                 }
3103
3104                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
3105                         log_error("Failed to parse reply.");
3106                         r = -EIO;
3107                         goto finish;
3108                 }
3109
3110                 dbus_message_iter_recurse(&sub2, &sub3);
3111
3112                 if (show_properties)
3113                         r = print_property(name, &sub3);
3114                 else
3115                         r = status_property(name, &sub3, &info);
3116
3117                 if (r < 0) {
3118                         log_error("Failed to parse reply.");
3119                         r = -EIO;
3120                         goto finish;
3121                 }
3122
3123                 dbus_message_iter_next(&sub);
3124         }
3125
3126         r = 0;
3127
3128         if (!show_properties) {
3129                 if (streq(verb, "help"))
3130                         show_unit_help(&info);
3131                 else
3132                         print_status_info(&info);
3133         }
3134
3135         strv_free(info.documentation);
3136
3137         if (!streq_ptr(info.active_state, "active") &&
3138             !streq_ptr(info.active_state, "reloading") &&
3139             streq(verb, "status"))
3140                 /* According to LSB: "program not running" */
3141                 r = 3;
3142
3143         while ((p = info.exec)) {
3144                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3145                 exec_status_info_free(p);
3146         }
3147
3148 finish:
3149         if (m)
3150                 dbus_message_unref(m);
3151
3152         if (reply)
3153                 dbus_message_unref(reply);
3154
3155         dbus_error_free(&error);
3156
3157         return r;
3158 }
3159
3160 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3161         DBusMessage *m = NULL, *reply = NULL;
3162         const char *path = NULL;
3163         DBusError error;
3164         int r;
3165
3166         dbus_error_init(&error);
3167
3168         m = dbus_message_new_method_call(
3169                               "org.freedesktop.systemd1",
3170                               "/org/freedesktop/systemd1",
3171                               "org.freedesktop.systemd1.Manager",
3172                               "GetUnitByPID");
3173         if (!m) {
3174                 log_error("Could not allocate message.");
3175                 r = -ENOMEM;
3176                 goto finish;
3177         }
3178
3179         if (!dbus_message_append_args(m,
3180                                       DBUS_TYPE_UINT32, &pid,
3181                                       DBUS_TYPE_INVALID)) {
3182                 log_error("Could not append arguments to message.");
3183                 r = -ENOMEM;
3184                 goto finish;
3185         }
3186
3187         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3188         if (!reply) {
3189                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3190                 r = -EIO;
3191                 goto finish;
3192         }
3193
3194         if (!dbus_message_get_args(reply, &error,
3195                                    DBUS_TYPE_OBJECT_PATH, &path,
3196                                    DBUS_TYPE_INVALID)) {
3197                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3198                 r = -EIO;
3199                 goto finish;
3200         }
3201
3202         r = show_one(verb, bus, path, false, new_line);
3203
3204 finish:
3205         if (m)
3206                 dbus_message_unref(m);
3207
3208         if (reply)
3209                 dbus_message_unref(reply);
3210
3211         dbus_error_free(&error);
3212
3213         return r;
3214 }
3215
3216 static int show(DBusConnection *bus, char **args) {
3217         int r, ret = 0;
3218         bool show_properties, new_line = false;
3219         char **name;
3220
3221         assert(bus);
3222         assert(args);
3223
3224         show_properties = streq(args[0], "show");
3225
3226         if (show_properties)
3227                 pager_open_if_enabled();
3228
3229         if (show_properties && strv_length(args) <= 1) {
3230                 /* If not argument is specified inspect the manager
3231                  * itself */
3232
3233                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3234         }
3235
3236         STRV_FOREACH(name, args+1) {
3237                 uint32_t id;
3238
3239                 if (safe_atou32(*name, &id) < 0) {
3240
3241                         /* Interpret as unit name */
3242
3243                         char *p = unit_dbus_path_from_name(*name);
3244                         if (!p)
3245                                 return -ENOMEM;
3246
3247                         r = show_one(args[0], bus, p, show_properties, &new_line);
3248                         free(p);
3249
3250                         if (r != 0)
3251                                 ret = r;
3252
3253                 } else if (show_properties) {
3254
3255                         /* Interpret as job id */
3256
3257                         char *p;
3258                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3259                                 return -ENOMEM;
3260
3261                         r = show_one(args[0], bus, p, show_properties, &new_line);
3262                         free(p);
3263
3264                         if (r != 0)
3265                                 ret = r;
3266
3267                 } else {
3268
3269                         /* Interpret as PID */
3270
3271                         r = show_one_by_pid(args[0], bus, id, &new_line);
3272                         if (r != 0)
3273                                 ret = r;
3274                 }
3275         }
3276
3277         return ret;
3278 }
3279
3280 static int dump(DBusConnection *bus, char **args) {
3281         DBusMessage *m = NULL, *reply = NULL;
3282         DBusError error;
3283         int r;
3284         const char *text;
3285
3286         dbus_error_init(&error);
3287
3288         pager_open_if_enabled();
3289
3290         if (!(m = dbus_message_new_method_call(
3291                               "org.freedesktop.systemd1",
3292                               "/org/freedesktop/systemd1",
3293                               "org.freedesktop.systemd1.Manager",
3294                               "Dump"))) {
3295                 log_error("Could not allocate message.");
3296                 return -ENOMEM;
3297         }
3298
3299         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3300                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3301                 r = -EIO;
3302                 goto finish;
3303         }
3304
3305         if (!dbus_message_get_args(reply, &error,
3306                                    DBUS_TYPE_STRING, &text,
3307                                    DBUS_TYPE_INVALID)) {
3308                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3309                 r = -EIO;
3310                 goto finish;
3311         }
3312
3313         fputs(text, stdout);
3314
3315         r = 0;
3316
3317 finish:
3318         if (m)
3319                 dbus_message_unref(m);
3320
3321         if (reply)
3322                 dbus_message_unref(reply);
3323
3324         dbus_error_free(&error);
3325
3326         return r;
3327 }
3328
3329 static int snapshot(DBusConnection *bus, char **args) {
3330         DBusMessage *m = NULL, *reply = NULL;
3331         DBusError error;
3332         int r;
3333         const char *name = "", *path, *id;
3334         dbus_bool_t cleanup = FALSE;
3335         DBusMessageIter iter, sub;
3336         const char
3337                 *interface = "org.freedesktop.systemd1.Unit",
3338                 *property = "Id";
3339
3340         dbus_error_init(&error);
3341
3342         if (!(m = dbus_message_new_method_call(
3343                               "org.freedesktop.systemd1",
3344                               "/org/freedesktop/systemd1",
3345                               "org.freedesktop.systemd1.Manager",
3346                               "CreateSnapshot"))) {
3347                 log_error("Could not allocate message.");
3348                 return -ENOMEM;
3349         }
3350
3351         if (strv_length(args) > 1)
3352                 name = args[1];
3353
3354         if (!dbus_message_append_args(m,
3355                                       DBUS_TYPE_STRING, &name,
3356                                       DBUS_TYPE_BOOLEAN, &cleanup,
3357                                       DBUS_TYPE_INVALID)) {
3358                 log_error("Could not append arguments to message.");
3359                 r = -ENOMEM;
3360                 goto finish;
3361         }
3362
3363         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3364                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3365                 r = -EIO;
3366                 goto finish;
3367         }
3368
3369         if (!dbus_message_get_args(reply, &error,
3370                                    DBUS_TYPE_OBJECT_PATH, &path,
3371                                    DBUS_TYPE_INVALID)) {
3372                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3373                 r = -EIO;
3374                 goto finish;
3375         }
3376
3377         dbus_message_unref(m);
3378         if (!(m = dbus_message_new_method_call(
3379                               "org.freedesktop.systemd1",
3380                               path,
3381                               "org.freedesktop.DBus.Properties",
3382                               "Get"))) {
3383                 log_error("Could not allocate message.");
3384                 return -ENOMEM;
3385         }
3386
3387         if (!dbus_message_append_args(m,
3388                                       DBUS_TYPE_STRING, &interface,
3389                                       DBUS_TYPE_STRING, &property,
3390                                       DBUS_TYPE_INVALID)) {
3391                 log_error("Could not append arguments to message.");
3392                 r = -ENOMEM;
3393                 goto finish;
3394         }
3395
3396         dbus_message_unref(reply);
3397         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3398                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3399                 r = -EIO;
3400                 goto finish;
3401         }
3402
3403         if (!dbus_message_iter_init(reply, &iter) ||
3404             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3405                 log_error("Failed to parse reply.");
3406                 r = -EIO;
3407                 goto finish;
3408         }
3409
3410         dbus_message_iter_recurse(&iter, &sub);
3411
3412         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3413                 log_error("Failed to parse reply.");
3414                 r = -EIO;
3415                 goto finish;
3416         }
3417
3418         dbus_message_iter_get_basic(&sub, &id);
3419
3420         if (!arg_quiet)
3421                 puts(id);
3422         r = 0;
3423
3424 finish:
3425         if (m)
3426                 dbus_message_unref(m);
3427
3428         if (reply)
3429                 dbus_message_unref(reply);
3430
3431         dbus_error_free(&error);
3432
3433         return r;
3434 }
3435
3436 static int delete_snapshot(DBusConnection *bus, char **args) {
3437         DBusMessage *m = NULL, *reply = NULL;
3438         int r;
3439         DBusError error;
3440         char **name;
3441
3442         assert(bus);
3443         assert(args);
3444
3445         dbus_error_init(&error);
3446
3447         STRV_FOREACH(name, args+1) {
3448                 const char *path = NULL;
3449
3450                 if (!(m = dbus_message_new_method_call(
3451                                       "org.freedesktop.systemd1",
3452                                       "/org/freedesktop/systemd1",
3453                                       "org.freedesktop.systemd1.Manager",
3454                                       "GetUnit"))) {
3455                         log_error("Could not allocate message.");
3456                         r = -ENOMEM;
3457                         goto finish;
3458                 }
3459
3460                 if (!dbus_message_append_args(m,
3461                                               DBUS_TYPE_STRING, name,
3462                                               DBUS_TYPE_INVALID)) {
3463                         log_error("Could not append arguments to message.");
3464                         r = -ENOMEM;
3465                         goto finish;
3466                 }
3467
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_get_args(reply, &error,
3475                                            DBUS_TYPE_OBJECT_PATH, &path,
3476                                            DBUS_TYPE_INVALID)) {
3477                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3478                         r = -EIO;
3479                         goto finish;
3480                 }
3481
3482                 dbus_message_unref(m);
3483                 if (!(m = dbus_message_new_method_call(
3484                                       "org.freedesktop.systemd1",
3485                                       path,
3486                                       "org.freedesktop.systemd1.Snapshot",
3487                                       "Remove"))) {
3488                         log_error("Could not allocate message.");
3489                         r = -ENOMEM;
3490                         goto finish;
3491                 }
3492
3493                 dbus_message_unref(reply);
3494                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3495                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3496                         r = -EIO;
3497                         goto finish;
3498                 }
3499
3500                 dbus_message_unref(m);
3501                 dbus_message_unref(reply);
3502                 m = reply = NULL;
3503         }
3504
3505         r = 0;
3506
3507 finish:
3508         if (m)
3509                 dbus_message_unref(m);
3510
3511         if (reply)
3512                 dbus_message_unref(reply);
3513
3514         dbus_error_free(&error);
3515
3516         return r;
3517 }
3518
3519 static int daemon_reload(DBusConnection *bus, char **args) {
3520         DBusMessage *m = NULL, *reply = NULL;
3521         DBusError error;
3522         int r;
3523         const char *method;
3524
3525         dbus_error_init(&error);
3526
3527         if (arg_action == ACTION_RELOAD)
3528                 method = "Reload";
3529         else if (arg_action == ACTION_REEXEC)
3530                 method = "Reexecute";
3531         else {
3532                 assert(arg_action == ACTION_SYSTEMCTL);
3533
3534                 method =
3535                         streq(args[0], "clear-jobs")    ||
3536                         streq(args[0], "cancel")        ? "ClearJobs" :
3537                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3538                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3539                         streq(args[0], "halt")          ? "Halt" :
3540                         streq(args[0], "poweroff")      ? "PowerOff" :
3541                         streq(args[0], "reboot")        ? "Reboot" :
3542                         streq(args[0], "kexec")         ? "KExec" :
3543                         streq(args[0], "exit")          ? "Exit" :
3544                                     /* "daemon-reload" */ "Reload";
3545         }
3546
3547         if (!(m = dbus_message_new_method_call(
3548                               "org.freedesktop.systemd1",
3549                               "/org/freedesktop/systemd1",
3550                               "org.freedesktop.systemd1.Manager",
3551                               method))) {
3552                 log_error("Could not allocate message.");
3553                 return -ENOMEM;
3554         }
3555
3556         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3557
3558                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3559                         /* There's always a fallback possible for
3560                          * legacy actions. */
3561                         r = -EADDRNOTAVAIL;
3562                         goto finish;
3563                 }
3564
3565                 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3566                         /* On reexecution, we expect a disconnect, not
3567                          * a reply */
3568                         r = 0;
3569                         goto finish;
3570                 }
3571
3572                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3573                 r = -EIO;
3574                 goto finish;
3575         }
3576
3577         r = 0;
3578
3579 finish:
3580         if (m)
3581                 dbus_message_unref(m);
3582
3583         if (reply)
3584                 dbus_message_unref(reply);
3585
3586         dbus_error_free(&error);
3587
3588         return r;
3589 }
3590
3591 static int reset_failed(DBusConnection *bus, char **args) {
3592         DBusMessage *m = NULL;
3593         int r;
3594         DBusError error;
3595         char **name;
3596
3597         assert(bus);
3598         dbus_error_init(&error);
3599
3600         if (strv_length(args) <= 1)
3601                 return daemon_reload(bus, args);
3602
3603         STRV_FOREACH(name, args+1) {
3604                 DBusMessage *reply;
3605
3606                 if (!(m = dbus_message_new_method_call(
3607                                       "org.freedesktop.systemd1",
3608                                       "/org/freedesktop/systemd1",
3609                                       "org.freedesktop.systemd1.Manager",
3610                                       "ResetFailedUnit"))) {
3611                         log_error("Could not allocate message.");
3612                         r = -ENOMEM;
3613                         goto finish;
3614                 }
3615
3616                 if (!dbus_message_append_args(m,
3617                                               DBUS_TYPE_STRING, name,
3618                                               DBUS_TYPE_INVALID)) {
3619                         log_error("Could not append arguments to message.");
3620                         r = -ENOMEM;
3621                         goto finish;
3622                 }
3623
3624                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3625                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3626                         r = -EIO;
3627                         goto finish;
3628                 }
3629
3630                 dbus_message_unref(m);
3631                 dbus_message_unref(reply);
3632                 m = reply = NULL;
3633         }
3634
3635         r = 0;
3636
3637 finish:
3638         if (m)
3639                 dbus_message_unref(m);
3640
3641         dbus_error_free(&error);
3642
3643         return r;
3644 }
3645
3646 static int show_enviroment(DBusConnection *bus, char **args) {
3647         DBusMessage *m = NULL, *reply = NULL;
3648         DBusError error;
3649         DBusMessageIter iter, sub, sub2;
3650         int r;
3651         const char
3652                 *interface = "org.freedesktop.systemd1.Manager",
3653                 *property = "Environment";
3654
3655         dbus_error_init(&error);
3656
3657         pager_open_if_enabled();
3658
3659         if (!(m = dbus_message_new_method_call(
3660                               "org.freedesktop.systemd1",
3661                               "/org/freedesktop/systemd1",
3662                               "org.freedesktop.DBus.Properties",
3663                               "Get"))) {
3664                 log_error("Could not allocate message.");
3665                 return -ENOMEM;
3666         }
3667
3668         if (!dbus_message_append_args(m,
3669                                       DBUS_TYPE_STRING, &interface,
3670                                       DBUS_TYPE_STRING, &property,
3671                                       DBUS_TYPE_INVALID)) {
3672                 log_error("Could not append arguments to message.");
3673                 r = -ENOMEM;
3674                 goto finish;
3675         }
3676
3677         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3678                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3679                 r = -EIO;
3680                 goto finish;
3681         }
3682
3683         if (!dbus_message_iter_init(reply, &iter) ||
3684             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3685                 log_error("Failed to parse reply.");
3686                 r = -EIO;
3687                 goto finish;
3688         }
3689
3690         dbus_message_iter_recurse(&iter, &sub);
3691
3692         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3693             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3694                 log_error("Failed to parse reply.");
3695                 r = -EIO;
3696                 goto finish;
3697         }
3698
3699         dbus_message_iter_recurse(&sub, &sub2);
3700
3701         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3702                 const char *text;
3703
3704                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3705                         log_error("Failed to parse reply.");
3706                         r = -EIO;
3707                         goto finish;
3708                 }
3709
3710                 dbus_message_iter_get_basic(&sub2, &text);
3711                 printf("%s\n", text);
3712
3713                 dbus_message_iter_next(&sub2);
3714         }
3715
3716         r = 0;
3717
3718 finish:
3719         if (m)
3720                 dbus_message_unref(m);
3721
3722         if (reply)
3723                 dbus_message_unref(reply);
3724
3725         dbus_error_free(&error);
3726
3727         return r;
3728 }
3729
3730 static int switch_root(DBusConnection *bus, char **args) {
3731         DBusMessage *m = NULL, *reply = NULL;
3732         unsigned l;
3733         const char *root, *init;
3734         DBusError error;
3735         int r;
3736
3737         dbus_error_init(&error);
3738
3739         l = strv_length(args);
3740         if (l < 2 || l > 3) {
3741                 log_error("Wrong number of arguments.");
3742                 return -EINVAL;
3743         }
3744
3745         root = args[1];
3746         init = l >= 3 ? args[2] : "";
3747
3748         m = dbus_message_new_method_call(
3749                         "org.freedesktop.systemd1",
3750                         "/org/freedesktop/systemd1",
3751                         "org.freedesktop.systemd1.Manager",
3752                         "SwitchRoot");
3753         if (!m) {
3754                 log_error("Could not allocate message.");
3755                 return -ENOMEM;
3756         }
3757
3758         if (!dbus_message_append_args(
3759                             m,
3760                             DBUS_TYPE_STRING, &root,
3761                             DBUS_TYPE_STRING, &init,
3762                             DBUS_TYPE_INVALID)) {
3763                 log_error("Could not append arguments to message.");
3764                 r = -ENOMEM;
3765                 goto finish;
3766         }
3767
3768         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3769         if (!reply) {
3770                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3771                 r = -EIO;
3772                 goto finish;
3773         }
3774
3775         r = 0;
3776
3777 finish:
3778         if (m)
3779                 dbus_message_unref(m);
3780
3781         if (reply)
3782                 dbus_message_unref(reply);
3783
3784         dbus_error_free(&error);
3785
3786         return r;
3787 }
3788
3789 static int set_environment(DBusConnection *bus, char **args) {
3790         DBusMessage *m = NULL, *reply = NULL;
3791         DBusError error;
3792         int r;
3793         const char *method;
3794         DBusMessageIter iter, sub;
3795         char **name;
3796
3797         dbus_error_init(&error);
3798
3799         method = streq(args[0], "set-environment")
3800                 ? "SetEnvironment"
3801                 : "UnsetEnvironment";
3802
3803         if (!(m = dbus_message_new_method_call(
3804                               "org.freedesktop.systemd1",
3805                               "/org/freedesktop/systemd1",
3806                               "org.freedesktop.systemd1.Manager",
3807                               method))) {
3808
3809                 log_error("Could not allocate message.");
3810                 return -ENOMEM;
3811         }
3812
3813         dbus_message_iter_init_append(m, &iter);
3814
3815         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3816                 log_error("Could not append arguments to message.");
3817                 r = -ENOMEM;
3818                 goto finish;
3819         }
3820
3821         STRV_FOREACH(name, args+1)
3822                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3823                         log_error("Could not append arguments to message.");
3824                         r = -ENOMEM;
3825                         goto finish;
3826                 }
3827
3828         if (!dbus_message_iter_close_container(&iter, &sub)) {
3829                 log_error("Could not append arguments to message.");
3830                 r = -ENOMEM;
3831                 goto finish;
3832         }
3833
3834         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3835                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3836                 r = -EIO;
3837                 goto finish;
3838         }
3839
3840         r = 0;
3841
3842 finish:
3843         if (m)
3844                 dbus_message_unref(m);
3845
3846         if (reply)
3847                 dbus_message_unref(reply);
3848
3849         dbus_error_free(&error);
3850
3851         return r;
3852 }
3853
3854 static int enable_sysv_units(char **args) {
3855         int r = 0;
3856
3857 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3858         const char *verb = args[0];
3859         unsigned f = 1, t = 1;
3860         LookupPaths paths;
3861
3862         if (arg_scope != UNIT_FILE_SYSTEM)
3863                 return 0;
3864
3865         if (!streq(verb, "enable") &&
3866             !streq(verb, "disable") &&
3867             !streq(verb, "is-enabled"))
3868                 return 0;
3869
3870         /* Processes all SysV units, and reshuffles the array so that
3871          * afterwards only the native units remain */
3872
3873         zero(paths);
3874         r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
3875         if (r < 0)
3876                 return r;
3877
3878         r = 0;
3879         for (f = 1; args[f]; f++) {
3880                 const char *name;
3881                 char *p;
3882                 bool found_native = false, found_sysv;
3883                 unsigned c = 1;
3884                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3885                 char **k, *l, *q = NULL;
3886                 int j;
3887                 pid_t pid;
3888                 siginfo_t status;
3889
3890                 name = args[f];
3891
3892                 if (!endswith(name, ".service"))
3893                         continue;
3894
3895                 if (path_is_absolute(name))
3896                         continue;
3897
3898                 STRV_FOREACH(k, paths.unit_path) {
3899                         p = NULL;
3900
3901                         if (!isempty(arg_root))
3902                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3903                         else
3904                                 asprintf(&p, "%s/%s", *k, name);
3905
3906                         if (!p) {
3907                                 log_error("No memory");
3908                                 r = -ENOMEM;
3909                                 goto finish;
3910                         }
3911
3912                         found_native = access(p, F_OK) >= 0;
3913                         free(p);
3914
3915                         if (found_native)
3916                                 break;
3917                 }
3918
3919                 if (found_native)
3920                         continue;
3921
3922                 p = NULL;
3923                 if (!isempty(arg_root))
3924                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3925                 else
3926                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3927                 if (!p) {
3928                         log_error("No memory");
3929                         r = -ENOMEM;
3930                         goto finish;
3931                 }
3932
3933                 p[strlen(p) - sizeof(".service") + 1] = 0;
3934                 found_sysv = access(p, F_OK) >= 0;
3935
3936                 if (!found_sysv) {
3937                         free(p);
3938                         continue;
3939                 }
3940
3941                 /* Mark this entry, so that we don't try enabling it as native unit */
3942                 args[f] = (char*) "";
3943
3944                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3945
3946                 if (!isempty(arg_root))
3947                         argv[c++] = q = strappend("--root=", arg_root);
3948
3949                 argv[c++] = path_get_file_name(p);
3950                 argv[c++] =
3951                         streq(verb, "enable") ? "on" :
3952                         streq(verb, "disable") ? "off" : "--level=5";
3953                 argv[c] = NULL;
3954
3955                 l = strv_join((char**)argv, " ");
3956                 if (!l) {
3957                         log_error("No memory.");
3958                         free(q);
3959                         free(p);
3960                         r = -ENOMEM;
3961                         goto finish;
3962                 }
3963
3964                 log_info("Executing %s", l);
3965                 free(l);
3966
3967                 pid = fork();
3968                 if (pid < 0) {
3969                         log_error("Failed to fork: %m");
3970                         free(p);
3971                         free(q);
3972                         r = -errno;
3973                         goto finish;
3974                 } else if (pid == 0) {
3975                         /* Child */
3976
3977                         execv(argv[0], (char**) argv);
3978                         _exit(EXIT_FAILURE);
3979                 }
3980
3981                 free(p);
3982                 free(q);
3983
3984                 j = wait_for_terminate(pid, &status);
3985                 if (j < 0) {
3986                         log_error("Failed to wait for child: %s", strerror(-r));
3987                         r = j;
3988                         goto finish;
3989                 }
3990
3991                 if (status.si_code == CLD_EXITED) {
3992                         if (streq(verb, "is-enabled")) {
3993                                 if (status.si_status == 0) {
3994                                         if (!arg_quiet)
3995                                                 puts("enabled");
3996                                         r = 1;
3997                                 } else {
3998                                         if (!arg_quiet)
3999                                                 puts("disabled");
4000                                 }
4001
4002                         } else if (status.si_status != 0) {
4003                                 r = -EINVAL;
4004                                 goto finish;
4005                         }
4006                 } else {
4007                         r = -EPROTO;
4008                         goto finish;
4009                 }
4010         }
4011
4012 finish:
4013         lookup_paths_free(&paths);
4014
4015         /* Drop all SysV units */
4016         for (f = 1, t = 1; args[f]; f++) {
4017
4018                 if (isempty(args[f]))
4019                         continue;
4020
4021                 args[t++] = args[f];
4022         }
4023
4024         args[t] = NULL;
4025
4026 #endif
4027         return r;
4028 }
4029
4030 static int enable_unit(DBusConnection *bus, char **args) {
4031         const char *verb = args[0];
4032         UnitFileChange *changes = NULL;
4033         unsigned n_changes = 0, i;
4034         int carries_install_info = -1;
4035         DBusMessage *m = NULL, *reply = NULL;
4036         int r;
4037         DBusError error;
4038
4039         r = enable_sysv_units(args);
4040         if (r < 0)
4041                 return r;
4042
4043         if (!args[1])
4044                 return 0;
4045
4046         dbus_error_init(&error);
4047
4048         if (!bus || avoid_bus()) {
4049                 if (streq(verb, "enable")) {
4050                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4051                         carries_install_info = r;
4052                 } else if (streq(verb, "disable"))
4053                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4054                 else if (streq(verb, "reenable")) {
4055                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4056                         carries_install_info = r;
4057                 } else if (streq(verb, "link"))
4058                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4059                 else if (streq(verb, "preset")) {
4060                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4061                         carries_install_info = r;
4062                 } else if (streq(verb, "mask"))
4063                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4064                 else if (streq(verb, "unmask"))
4065                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4066                 else
4067                         assert_not_reached("Unknown verb");
4068
4069                 if (r < 0) {
4070                         log_error("Operation failed: %s", strerror(-r));
4071                         goto finish;
4072                 }
4073
4074                 if (!arg_quiet) {
4075                         for (i = 0; i < n_changes; i++) {
4076                                 if (changes[i].type == UNIT_FILE_SYMLINK)
4077                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4078                                 else
4079                                         log_info("rm '%s'", changes[i].path);
4080                         }
4081                 }
4082
4083         } else {
4084                 const char *method;
4085                 bool send_force = true, expect_carries_install_info = false;
4086                 dbus_bool_t a, b;
4087                 DBusMessageIter iter, sub, sub2;
4088
4089                 if (streq(verb, "enable")) {
4090                         method = "EnableUnitFiles";
4091                         expect_carries_install_info = true;
4092                 } else if (streq(verb, "disable")) {
4093                         method = "DisableUnitFiles";
4094                         send_force = false;
4095                 } else if (streq(verb, "reenable")) {
4096                         method = "ReenableUnitFiles";
4097                         expect_carries_install_info = true;
4098                 } else if (streq(verb, "link"))
4099                         method = "LinkUnitFiles";
4100                 else if (streq(verb, "preset")) {
4101                         method = "PresetUnitFiles";
4102                         expect_carries_install_info = true;
4103                 } else if (streq(verb, "mask"))
4104                         method = "MaskUnitFiles";
4105                 else if (streq(verb, "unmask")) {
4106                         method = "UnmaskUnitFiles";
4107                         send_force = false;
4108                 } else
4109                         assert_not_reached("Unknown verb");
4110
4111                 m = dbus_message_new_method_call(
4112                                 "org.freedesktop.systemd1",
4113                                 "/org/freedesktop/systemd1",
4114                                 "org.freedesktop.systemd1.Manager",
4115                                 method);
4116                 if (!m) {
4117                         log_error("Out of memory");
4118                         r = -ENOMEM;
4119                         goto finish;
4120                 }
4121
4122                 dbus_message_iter_init_append(m, &iter);
4123
4124                 r = bus_append_strv_iter(&iter, args+1);
4125                 if (r < 0) {
4126                         log_error("Failed to append unit files.");
4127                         goto finish;
4128                 }
4129
4130                 a = arg_runtime;
4131                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4132                         log_error("Failed to append runtime boolean.");
4133                         r = -ENOMEM;
4134                         goto finish;
4135                 }
4136
4137                 if (send_force) {
4138                         b = arg_force;
4139
4140                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4141                                 log_error("Failed to append force boolean.");
4142                                 r = -ENOMEM;
4143                                 goto finish;
4144                         }
4145                 }
4146
4147                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4148                 if (!reply) {
4149                         log_error("Failed to issue method call: %s", bus_error_message(&error));
4150                         r = -EIO;
4151                         goto finish;
4152                 }
4153
4154                 if (!dbus_message_iter_init(reply, &iter)) {
4155                         log_error("Failed to initialize iterator.");
4156                         goto finish;
4157                 }
4158
4159                 if (expect_carries_install_info) {
4160                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4161                         if (r < 0) {
4162                                 log_error("Failed to parse reply.");
4163                                 goto finish;
4164                         }
4165
4166                         carries_install_info = b;
4167                 }
4168
4169                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4170                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4171                         log_error("Failed to parse reply.");
4172                         r = -EIO;
4173                         goto finish;
4174                 }
4175
4176                 dbus_message_iter_recurse(&iter, &sub);
4177                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4178                         const char *type, *path, *source;
4179
4180                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4181                                 log_error("Failed to parse reply.");
4182                                 r = -EIO;
4183                                 goto finish;
4184                         }
4185
4186                         dbus_message_iter_recurse(&sub, &sub2);
4187
4188                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4189                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4190                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4191                                 log_error("Failed to parse reply.");
4192                                 r = -EIO;
4193                                 goto finish;
4194                         }
4195
4196                         if (!arg_quiet) {
4197                                 if (streq(type, "symlink"))
4198                                         log_info("ln -s '%s' '%s'", source, path);
4199                                 else
4200                                         log_info("rm '%s'", path);
4201                         }
4202
4203                         dbus_message_iter_next(&sub);
4204                 }
4205
4206                 /* Try to reload if enabeld */
4207                 if (!arg_no_reload)
4208                         r = daemon_reload(bus, args);
4209         }
4210
4211         if (carries_install_info == 0)
4212                 log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
4213
4214 finish:
4215         if (m)
4216                 dbus_message_unref(m);
4217
4218         if (reply)
4219                 dbus_message_unref(reply);
4220
4221         unit_file_changes_free(changes, n_changes);
4222
4223         dbus_error_free(&error);
4224         return r;
4225 }
4226
4227 static int unit_is_enabled(DBusConnection *bus, char **args) {
4228         DBusError error;
4229         int r;
4230         DBusMessage *m = NULL, *reply = NULL;
4231         bool enabled;
4232         char **name;
4233
4234         dbus_error_init(&error);
4235
4236         r = enable_sysv_units(args);
4237         if (r < 0)
4238                 return r;
4239
4240         enabled = r > 0;
4241
4242         if (!bus || avoid_bus()) {
4243
4244                 STRV_FOREACH(name, args+1) {
4245                         UnitFileState state;
4246
4247                         state = unit_file_get_state(arg_scope, arg_root, *name);
4248                         if (state < 0) {
4249                                 r = state;
4250                                 goto finish;
4251                         }
4252
4253                         if (state == UNIT_FILE_ENABLED ||
4254                             state == UNIT_FILE_ENABLED_RUNTIME ||
4255                             state == UNIT_FILE_STATIC)
4256                                 enabled = true;
4257
4258                         if (!arg_quiet)
4259                                 puts(unit_file_state_to_string(state));
4260                 }
4261
4262         } else {
4263                 STRV_FOREACH(name, args+1) {
4264                         const char *s;
4265
4266                         m = dbus_message_new_method_call(
4267                                         "org.freedesktop.systemd1",
4268                                         "/org/freedesktop/systemd1",
4269                                         "org.freedesktop.systemd1.Manager",
4270                                         "GetUnitFileState");
4271                         if (!m) {
4272                                 log_error("Out of memory");
4273                                 r = -ENOMEM;
4274                                 goto finish;
4275                         }
4276
4277                         if (!dbus_message_append_args(m,
4278                                                       DBUS_TYPE_STRING, name,
4279                                                       DBUS_TYPE_INVALID)) {
4280                                 log_error("Could not append arguments to message.");
4281                                 r = -ENOMEM;
4282                                 goto finish;
4283                         }
4284
4285                         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4286                         if (!reply) {
4287                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4288                                 r = -EIO;
4289                                 goto finish;
4290                         }
4291
4292                         if (!dbus_message_get_args(reply, &error,
4293                                                    DBUS_TYPE_STRING, &s,
4294                                                    DBUS_TYPE_INVALID)) {
4295                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4296                                 r = -EIO;
4297                                 goto finish;
4298                         }
4299
4300                         dbus_message_unref(m);
4301                         dbus_message_unref(reply);
4302                         m = reply = NULL;
4303
4304                         if (streq(s, "enabled") ||
4305                             streq(s, "enabled-runtime") ||
4306                             streq(s, "static"))
4307                                 enabled = true;
4308
4309                         if (!arg_quiet)
4310                                 puts(s);
4311                 }
4312         }
4313
4314         r = enabled ? 0 : 1;
4315
4316 finish:
4317         if (m)
4318                 dbus_message_unref(m);
4319
4320         if (reply)
4321                 dbus_message_unref(reply);
4322
4323         dbus_error_free(&error);
4324         return r;
4325 }
4326
4327 static int systemctl_help(void) {
4328
4329         pager_open_if_enabled();
4330
4331         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4332                "Query or send control commands to the systemd manager.\n\n"
4333                "  -h --help           Show this help\n"
4334                "     --version        Show package version\n"
4335                "  -t --type=TYPE      List only units of a particular type\n"
4336                "  -p --property=NAME  Show only properties by this name\n"
4337                "  -a --all            Show all units/properties, including dead/empty ones\n"
4338                "     --failed         Show only failed units\n"
4339                "     --full           Don't ellipsize unit names on output\n"
4340                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4341                "                      pending\n"
4342                "     --ignore-dependencies\n"
4343                "                      When queueing a new job, ignore all its dependencies\n"
4344                "     --kill-who=WHO   Who to send signal to\n"
4345                "  -s --signal=SIGNAL  Which signal to send\n"
4346                "  -H --host=[USER@]HOST\n"
4347                "                      Show information for remote host\n"
4348                "  -P --privileged     Acquire privileges before execution\n"
4349                "  -q --quiet          Suppress output\n"
4350                "     --no-block       Do not wait until operation finished\n"
4351                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4352                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4353                "                      configuration\n"
4354                "     --no-legend      Do not print a legend (column headers and hints)\n"
4355                "     --no-pager       Do not pipe output into a pager\n"
4356                "     --no-ask-password\n"
4357                "                      Do not ask for system passwords\n"
4358                "     --order          When generating graph for dot, show only order\n"
4359                "     --require        When generating graph for dot, show only requirement\n"
4360                "     --system         Connect to system manager\n"
4361                "     --user           Connect to user service manager\n"
4362                "     --global         Enable/disable unit files globally\n"
4363                "  -f --force          When enabling unit files, override existing symlinks\n"
4364                "                      When shutting down, execute action immediately\n"
4365                "     --root=PATH      Enable unit files in the specified root directory\n"
4366                "     --runtime        Enable unit files only temporarily until next reboot\n"
4367                "  -n --lines=INTEGER  Journal entries to show\n"
4368                "     --follow         Follow journal\n"
4369                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4370                "                      verbose, export, json, cat)\n\n"
4371                "Unit Commands:\n"
4372                "  list-units                      List loaded units\n"
4373                "  start [NAME...]                 Start (activate) one or more units\n"
4374                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4375                "  reload [NAME...]                Reload one or more units\n"
4376                "  restart [NAME...]               Start or restart one or more units\n"
4377                "  try-restart [NAME...]           Restart one or more units if active\n"
4378                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
4379                "                                  otherwise start or restart\n"
4380                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4381                "                                  otherwise restart if active\n"
4382                "  isolate [NAME]                  Start one unit and stop all others\n"
4383                "  kill [NAME...]                  Send signal to processes of a unit\n"
4384                "  is-active [NAME...]             Check whether units are active\n"
4385                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4386                "  show [NAME...|JOB...]           Show properties of one or more\n"
4387                "                                  units/jobs or the manager\n"
4388                "  help [NAME...|PID...]            Show manual for one or more units\n"
4389                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4390                "                                  units\n"
4391                "  load [NAME...]                  Load one or more units\n\n"
4392                "Unit File Commands:\n"
4393                "  list-unit-files                 List installed unit files\n"
4394                "  enable [NAME...]                Enable one or more unit files\n"
4395                "  disable [NAME...]               Disable one or more unit files\n"
4396                "  reenable [NAME...]              Reenable one or more unit files\n"
4397                "  preset [NAME...]                Enable/disable one or more unit files\n"
4398                "                                  based on preset configuration\n"
4399                "  mask [NAME...]                  Mask one or more units\n"
4400                "  unmask [NAME...]                Unmask one or more units\n"
4401                "  link [PATH...]                  Link one or more units files into\n"
4402                "                                  the search path\n"
4403                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4404                "Job Commands:\n"
4405                "  list-jobs                       List jobs\n"
4406                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4407                "Status Commands:\n"
4408                "  dump                            Dump server status\n"
4409                "  dot                             Dump dependency graph for dot(1)\n\n"
4410                "Snapshot Commands:\n"
4411                "  snapshot [NAME]                 Create a snapshot\n"
4412                "  delete [NAME...]                Remove one or more snapshots\n\n"
4413                "Environment Commands:\n"
4414                "  show-environment                Dump environment\n"
4415                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4416                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4417                "Manager Lifecycle Commands:\n"
4418                "  daemon-reload                   Reload systemd manager configuration\n"
4419                "  daemon-reexec                   Reexecute systemd manager\n\n"
4420                "System Commands:\n"
4421                "  default                         Enter system default mode\n"
4422                "  rescue                          Enter system rescue mode\n"
4423                "  emergency                       Enter system emergency mode\n"
4424                "  halt                            Shut down and halt the system\n"
4425                "  poweroff                        Shut down and power-off the system\n"
4426                "  reboot                          Shut down and reboot the system\n"
4427                "  kexec                           Shut down and reboot the system with kexec\n"
4428                "  exit                            Request user instance exit\n"
4429                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4430                "  suspend                         Suspend the system\n"
4431                "  hibernate                       Hibernate the system\n",
4432                program_invocation_short_name);
4433
4434         return 0;
4435 }
4436
4437 static int halt_help(void) {
4438
4439         printf("%s [OPTIONS...]\n\n"
4440                "%s the system.\n\n"
4441                "     --help      Show this help\n"
4442                "     --halt      Halt the machine\n"
4443                "  -p --poweroff  Switch off the machine\n"
4444                "     --reboot    Reboot the machine\n"
4445                "  -f --force     Force immediate halt/power-off/reboot\n"
4446                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4447                "  -d --no-wtmp   Don't write wtmp record\n"
4448                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
4449                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4450                program_invocation_short_name,
4451                arg_action == ACTION_REBOOT   ? "Reboot" :
4452                arg_action == ACTION_POWEROFF ? "Power off" :
4453                                                "Halt");
4454
4455         return 0;
4456 }
4457
4458 static int shutdown_help(void) {
4459
4460         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4461                "Shut down the system.\n\n"
4462                "     --help      Show this help\n"
4463                "  -H --halt      Halt the machine\n"
4464                "  -P --poweroff  Power-off the machine\n"
4465                "  -r --reboot    Reboot the machine\n"
4466                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4467                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4468                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4469                "  -c             Cancel a pending shutdown\n",
4470                program_invocation_short_name);
4471
4472         return 0;
4473 }
4474
4475 static int telinit_help(void) {
4476
4477         printf("%s [OPTIONS...] {COMMAND}\n\n"
4478                "Send control commands to the init daemon.\n\n"
4479                "     --help      Show this help\n"
4480                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4481                "Commands:\n"
4482                "  0              Power-off the machine\n"
4483                "  6              Reboot the machine\n"
4484                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4485                "  1, s, S        Enter rescue mode\n"
4486                "  q, Q           Reload init daemon configuration\n"
4487                "  u, U           Reexecute init daemon\n",
4488                program_invocation_short_name);
4489
4490         return 0;
4491 }
4492
4493 static int runlevel_help(void) {
4494
4495         printf("%s [OPTIONS...]\n\n"
4496                "Prints the previous and current runlevel of the init system.\n\n"
4497                "     --help      Show this help\n",
4498                program_invocation_short_name);
4499
4500         return 0;
4501 }
4502
4503 static int systemctl_parse_argv(int argc, char *argv[]) {
4504
4505         enum {
4506                 ARG_FAIL = 0x100,
4507                 ARG_IGNORE_DEPENDENCIES,
4508                 ARG_VERSION,
4509                 ARG_USER,
4510                 ARG_SYSTEM,
4511                 ARG_GLOBAL,
4512                 ARG_NO_BLOCK,
4513                 ARG_NO_LEGEND,
4514                 ARG_NO_PAGER,
4515                 ARG_NO_WALL,
4516                 ARG_ORDER,
4517                 ARG_REQUIRE,
4518                 ARG_ROOT,
4519                 ARG_FULL,
4520                 ARG_NO_RELOAD,
4521                 ARG_KILL_MODE,
4522                 ARG_KILL_WHO,
4523                 ARG_NO_ASK_PASSWORD,
4524                 ARG_FAILED,
4525                 ARG_RUNTIME,
4526                 ARG_FOLLOW,
4527                 ARG_FORCE
4528         };
4529
4530         static const struct option options[] = {
4531                 { "help",      no_argument,       NULL, 'h'           },
4532                 { "version",   no_argument,       NULL, ARG_VERSION   },
4533                 { "type",      required_argument, NULL, 't'           },
4534                 { "property",  required_argument, NULL, 'p'           },
4535                 { "all",       no_argument,       NULL, 'a'           },
4536                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4537                 { "full",      no_argument,       NULL, ARG_FULL      },
4538                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4539                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4540                 { "user",      no_argument,       NULL, ARG_USER      },
4541                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4542                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4543                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4544                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4545                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4546                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4547                 { "quiet",     no_argument,       NULL, 'q'           },
4548                 { "order",     no_argument,       NULL, ARG_ORDER     },
4549                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4550                 { "root",      required_argument, NULL, ARG_ROOT      },
4551                 { "force",     no_argument,       NULL, ARG_FORCE     },
4552                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4553                 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
4554                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4555                 { "signal",    required_argument, NULL, 's'           },
4556                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4557                 { "host",      required_argument, NULL, 'H'           },
4558                 { "privileged",no_argument,       NULL, 'P'           },
4559                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4560                 { "lines",     required_argument, NULL, 'n'           },
4561                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4562                 { "output",    required_argument, NULL, 'o'           },
4563                 { NULL,        0,                 NULL, 0             }
4564         };
4565
4566         int c;
4567
4568         assert(argc >= 0);
4569         assert(argv);
4570
4571         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4572
4573                 switch (c) {
4574
4575                 case 'h':
4576                         systemctl_help();
4577                         return 0;
4578
4579                 case ARG_VERSION:
4580                         puts(PACKAGE_STRING);
4581                         puts(DISTRIBUTION);
4582                         puts(SYSTEMD_FEATURES);
4583                         return 0;
4584
4585                 case 't':
4586                         arg_type = optarg;
4587                         break;
4588
4589                 case 'p': {
4590                         char **l;
4591
4592                         if (!(l = strv_append(arg_property, optarg)))
4593                                 return -ENOMEM;
4594
4595                         strv_free(arg_property);
4596                         arg_property = l;
4597
4598                         /* If the user asked for a particular
4599                          * property, show it to him, even if it is
4600                          * empty. */
4601                         arg_all = true;
4602                         break;
4603                 }
4604
4605                 case 'a':
4606                         arg_all = true;
4607                         break;
4608
4609                 case ARG_FAIL:
4610                         arg_job_mode = "fail";
4611                         break;
4612
4613                 case ARG_IGNORE_DEPENDENCIES:
4614                         arg_job_mode = "ignore-dependencies";
4615                         break;
4616
4617                 case ARG_USER:
4618                         arg_scope = UNIT_FILE_USER;
4619                         break;
4620
4621                 case ARG_SYSTEM:
4622                         arg_scope = UNIT_FILE_SYSTEM;
4623                         break;
4624
4625                 case ARG_GLOBAL:
4626                         arg_scope = UNIT_FILE_GLOBAL;
4627                         break;
4628
4629                 case ARG_NO_BLOCK:
4630                         arg_no_block = true;
4631                         break;
4632
4633                 case ARG_NO_LEGEND:
4634                         arg_no_legend = true;
4635                         break;
4636
4637                 case ARG_NO_PAGER:
4638                         arg_no_pager = true;
4639                         break;
4640
4641                 case ARG_NO_WALL:
4642                         arg_no_wall = true;
4643                         break;
4644
4645                 case ARG_ORDER:
4646                         arg_dot = DOT_ORDER;
4647                         break;
4648
4649                 case ARG_REQUIRE:
4650                         arg_dot = DOT_REQUIRE;
4651                         break;
4652
4653                 case ARG_ROOT:
4654                         arg_root = optarg;
4655                         break;
4656
4657                 case ARG_FULL:
4658                         arg_full = true;
4659                         break;
4660
4661                 case ARG_FAILED:
4662                         arg_failed = true;
4663                         break;
4664
4665                 case 'q':
4666                         arg_quiet = true;
4667                         break;
4668
4669                 case ARG_FORCE:
4670                         arg_force ++;
4671                         break;
4672
4673                 case ARG_FOLLOW:
4674                         arg_follow = true;
4675                         break;
4676
4677                 case 'f':
4678                         /* -f is short for both --follow and --force! */
4679                         arg_force ++;
4680                         arg_follow = true;
4681                         break;
4682
4683                 case ARG_NO_RELOAD:
4684                         arg_no_reload = true;
4685                         break;
4686
4687                 case ARG_KILL_WHO:
4688                         arg_kill_who = optarg;
4689                         break;
4690
4691                 case ARG_KILL_MODE:
4692                         arg_kill_mode = optarg;
4693                         break;
4694
4695                 case 's':
4696                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4697                                 log_error("Failed to parse signal string %s.", optarg);
4698                                 return -EINVAL;
4699                         }
4700                         break;
4701
4702                 case ARG_NO_ASK_PASSWORD:
4703                         arg_ask_password = false;
4704                         break;
4705
4706                 case 'P':
4707                         arg_transport = TRANSPORT_POLKIT;
4708                         break;
4709
4710                 case 'H':
4711                         arg_transport = TRANSPORT_SSH;
4712                         arg_host = optarg;
4713                         break;
4714
4715                 case ARG_RUNTIME:
4716                         arg_runtime = true;
4717                         break;
4718
4719                 case 'n':
4720                         if (safe_atou(optarg, &arg_lines) < 0) {
4721                                 log_error("Failed to parse lines '%s'", optarg);
4722                                 return -EINVAL;
4723                         }
4724                         break;
4725
4726                 case 'o':
4727                         arg_output = output_mode_from_string(optarg);
4728                         if (arg_output < 0) {
4729                                 log_error("Unknown output '%s'.", optarg);
4730                                 return -EINVAL;
4731                         }
4732                         break;
4733
4734                 case '?':
4735                         return -EINVAL;
4736
4737                 default:
4738                         log_error("Unknown option code %c", c);
4739                         return -EINVAL;
4740                 }
4741         }
4742
4743         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4744                 log_error("Cannot access user instance remotely.");
4745                 return -EINVAL;
4746         }
4747
4748         return 1;
4749 }
4750
4751 static int halt_parse_argv(int argc, char *argv[]) {
4752
4753         enum {
4754                 ARG_HELP = 0x100,
4755                 ARG_HALT,
4756                 ARG_REBOOT,
4757                 ARG_NO_WALL
4758         };
4759
4760         static const struct option options[] = {
4761                 { "help",      no_argument,       NULL, ARG_HELP    },
4762                 { "halt",      no_argument,       NULL, ARG_HALT    },
4763                 { "poweroff",  no_argument,       NULL, 'p'         },
4764                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4765                 { "force",     no_argument,       NULL, 'f'         },
4766                 { "wtmp-only", no_argument,       NULL, 'w'         },
4767                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4768                 { "no-sync",   no_argument,       NULL, 'n'         },
4769                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4770                 { NULL,        0,                 NULL, 0           }
4771         };
4772
4773         int c, runlevel;
4774
4775         assert(argc >= 0);
4776         assert(argv);
4777
4778         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4779                 if (runlevel == '0' || runlevel == '6')
4780                         arg_force = 2;
4781
4782         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4783                 switch (c) {
4784
4785                 case ARG_HELP:
4786                         halt_help();
4787                         return 0;
4788
4789                 case ARG_HALT:
4790                         arg_action = ACTION_HALT;
4791                         break;
4792
4793                 case 'p':
4794                         if (arg_action != ACTION_REBOOT)
4795                                 arg_action = ACTION_POWEROFF;
4796                         break;
4797
4798                 case ARG_REBOOT:
4799                         arg_action = ACTION_REBOOT;
4800                         break;
4801
4802                 case 'f':
4803                         arg_force = 2;
4804                         break;
4805
4806                 case 'w':
4807                         arg_dry = true;
4808                         break;
4809
4810                 case 'd':
4811                         arg_no_wtmp = true;
4812                         break;
4813
4814                 case 'n':
4815                         arg_no_sync = true;
4816                         break;
4817
4818                 case ARG_NO_WALL:
4819                         arg_no_wall = true;
4820                         break;
4821
4822                 case 'i':
4823                 case 'h':
4824                         /* Compatibility nops */
4825                         break;
4826
4827                 case '?':
4828                         return -EINVAL;
4829
4830                 default:
4831                         log_error("Unknown option code %c", c);
4832                         return -EINVAL;
4833                 }
4834         }
4835
4836         if (optind < argc) {
4837                 log_error("Too many arguments.");
4838                 return -EINVAL;
4839         }
4840
4841         return 1;
4842 }
4843
4844 static int parse_time_spec(const char *t, usec_t *_u) {
4845         assert(t);
4846         assert(_u);
4847
4848         if (streq(t, "now"))
4849                 *_u = 0;
4850         else if (!strchr(t, ':')) {
4851                 uint64_t u;
4852
4853                 if (safe_atou64(t, &u) < 0)
4854                         return -EINVAL;
4855
4856                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4857         } else {
4858                 char *e = NULL;
4859                 long hour, minute;
4860                 struct tm tm;
4861                 time_t s;
4862                 usec_t n;
4863
4864                 errno = 0;
4865                 hour = strtol(t, &e, 10);
4866                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4867                         return -EINVAL;
4868
4869                 minute = strtol(e+1, &e, 10);
4870                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4871                         return -EINVAL;
4872
4873                 n = now(CLOCK_REALTIME);
4874                 s = (time_t) (n / USEC_PER_SEC);
4875
4876                 zero(tm);
4877                 assert_se(localtime_r(&s, &tm));
4878
4879                 tm.tm_hour = (int) hour;
4880                 tm.tm_min = (int) minute;
4881                 tm.tm_sec = 0;
4882
4883                 assert_se(s = mktime(&tm));
4884
4885                 *_u = (usec_t) s * USEC_PER_SEC;
4886
4887                 while (*_u <= n)
4888                         *_u += USEC_PER_DAY;
4889         }
4890
4891         return 0;
4892 }
4893
4894 static int shutdown_parse_argv(int argc, char *argv[]) {
4895
4896         enum {
4897                 ARG_HELP = 0x100,
4898                 ARG_NO_WALL
4899         };
4900
4901         static const struct option options[] = {
4902                 { "help",      no_argument,       NULL, ARG_HELP    },
4903                 { "halt",      no_argument,       NULL, 'H'         },
4904                 { "poweroff",  no_argument,       NULL, 'P'         },
4905                 { "reboot",    no_argument,       NULL, 'r'         },
4906                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4907                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4908                 { NULL,        0,                 NULL, 0           }
4909         };
4910
4911         int c, r;
4912
4913         assert(argc >= 0);
4914         assert(argv);
4915
4916         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4917                 switch (c) {
4918
4919                 case ARG_HELP:
4920                         shutdown_help();
4921                         return 0;
4922
4923                 case 'H':
4924                         arg_action = ACTION_HALT;
4925                         break;
4926
4927                 case 'P':
4928                         arg_action = ACTION_POWEROFF;
4929                         break;
4930
4931                 case 'r':
4932                         if (kexec_loaded())
4933                                 arg_action = ACTION_KEXEC;
4934                         else
4935                                 arg_action = ACTION_REBOOT;
4936                         break;
4937
4938                 case 'K':
4939                         arg_action = ACTION_KEXEC;
4940                         break;
4941
4942                 case 'h':
4943                         if (arg_action != ACTION_HALT)
4944                                 arg_action = ACTION_POWEROFF;
4945                         break;
4946
4947                 case 'k':
4948                         arg_dry = true;
4949                         break;
4950
4951                 case ARG_NO_WALL:
4952                         arg_no_wall = true;
4953                         break;
4954
4955                 case 't':
4956                 case 'a':
4957                         /* Compatibility nops */
4958                         break;
4959
4960                 case 'c':
4961                         arg_action = ACTION_CANCEL_SHUTDOWN;
4962                         break;
4963
4964                 case '?':
4965                         return -EINVAL;
4966
4967                 default:
4968                         log_error("Unknown option code %c", c);
4969                         return -EINVAL;
4970                 }
4971         }
4972
4973         if (argc > optind) {
4974                 r = parse_time_spec(argv[optind], &arg_when);
4975                 if (r < 0) {
4976                         log_error("Failed to parse time specification: %s", argv[optind]);
4977                         return r;
4978                 }
4979         } else
4980                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4981
4982         /* We skip the time argument */
4983         if (argc > optind + 1)
4984                 arg_wall = argv + optind + 1;
4985
4986         optind = argc;
4987
4988         return 1;
4989 }
4990
4991 static int telinit_parse_argv(int argc, char *argv[]) {
4992
4993         enum {
4994                 ARG_HELP = 0x100,
4995                 ARG_NO_WALL
4996         };
4997
4998         static const struct option options[] = {
4999                 { "help",      no_argument,       NULL, ARG_HELP    },
5000                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
5001                 { NULL,        0,                 NULL, 0           }
5002         };
5003
5004         static const struct {
5005                 char from;
5006                 enum action to;
5007         } table[] = {
5008                 { '0', ACTION_POWEROFF },
5009                 { '6', ACTION_REBOOT },
5010                 { '1', ACTION_RESCUE },
5011                 { '2', ACTION_RUNLEVEL2 },
5012                 { '3', ACTION_RUNLEVEL3 },
5013                 { '4', ACTION_RUNLEVEL4 },
5014                 { '5', ACTION_RUNLEVEL5 },
5015                 { 's', ACTION_RESCUE },
5016                 { 'S', ACTION_RESCUE },
5017                 { 'q', ACTION_RELOAD },
5018                 { 'Q', ACTION_RELOAD },
5019                 { 'u', ACTION_REEXEC },
5020                 { 'U', ACTION_REEXEC }
5021         };
5022
5023         unsigned i;
5024         int c;
5025
5026         assert(argc >= 0);
5027         assert(argv);
5028
5029         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5030                 switch (c) {
5031
5032                 case ARG_HELP:
5033                         telinit_help();
5034                         return 0;
5035
5036                 case ARG_NO_WALL:
5037                         arg_no_wall = true;
5038                         break;
5039
5040                 case '?':
5041                         return -EINVAL;
5042
5043                 default:
5044                         log_error("Unknown option code %c", c);
5045                         return -EINVAL;
5046                 }
5047         }
5048
5049         if (optind >= argc) {
5050                 telinit_help();
5051                 return -EINVAL;
5052         }
5053
5054         if (optind + 1 < argc) {
5055                 log_error("Too many arguments.");
5056                 return -EINVAL;
5057         }
5058
5059         if (strlen(argv[optind]) != 1) {
5060                 log_error("Expected single character argument.");
5061                 return -EINVAL;
5062         }
5063
5064         for (i = 0; i < ELEMENTSOF(table); i++)
5065                 if (table[i].from == argv[optind][0])
5066                         break;
5067
5068         if (i >= ELEMENTSOF(table)) {
5069                 log_error("Unknown command %s.", argv[optind]);
5070                 return -EINVAL;
5071         }
5072
5073         arg_action = table[i].to;
5074
5075         optind ++;
5076
5077         return 1;
5078 }
5079
5080 static int runlevel_parse_argv(int argc, char *argv[]) {
5081
5082         enum {
5083                 ARG_HELP = 0x100,
5084         };
5085
5086         static const struct option options[] = {
5087                 { "help",      no_argument,       NULL, ARG_HELP    },
5088                 { NULL,        0,                 NULL, 0           }
5089         };
5090
5091         int c;
5092
5093         assert(argc >= 0);
5094         assert(argv);
5095
5096         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5097                 switch (c) {
5098
5099                 case ARG_HELP:
5100                         runlevel_help();
5101                         return 0;
5102
5103                 case '?':
5104                         return -EINVAL;
5105
5106                 default:
5107                         log_error("Unknown option code %c", c);
5108                         return -EINVAL;
5109                 }
5110         }
5111
5112         if (optind < argc) {
5113                 log_error("Too many arguments.");
5114                 return -EINVAL;
5115         }
5116
5117         return 1;
5118 }
5119
5120 static int parse_argv(int argc, char *argv[]) {
5121         assert(argc >= 0);
5122         assert(argv);
5123
5124         if (program_invocation_short_name) {
5125
5126                 if (strstr(program_invocation_short_name, "halt")) {
5127                         arg_action = ACTION_HALT;
5128                         return halt_parse_argv(argc, argv);
5129                 } else if (strstr(program_invocation_short_name, "poweroff")) {
5130                         arg_action = ACTION_POWEROFF;
5131                         return halt_parse_argv(argc, argv);
5132                 } else if (strstr(program_invocation_short_name, "reboot")) {
5133                         if (kexec_loaded())
5134                                 arg_action = ACTION_KEXEC;
5135                         else
5136                                 arg_action = ACTION_REBOOT;
5137                         return halt_parse_argv(argc, argv);
5138                 } else if (strstr(program_invocation_short_name, "shutdown")) {
5139                         arg_action = ACTION_POWEROFF;
5140                         return shutdown_parse_argv(argc, argv);
5141                 } else if (strstr(program_invocation_short_name, "init")) {
5142
5143                         if (sd_booted() > 0) {
5144                                 arg_action = ACTION_INVALID;
5145                                 return telinit_parse_argv(argc, argv);
5146                         } else {
5147                                 /* Hmm, so some other init system is
5148                                  * running, we need to forward this
5149                                  * request to it. For now we simply
5150                                  * guess that it is Upstart. */
5151
5152                                 execv("/lib/upstart/telinit", argv);
5153
5154                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
5155                                 return -EIO;
5156                         }
5157
5158                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5159                         arg_action = ACTION_RUNLEVEL;
5160                         return runlevel_parse_argv(argc, argv);
5161                 }
5162         }
5163
5164         arg_action = ACTION_SYSTEMCTL;
5165         return systemctl_parse_argv(argc, argv);
5166 }
5167
5168 static int action_to_runlevel(void) {
5169
5170         static const char table[_ACTION_MAX] = {
5171                 [ACTION_HALT] =      '0',
5172                 [ACTION_POWEROFF] =  '0',
5173                 [ACTION_REBOOT] =    '6',
5174                 [ACTION_RUNLEVEL2] = '2',
5175                 [ACTION_RUNLEVEL3] = '3',
5176                 [ACTION_RUNLEVEL4] = '4',
5177                 [ACTION_RUNLEVEL5] = '5',
5178                 [ACTION_RESCUE] =    '1'
5179         };
5180
5181         assert(arg_action < _ACTION_MAX);
5182
5183         return table[arg_action];
5184 }
5185
5186 static int talk_upstart(void) {
5187         DBusMessage *m = NULL, *reply = NULL;
5188         DBusError error;
5189         int previous, rl, r;
5190         char
5191                 env1_buf[] = "RUNLEVEL=X",
5192                 env2_buf[] = "PREVLEVEL=X";
5193         char *env1 = env1_buf, *env2 = env2_buf;
5194         const char *emit = "runlevel";
5195         dbus_bool_t b_false = FALSE;
5196         DBusMessageIter iter, sub;
5197         DBusConnection *bus;
5198
5199         dbus_error_init(&error);
5200
5201         if (!(rl = action_to_runlevel()))
5202                 return 0;
5203
5204         if (utmp_get_runlevel(&previous, NULL) < 0)
5205                 previous = 'N';
5206
5207         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5208                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5209                         r = 0;
5210                         goto finish;
5211                 }
5212
5213                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5214                 r = -EIO;
5215                 goto finish;
5216         }
5217
5218         if ((r = bus_check_peercred(bus)) < 0) {
5219                 log_error("Failed to verify owner of bus.");
5220                 goto finish;
5221         }
5222
5223         if (!(m = dbus_message_new_method_call(
5224                               "com.ubuntu.Upstart",
5225                               "/com/ubuntu/Upstart",
5226                               "com.ubuntu.Upstart0_6",
5227                               "EmitEvent"))) {
5228
5229                 log_error("Could not allocate message.");
5230                 r = -ENOMEM;
5231                 goto finish;
5232         }
5233
5234         dbus_message_iter_init_append(m, &iter);
5235
5236         env1_buf[sizeof(env1_buf)-2] = rl;
5237         env2_buf[sizeof(env2_buf)-2] = previous;
5238
5239         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5240             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5241             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5242             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5243             !dbus_message_iter_close_container(&iter, &sub) ||
5244             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5245                 log_error("Could not append arguments to message.");
5246                 r = -ENOMEM;
5247                 goto finish;
5248         }
5249
5250         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5251
5252                 if (error_is_no_service(&error)) {
5253                         r = -EADDRNOTAVAIL;
5254                         goto finish;
5255                 }
5256
5257                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5258                 r = -EIO;
5259                 goto finish;
5260         }
5261
5262         r = 1;
5263
5264 finish:
5265         if (m)
5266                 dbus_message_unref(m);
5267
5268         if (reply)
5269                 dbus_message_unref(reply);
5270
5271         if (bus) {
5272                 dbus_connection_flush(bus);
5273                 dbus_connection_close(bus);
5274                 dbus_connection_unref(bus);
5275         }
5276
5277         dbus_error_free(&error);
5278
5279         return r;
5280 }
5281
5282 static int talk_initctl(void) {
5283         struct init_request request;
5284         int r, fd;
5285         char rl;
5286
5287         if (!(rl = action_to_runlevel()))
5288                 return 0;
5289
5290         zero(request);
5291         request.magic = INIT_MAGIC;
5292         request.sleeptime = 0;
5293         request.cmd = INIT_CMD_RUNLVL;
5294         request.runlevel = rl;
5295
5296         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5297
5298                 if (errno == ENOENT)
5299                         return 0;
5300
5301                 log_error("Failed to open "INIT_FIFO": %m");
5302                 return -errno;
5303         }
5304
5305         errno = 0;
5306         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5307         close_nointr_nofail(fd);
5308
5309         if (r < 0) {
5310                 log_error("Failed to write to "INIT_FIFO": %m");
5311                 return errno ? -errno : -EIO;
5312         }
5313
5314         return 1;
5315 }
5316
5317 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5318
5319         static const struct {
5320                 const char* verb;
5321                 const enum {
5322                         MORE,
5323                         LESS,
5324                         EQUAL
5325                 } argc_cmp;
5326                 const int argc;
5327                 int (* const dispatch)(DBusConnection *bus, char **args);
5328         } verbs[] = {
5329                 { "list-units",            LESS,  1, list_units        },
5330                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5331                 { "list-jobs",             EQUAL, 1, list_jobs         },
5332                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5333                 { "load",                  MORE,  2, load_unit         },
5334                 { "cancel",                MORE,  2, cancel_job        },
5335                 { "start",                 MORE,  2, start_unit        },
5336                 { "stop",                  MORE,  2, start_unit        },
5337                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5338                 { "reload",                MORE,  2, start_unit        },
5339                 { "restart",               MORE,  2, start_unit        },
5340                 { "try-restart",           MORE,  2, start_unit        },
5341                 { "reload-or-restart",     MORE,  2, start_unit        },
5342                 { "reload-or-try-restart", MORE,  2, start_unit        },
5343                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5344                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5345                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5346                 { "isolate",               EQUAL, 2, start_unit        },
5347                 { "kill",                  MORE,  2, kill_unit         },
5348                 { "is-active",             MORE,  2, check_unit        },
5349                 { "check",                 MORE,  2, check_unit        },
5350                 { "show",                  MORE,  1, show              },
5351                 { "status",                MORE,  2, show              },
5352                 { "help",                  MORE,  2, show              },
5353                 { "dump",                  EQUAL, 1, dump              },
5354                 { "dot",                   EQUAL, 1, dot               },
5355                 { "snapshot",              LESS,  2, snapshot          },
5356                 { "delete",                MORE,  2, delete_snapshot   },
5357                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5358                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5359                 { "show-environment",      EQUAL, 1, show_enviroment   },
5360                 { "set-environment",       MORE,  2, set_environment   },
5361                 { "unset-environment",     MORE,  2, set_environment   },
5362                 { "halt",                  EQUAL, 1, start_special     },
5363                 { "poweroff",              EQUAL, 1, start_special     },
5364                 { "reboot",                EQUAL, 1, start_special     },
5365                 { "kexec",                 EQUAL, 1, start_special     },
5366                 { "suspend",               EQUAL, 1, start_special     },
5367                 { "hibernate",             EQUAL, 1, start_special     },
5368                 { "default",               EQUAL, 1, start_special     },
5369                 { "rescue",                EQUAL, 1, start_special     },
5370                 { "emergency",             EQUAL, 1, start_special     },
5371                 { "exit",                  EQUAL, 1, start_special     },
5372                 { "reset-failed",          MORE,  1, reset_failed      },
5373                 { "enable",                MORE,  2, enable_unit       },
5374                 { "disable",               MORE,  2, enable_unit       },
5375                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5376                 { "reenable",              MORE,  2, enable_unit       },
5377                 { "preset",                MORE,  2, enable_unit       },
5378                 { "mask",                  MORE,  2, enable_unit       },
5379                 { "unmask",                MORE,  2, enable_unit       },
5380                 { "link",                  MORE,  2, enable_unit       },
5381                 { "switch-root",           MORE,  2, switch_root       },
5382         };
5383
5384         int left;
5385         unsigned i;
5386
5387         assert(argc >= 0);
5388         assert(argv);
5389         assert(error);
5390
5391         left = argc - optind;
5392
5393         if (left <= 0)
5394                 /* Special rule: no arguments means "list-units" */
5395                 i = 0;
5396         else {
5397                 if (streq(argv[optind], "help") && !argv[optind+1]) {
5398                         log_error("This command expects one or more "
5399                                   "unit names. Did you mean --help?");
5400                         return -EINVAL;
5401                 }
5402
5403                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5404                         if (streq(argv[optind], verbs[i].verb))
5405                                 break;
5406
5407                 if (i >= ELEMENTSOF(verbs)) {
5408                         log_error("Unknown operation %s", argv[optind]);
5409                         return -EINVAL;
5410                 }
5411         }
5412
5413         switch (verbs[i].argc_cmp) {
5414
5415         case EQUAL:
5416                 if (left != verbs[i].argc) {
5417                         log_error("Invalid number of arguments.");
5418                         return -EINVAL;
5419                 }
5420
5421                 break;
5422
5423         case MORE:
5424                 if (left < verbs[i].argc) {
5425                         log_error("Too few arguments.");
5426                         return -EINVAL;
5427                 }
5428
5429                 break;
5430
5431         case LESS:
5432                 if (left > verbs[i].argc) {
5433                         log_error("Too many arguments.");
5434                         return -EINVAL;
5435                 }
5436
5437                 break;
5438
5439         default:
5440                 assert_not_reached("Unknown comparison operator.");
5441         }
5442
5443         /* Require a bus connection for all operations but
5444          * enable/disable */
5445         if (!streq(verbs[i].verb, "enable") &&
5446             !streq(verbs[i].verb, "disable") &&
5447             !streq(verbs[i].verb, "is-enabled") &&
5448             !streq(verbs[i].verb, "list-unit-files") &&
5449             !streq(verbs[i].verb, "reenable") &&
5450             !streq(verbs[i].verb, "preset") &&
5451             !streq(verbs[i].verb, "mask") &&
5452             !streq(verbs[i].verb, "unmask") &&
5453             !streq(verbs[i].verb, "link")) {
5454
5455                 if (running_in_chroot() > 0) {
5456                         log_info("Running in chroot, ignoring request.");
5457                         return 0;
5458                 }
5459
5460                 if (((!streq(verbs[i].verb, "reboot") &&
5461                       !streq(verbs[i].verb, "halt") &&
5462                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5463                         log_error("Failed to get D-Bus connection: %s",
5464                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5465                         return -EIO;
5466                 }
5467
5468         } else {
5469
5470                 if (!bus && !avoid_bus()) {
5471                         log_error("Failed to get D-Bus connection: %s",
5472                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5473                         return -EIO;
5474                 }
5475         }
5476
5477         return verbs[i].dispatch(bus, argv + optind);
5478 }
5479
5480 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5481         int fd;
5482         struct msghdr msghdr;
5483         struct iovec iovec[2];
5484         union sockaddr_union sockaddr;
5485         struct sd_shutdown_command c;
5486
5487         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5488         if (fd < 0)
5489                 return -errno;
5490
5491         zero(c);
5492         c.usec = t;
5493         c.mode = mode;
5494         c.dry_run = dry_run;
5495         c.warn_wall = warn;
5496
5497         zero(sockaddr);
5498         sockaddr.sa.sa_family = AF_UNIX;
5499         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5500
5501         zero(msghdr);
5502         msghdr.msg_name = &sockaddr;
5503         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5504
5505         zero(iovec);
5506         iovec[0].iov_base = (char*) &c;
5507         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5508
5509         if (isempty(message))
5510                 msghdr.msg_iovlen = 1;
5511         else {
5512                 iovec[1].iov_base = (char*) message;
5513                 iovec[1].iov_len = strlen(message);
5514                 msghdr.msg_iovlen = 2;
5515         }
5516         msghdr.msg_iov = iovec;
5517
5518         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5519                 close_nointr_nofail(fd);
5520                 return -errno;
5521         }
5522
5523         close_nointr_nofail(fd);
5524         return 0;
5525 }
5526
5527 static int reload_with_fallback(DBusConnection *bus) {
5528
5529         if (bus) {
5530                 /* First, try systemd via D-Bus. */
5531                 if (daemon_reload(bus, NULL) >= 0)
5532                         return 0;
5533         }
5534
5535         /* Nothing else worked, so let's try signals */
5536         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5537
5538         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5539                 log_error("kill() failed: %m");
5540                 return -errno;
5541         }
5542
5543         return 0;
5544 }
5545
5546 static int start_with_fallback(DBusConnection *bus) {
5547
5548         if (bus) {
5549                 /* First, try systemd via D-Bus. */
5550                 if (start_unit(bus, NULL) >= 0)
5551                         goto done;
5552         }
5553
5554         /* Hmm, talking to systemd via D-Bus didn't work. Then
5555          * let's try to talk to Upstart via D-Bus. */
5556         if (talk_upstart() > 0)
5557                 goto done;
5558
5559         /* Nothing else worked, so let's try
5560          * /dev/initctl */
5561         if (talk_initctl() > 0)
5562                 goto done;
5563
5564         log_error("Failed to talk to init daemon.");
5565         return -EIO;
5566
5567 done:
5568         warn_wall(arg_action);
5569         return 0;
5570 }
5571
5572 static void halt_now(enum action a) {
5573
5574        /* Make sure C-A-D is handled by the kernel from this
5575          * point on... */
5576         reboot(RB_ENABLE_CAD);
5577
5578         switch (a) {
5579
5580         case ACTION_HALT:
5581                 log_info("Halting.");
5582                 reboot(RB_HALT_SYSTEM);
5583                 break;
5584
5585         case ACTION_POWEROFF:
5586                 log_info("Powering off.");
5587                 reboot(RB_POWER_OFF);
5588                 break;
5589
5590         case ACTION_REBOOT:
5591                 log_info("Rebooting.");
5592                 reboot(RB_AUTOBOOT);
5593                 break;
5594
5595         default:
5596                 assert_not_reached("Unknown halt action.");
5597         }
5598
5599         assert_not_reached("Uh? This shouldn't happen.");
5600 }
5601
5602 static int halt_main(DBusConnection *bus) {
5603         int r;
5604
5605         if (geteuid() != 0) {
5606                 /* Try logind if we are a normal user and no special
5607                  * mode applies. Maybe PolicyKit allows us to shutdown
5608                  * the machine. */
5609
5610                 if (arg_when <= 0 &&
5611                     !arg_dry &&
5612                     !arg_force &&
5613                     (arg_action == ACTION_POWEROFF ||
5614                      arg_action == ACTION_REBOOT)) {
5615                         r = reboot_with_logind(bus, arg_action);
5616                         if (r >= 0)
5617                                 return r;
5618                 }
5619
5620                 log_error("Must be root.");
5621                 return -EPERM;
5622         }
5623
5624         if (arg_when > 0) {
5625                 char *m;
5626
5627                 m = strv_join(arg_wall, " ");
5628                 r = send_shutdownd(arg_when,
5629                                    arg_action == ACTION_HALT     ? 'H' :
5630                                    arg_action == ACTION_POWEROFF ? 'P' :
5631                                    arg_action == ACTION_KEXEC    ? 'K' :
5632                                                                    'r',
5633                                    arg_dry,
5634                                    !arg_no_wall,
5635                                    m);
5636                 free(m);
5637
5638                 if (r < 0)
5639                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5640                 else {
5641                         char date[FORMAT_TIMESTAMP_MAX];
5642
5643                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5644                                  format_timestamp(date, sizeof(date), arg_when));
5645                         return 0;
5646                 }
5647         }
5648
5649         if (!arg_dry && !arg_force)
5650                 return start_with_fallback(bus);
5651
5652         if (!arg_no_wtmp) {
5653                 if (sd_booted() > 0)
5654                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5655                 else {
5656                         r = utmp_put_shutdown();
5657                         if (r < 0)
5658                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5659                 }
5660         }
5661
5662         if (!arg_no_sync)
5663                 sync();
5664
5665         if (arg_dry)
5666                 return 0;
5667
5668         halt_now(arg_action);
5669         /* We should never reach this. */
5670         return -ENOSYS;
5671 }
5672
5673 static int runlevel_main(void) {
5674         int r, runlevel, previous;
5675
5676         r = utmp_get_runlevel(&runlevel, &previous);
5677         if (r < 0) {
5678                 puts("unknown");
5679                 return r;
5680         }
5681
5682         printf("%c %c\n",
5683                previous <= 0 ? 'N' : previous,
5684                runlevel <= 0 ? 'N' : runlevel);
5685
5686         return 0;
5687 }
5688
5689 int main(int argc, char*argv[]) {
5690         int r, retval = EXIT_FAILURE;
5691         DBusConnection *bus = NULL;
5692         DBusError error;
5693
5694         dbus_error_init(&error);
5695
5696         log_parse_environment();
5697         log_open();
5698
5699         r = parse_argv(argc, argv);
5700         if (r < 0)
5701                 goto finish;
5702         else if (r == 0) {
5703                 retval = EXIT_SUCCESS;
5704                 goto finish;
5705         }
5706
5707         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5708          * let's shortcut this */
5709         if (arg_action == ACTION_RUNLEVEL) {
5710                 r = runlevel_main();
5711                 retval = r < 0 ? EXIT_FAILURE : r;
5712                 goto finish;
5713         }
5714
5715         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5716                 log_info("Running in chroot, ignoring request.");
5717                 retval = 0;
5718                 goto finish;
5719         }
5720
5721         if (!avoid_bus()) {
5722                 if (arg_transport == TRANSPORT_NORMAL)
5723                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5724                 else if (arg_transport == TRANSPORT_POLKIT) {
5725                         bus_connect_system_polkit(&bus, &error);
5726                         private_bus = false;
5727                 } else if (arg_transport == TRANSPORT_SSH) {
5728                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5729                         private_bus = false;
5730                 } else
5731                         assert_not_reached("Uh, invalid transport...");
5732         }
5733
5734         switch (arg_action) {
5735
5736         case ACTION_SYSTEMCTL:
5737                 r = systemctl_main(bus, argc, argv, &error);
5738                 break;
5739
5740         case ACTION_HALT:
5741         case ACTION_POWEROFF:
5742         case ACTION_REBOOT:
5743         case ACTION_KEXEC:
5744                 r = halt_main(bus);
5745                 break;
5746
5747         case ACTION_RUNLEVEL2:
5748         case ACTION_RUNLEVEL3:
5749         case ACTION_RUNLEVEL4:
5750         case ACTION_RUNLEVEL5:
5751         case ACTION_RESCUE:
5752         case ACTION_EMERGENCY:
5753         case ACTION_DEFAULT:
5754                 r = start_with_fallback(bus);
5755                 break;
5756
5757         case ACTION_RELOAD:
5758         case ACTION_REEXEC:
5759                 r = reload_with_fallback(bus);
5760                 break;
5761
5762         case ACTION_CANCEL_SHUTDOWN:
5763                 r = send_shutdownd(0, 0, false, false, NULL);
5764                 break;
5765
5766         case ACTION_INVALID:
5767         case ACTION_RUNLEVEL:
5768         default:
5769                 assert_not_reached("Unknown action");
5770         }
5771
5772         retval = r < 0 ? EXIT_FAILURE : r;
5773
5774 finish:
5775         if (bus) {
5776                 dbus_connection_flush(bus);
5777                 dbus_connection_close(bus);
5778                 dbus_connection_unref(bus);
5779         }
5780
5781         dbus_error_free(&error);
5782
5783         dbus_shutdown();
5784
5785         strv_free(arg_property);
5786
5787         pager_close();
5788         ask_password_agent_close();
5789         polkit_agent_close();
5790
5791         return retval;
5792 }