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