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