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