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