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