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