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