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