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