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