chiark / gitweb /
3abd7dc2e16c5ec80494d998ec08c13a0861dfc8
[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                 unsigned c;
2270
2271                 printf("\t  CGroup: %s\n", i->default_control_group);
2272
2273                 if (arg_transport != TRANSPORT_SSH) {
2274                         unsigned k = 0;
2275                         pid_t extra[2];
2276
2277                         c = columns();
2278                         if (c > 18)
2279                                 c -= 18;
2280                         else
2281                                 c = 0;
2282
2283                         if (i->main_pid > 0)
2284                                 extra[k++] = i->main_pid;
2285
2286                         if (i->control_pid > 0)
2287                                 extra[k++] = i->control_pid;
2288
2289                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2290                 }
2291         }
2292
2293         if (i->id && arg_transport != TRANSPORT_SSH) {
2294                 int flags =
2295                         arg_all * OUTPUT_SHOW_ALL |
2296                         (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2297                         on_tty() * OUTPUT_COLOR |
2298                         !arg_quiet * OUTPUT_WARN_CUTOFF;
2299
2300                 printf("\n");
2301                 show_journal_by_unit(stdout,
2302                                      i->id,
2303                                      arg_output,
2304                                      0,
2305                                      i->inactive_exit_timestamp_monotonic,
2306                                      arg_lines,
2307                                      flags);
2308         }
2309
2310         if (i->need_daemon_reload)
2311                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2312                        ansi_highlight_red(true),
2313                        ansi_highlight_red(false),
2314                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2315 }
2316
2317 static void show_unit_help(UnitStatusInfo *i) {
2318         char **p;
2319
2320         assert(i);
2321
2322         if (!i->documentation) {
2323                 log_info("Documentation for %s not known.", i->id);
2324                 return;
2325         }
2326
2327         STRV_FOREACH(p, i->documentation) {
2328
2329                 if (startswith(*p, "man:")) {
2330                         size_t k;
2331                         char *e = NULL;
2332                         char *page = NULL, *section = NULL;
2333                         const char *args[4] = { "man", NULL, NULL, NULL };
2334                         pid_t pid;
2335
2336                         k = strlen(*p);
2337
2338                         if ((*p)[k-1] == ')')
2339                                 e = strrchr(*p, '(');
2340
2341                         if (e) {
2342                                 page = strndup((*p) + 4, e - *p - 4);
2343                                 if (!page) {
2344                                         log_oom();
2345                                         return;
2346                                 }
2347
2348                                 section = strndup(e + 1, *p + k - e - 2);
2349                                 if (!section) {
2350                                         free(page);
2351                                         log_oom();
2352                                         return;
2353                                 }
2354
2355                                 args[1] = section;
2356                                 args[2] = page;
2357                         } else
2358                                 args[1] = *p + 4;
2359
2360                         pid = fork();
2361                         if (pid < 0) {
2362                                 log_error("Failed to fork: %m");
2363                                 free(page);
2364                                 free(section);
2365                                 continue;
2366                         }
2367
2368                         if (pid == 0) {
2369                                 /* Child */
2370                                 execvp(args[0], (char**) args);
2371                                 log_error("Failed to execute man: %m");
2372                                 _exit(EXIT_FAILURE);
2373                         }
2374
2375                         free(page);
2376                         free(section);
2377
2378                         wait_for_terminate(pid, NULL);
2379                 } else
2380                         log_info("Can't show: %s", *p);
2381         }
2382 }
2383
2384 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2385
2386         assert(name);
2387         assert(iter);
2388         assert(i);
2389
2390         switch (dbus_message_iter_get_arg_type(iter)) {
2391
2392         case DBUS_TYPE_STRING: {
2393                 const char *s;
2394
2395                 dbus_message_iter_get_basic(iter, &s);
2396
2397                 if (!isempty(s)) {
2398                         if (streq(name, "Id"))
2399                                 i->id = s;
2400                         else if (streq(name, "LoadState"))
2401                                 i->load_state = s;
2402                         else if (streq(name, "ActiveState"))
2403                                 i->active_state = s;
2404                         else if (streq(name, "SubState"))
2405                                 i->sub_state = s;
2406                         else if (streq(name, "Description"))
2407                                 i->description = s;
2408                         else if (streq(name, "FragmentPath"))
2409                                 i->fragment_path = s;
2410                         else if (streq(name, "SourcePath"))
2411                                 i->source_path = s;
2412                         else if (streq(name, "DefaultControlGroup"))
2413                                 i->default_control_group = s;
2414                         else if (streq(name, "StatusText"))
2415                                 i->status_text = s;
2416                         else if (streq(name, "SysFSPath"))
2417                                 i->sysfs_path = s;
2418                         else if (streq(name, "Where"))
2419                                 i->where = s;
2420                         else if (streq(name, "What"))
2421                                 i->what = s;
2422                         else if (streq(name, "Following"))
2423                                 i->following = s;
2424                         else if (streq(name, "UnitFileState"))
2425                                 i->unit_file_state = s;
2426                         else if (streq(name, "Result"))
2427                                 i->result = s;
2428                 }
2429
2430                 break;
2431         }
2432
2433         case DBUS_TYPE_BOOLEAN: {
2434                 dbus_bool_t b;
2435
2436                 dbus_message_iter_get_basic(iter, &b);
2437
2438                 if (streq(name, "Accept"))
2439                         i->accept = b;
2440                 else if (streq(name, "NeedDaemonReload"))
2441                         i->need_daemon_reload = b;
2442                 else if (streq(name, "ConditionResult"))
2443                         i->condition_result = b;
2444
2445                 break;
2446         }
2447
2448         case DBUS_TYPE_UINT32: {
2449                 uint32_t u;
2450
2451                 dbus_message_iter_get_basic(iter, &u);
2452
2453                 if (streq(name, "MainPID")) {
2454                         if (u > 0) {
2455                                 i->main_pid = (pid_t) u;
2456                                 i->running = true;
2457                         }
2458                 } else if (streq(name, "ControlPID"))
2459                         i->control_pid = (pid_t) u;
2460                 else if (streq(name, "ExecMainPID")) {
2461                         if (u > 0)
2462                                 i->main_pid = (pid_t) u;
2463                 } else if (streq(name, "NAccepted"))
2464                         i->n_accepted = u;
2465                 else if (streq(name, "NConnections"))
2466                         i->n_connections = u;
2467
2468                 break;
2469         }
2470
2471         case DBUS_TYPE_INT32: {
2472                 int32_t j;
2473
2474                 dbus_message_iter_get_basic(iter, &j);
2475
2476                 if (streq(name, "ExecMainCode"))
2477                         i->exit_code = (int) j;
2478                 else if (streq(name, "ExecMainStatus"))
2479                         i->exit_status = (int) j;
2480
2481                 break;
2482         }
2483
2484         case DBUS_TYPE_UINT64: {
2485                 uint64_t u;
2486
2487                 dbus_message_iter_get_basic(iter, &u);
2488
2489                 if (streq(name, "ExecMainStartTimestamp"))
2490                         i->start_timestamp = (usec_t) u;
2491                 else if (streq(name, "ExecMainExitTimestamp"))
2492                         i->exit_timestamp = (usec_t) u;
2493                 else if (streq(name, "ActiveEnterTimestamp"))
2494                         i->active_enter_timestamp = (usec_t) u;
2495                 else if (streq(name, "InactiveEnterTimestamp"))
2496                         i->inactive_enter_timestamp = (usec_t) u;
2497                 else if (streq(name, "InactiveExitTimestamp"))
2498                         i->inactive_exit_timestamp = (usec_t) u;
2499                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2500                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2501                 else if (streq(name, "ActiveExitTimestamp"))
2502                         i->active_exit_timestamp = (usec_t) u;
2503                 else if (streq(name, "ConditionTimestamp"))
2504                         i->condition_timestamp = (usec_t) u;
2505
2506                 break;
2507         }
2508
2509         case DBUS_TYPE_ARRAY: {
2510
2511                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2512                     startswith(name, "Exec")) {
2513                         DBusMessageIter sub;
2514
2515                         dbus_message_iter_recurse(iter, &sub);
2516                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2517                                 ExecStatusInfo *info;
2518                                 int r;
2519
2520                                 if (!(info = new0(ExecStatusInfo, 1)))
2521                                         return -ENOMEM;
2522
2523                                 if (!(info->name = strdup(name))) {
2524                                         free(info);
2525                                         return -ENOMEM;
2526                                 }
2527
2528                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2529                                         free(info);
2530                                         return r;
2531                                 }
2532
2533                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2534
2535                                 dbus_message_iter_next(&sub);
2536                         }
2537                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2538                            streq(name, "Documentation")) {
2539
2540                         DBusMessageIter sub;
2541
2542                         dbus_message_iter_recurse(iter, &sub);
2543                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2544                                 const char *s;
2545                                 char **l;
2546
2547                                 dbus_message_iter_get_basic(&sub, &s);
2548
2549                                 l = strv_append(i->documentation, s);
2550                                 if (!l)
2551                                         return -ENOMEM;
2552
2553                                 strv_free(i->documentation);
2554                                 i->documentation = l;
2555
2556                                 dbus_message_iter_next(&sub);
2557                         }
2558                 }
2559
2560                 break;
2561         }
2562
2563         case DBUS_TYPE_STRUCT: {
2564
2565                 if (streq(name, "LoadError")) {
2566                         DBusMessageIter sub;
2567                         const char *n, *message;
2568                         int r;
2569
2570                         dbus_message_iter_recurse(iter, &sub);
2571
2572                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2573                         if (r < 0)
2574                                 return r;
2575
2576                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2577                         if (r < 0)
2578                                 return r;
2579
2580                         if (!isempty(message))
2581                                 i->load_error = message;
2582                 }
2583
2584                 break;
2585         }
2586         }
2587
2588         return 0;
2589 }
2590
2591 static int print_property(const char *name, DBusMessageIter *iter) {
2592         assert(name);
2593         assert(iter);
2594
2595         /* This is a low-level property printer, see
2596          * print_status_info() for the nicer output */
2597
2598         if (arg_property && !strv_find(arg_property, name))
2599                 return 0;
2600
2601         switch (dbus_message_iter_get_arg_type(iter)) {
2602
2603         case DBUS_TYPE_STRUCT: {
2604                 DBusMessageIter sub;
2605                 dbus_message_iter_recurse(iter, &sub);
2606
2607                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2608                         uint32_t u;
2609
2610                         dbus_message_iter_get_basic(&sub, &u);
2611
2612                         if (u)
2613                                 printf("%s=%u\n", name, (unsigned) u);
2614                         else if (arg_all)
2615                                 printf("%s=\n", name);
2616
2617                         return 0;
2618                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2619                         const char *s;
2620
2621                         dbus_message_iter_get_basic(&sub, &s);
2622
2623                         if (arg_all || s[0])
2624                                 printf("%s=%s\n", name, s);
2625
2626                         return 0;
2627                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2628                         const char *a = NULL, *b = NULL;
2629
2630                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2631                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2632
2633                         if (arg_all || !isempty(a) || !isempty(b))
2634                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2635
2636                         return 0;
2637                 }
2638
2639                 break;
2640         }
2641
2642         case DBUS_TYPE_ARRAY:
2643
2644                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2645                         DBusMessageIter sub, sub2;
2646
2647                         dbus_message_iter_recurse(iter, &sub);
2648                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2649                                 const char *path;
2650                                 dbus_bool_t ignore;
2651
2652                                 dbus_message_iter_recurse(&sub, &sub2);
2653
2654                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2655                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2656                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2657
2658                                 dbus_message_iter_next(&sub);
2659                         }
2660
2661                         return 0;
2662
2663                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2664                         DBusMessageIter sub, sub2;
2665
2666                         dbus_message_iter_recurse(iter, &sub);
2667                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2668                                 const char *type, *path;
2669
2670                                 dbus_message_iter_recurse(&sub, &sub2);
2671
2672                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2673                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2674                                         printf("%s=%s\n", type, path);
2675
2676                                 dbus_message_iter_next(&sub);
2677                         }
2678
2679                         return 0;
2680
2681                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2682                         DBusMessageIter sub, sub2;
2683
2684                         dbus_message_iter_recurse(iter, &sub);
2685                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2686                                 const char *base;
2687                                 uint64_t value, next_elapse;
2688
2689                                 dbus_message_iter_recurse(&sub, &sub2);
2690
2691                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2692                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2693                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2694                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2695
2696                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2697                                                base,
2698                                                format_timespan(timespan1, sizeof(timespan1), value),
2699                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2700                                 }
2701
2702                                 dbus_message_iter_next(&sub);
2703                         }
2704
2705                         return 0;
2706
2707                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2708                         DBusMessageIter sub, sub2;
2709
2710                         dbus_message_iter_recurse(iter, &sub);
2711                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2712                                 const char *controller, *attr, *value;
2713
2714                                 dbus_message_iter_recurse(&sub, &sub2);
2715
2716                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2717                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2718                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2719
2720                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2721                                                controller,
2722                                                attr,
2723                                                value);
2724                                 }
2725
2726                                 dbus_message_iter_next(&sub);
2727                         }
2728
2729                         return 0;
2730
2731                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2732                         DBusMessageIter sub;
2733
2734                         dbus_message_iter_recurse(iter, &sub);
2735                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2736                                 ExecStatusInfo info;
2737
2738                                 zero(info);
2739                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2740                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2741                                         char *t;
2742
2743                                         t = strv_join(info.argv, " ");
2744
2745                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2746                                                name,
2747                                                strna(info.path),
2748                                                strna(t),
2749                                                yes_no(info.ignore),
2750                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2751                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2752                                                (unsigned) info. pid,
2753                                                sigchld_code_to_string(info.code),
2754                                                info.status,
2755                                                info.code == CLD_EXITED ? "" : "/",
2756                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2757
2758                                         free(t);
2759                                 }
2760
2761                                 free(info.path);
2762                                 strv_free(info.argv);
2763
2764                                 dbus_message_iter_next(&sub);
2765                         }
2766
2767                         return 0;
2768                 }
2769
2770                 break;
2771         }
2772
2773         if (generic_print_property(name, iter, arg_all) > 0)
2774                 return 0;
2775
2776         if (arg_all)
2777                 printf("%s=[unprintable]\n", name);
2778
2779         return 0;
2780 }
2781
2782 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2783         DBusMessage *reply = NULL;
2784         const char *interface = "";
2785         int r;
2786         DBusMessageIter iter, sub, sub2, sub3;
2787         UnitStatusInfo info;
2788         ExecStatusInfo *p;
2789
2790         assert(path);
2791         assert(new_line);
2792
2793         zero(info);
2794
2795         r = bus_method_call_with_reply (
2796                         bus,
2797                         "org.freedesktop.systemd1",
2798                         path,
2799                         "org.freedesktop.DBus.Properties",
2800                         "GetAll",
2801                         &reply,
2802                         NULL,
2803                         DBUS_TYPE_STRING, &interface,
2804                         DBUS_TYPE_INVALID);
2805         if (r)
2806                 goto finish;
2807
2808         if (!dbus_message_iter_init(reply, &iter) ||
2809             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2810             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2811                 log_error("Failed to parse reply.");
2812                 r = -EIO;
2813                 goto finish;
2814         }
2815
2816         dbus_message_iter_recurse(&iter, &sub);
2817
2818         if (*new_line)
2819                 printf("\n");
2820
2821         *new_line = true;
2822
2823         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2824                 const char *name;
2825
2826                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2827                         log_error("Failed to parse reply.");
2828                         r = -EIO;
2829                         goto finish;
2830                 }
2831
2832                 dbus_message_iter_recurse(&sub, &sub2);
2833
2834                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2835                         log_error("Failed to parse reply.");
2836                         r = -EIO;
2837                         goto finish;
2838                 }
2839
2840                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2841                         log_error("Failed to parse reply.");
2842                         r = -EIO;
2843                         goto finish;
2844                 }
2845
2846                 dbus_message_iter_recurse(&sub2, &sub3);
2847
2848                 if (show_properties)
2849                         r = print_property(name, &sub3);
2850                 else
2851                         r = status_property(name, &sub3, &info);
2852
2853                 if (r < 0) {
2854                         log_error("Failed to parse reply.");
2855                         r = -EIO;
2856                         goto finish;
2857                 }
2858
2859                 dbus_message_iter_next(&sub);
2860         }
2861
2862         r = 0;
2863
2864         if (!show_properties) {
2865                 if (streq(verb, "help"))
2866                         show_unit_help(&info);
2867                 else
2868                         print_status_info(&info);
2869         }
2870
2871         strv_free(info.documentation);
2872
2873         if (!streq_ptr(info.active_state, "active") &&
2874             !streq_ptr(info.active_state, "reloading") &&
2875             streq(verb, "status"))
2876                 /* According to LSB: "program not running" */
2877                 r = 3;
2878
2879         while ((p = info.exec)) {
2880                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2881                 exec_status_info_free(p);
2882         }
2883
2884 finish:
2885         if (reply)
2886                 dbus_message_unref(reply);
2887
2888         return r;
2889 }
2890
2891 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
2892         DBusMessage *reply = NULL;
2893         const char *path = NULL;
2894         DBusError error;
2895         int r;
2896
2897         dbus_error_init(&error);
2898
2899         r = bus_method_call_with_reply (
2900                         bus,
2901                         "org.freedesktop.systemd1",
2902                         "/org/freedesktop/systemd1",
2903                         "org.freedesktop.systemd1.Manager",
2904                         "GetUnitByPID",
2905                         &reply,
2906                         NULL,
2907                         DBUS_TYPE_UINT32, &pid,
2908                         DBUS_TYPE_INVALID);
2909         if (r)
2910                 goto finish;
2911
2912         if (!dbus_message_get_args(reply, &error,
2913                                    DBUS_TYPE_OBJECT_PATH, &path,
2914                                    DBUS_TYPE_INVALID)) {
2915                 log_error("Failed to parse reply: %s", bus_error_message(&error));
2916                 r = -EIO;
2917                 goto finish;
2918         }
2919
2920         r = show_one(verb, bus, path, false, new_line);
2921
2922 finish:
2923         if (reply)
2924                 dbus_message_unref(reply);
2925
2926         dbus_error_free(&error);
2927
2928         return r;
2929 }
2930
2931 static int show(DBusConnection *bus, char **args) {
2932         int r, ret = 0;
2933         bool show_properties, new_line = false;
2934         char **name;
2935
2936         assert(bus);
2937         assert(args);
2938
2939         show_properties = streq(args[0], "show");
2940
2941         if (show_properties)
2942                 pager_open_if_enabled();
2943
2944         if (show_properties && strv_length(args) <= 1) {
2945                 /* If not argument is specified inspect the manager
2946                  * itself */
2947
2948                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2949         }
2950
2951         STRV_FOREACH(name, args+1) {
2952                 uint32_t id;
2953
2954                 if (safe_atou32(*name, &id) < 0) {
2955                         char *p, *n;
2956                         /* Interpret as unit name */
2957
2958                         n = unit_name_mangle(*name);
2959                         p = unit_dbus_path_from_name(n ? n : *name);
2960                         free(n);
2961                         if (!p)
2962                                 return log_oom();
2963
2964                         r = show_one(args[0], bus, p, show_properties, &new_line);
2965                         free(p);
2966
2967                         if (r != 0)
2968                                 ret = r;
2969
2970                 } else if (show_properties) {
2971
2972                         /* Interpret as job id */
2973
2974                         char *p;
2975                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
2976                                 return log_oom();
2977
2978                         r = show_one(args[0], bus, p, show_properties, &new_line);
2979                         free(p);
2980
2981                         if (r != 0)
2982                                 ret = r;
2983
2984                 } else {
2985
2986                         /* Interpret as PID */
2987
2988                         r = show_one_by_pid(args[0], bus, id, &new_line);
2989                         if (r != 0)
2990                                 ret = r;
2991                 }
2992         }
2993
2994         return ret;
2995 }
2996
2997 static int dump(DBusConnection *bus, char **args) {
2998         DBusMessage *reply = NULL;
2999         DBusError error;
3000         int r;
3001         const char *text;
3002
3003         dbus_error_init(&error);
3004
3005         pager_open_if_enabled();
3006
3007         r = bus_method_call_with_reply (
3008                         bus,
3009                         "org.freedesktop.systemd1",
3010                         "/org/freedesktop/systemd1",
3011                         "org.freedesktop.systemd1.Manager",
3012                         "Dump",
3013                         &reply,
3014                         NULL,
3015                         DBUS_TYPE_INVALID);
3016         if (r)
3017                 goto finish;
3018
3019         if (!dbus_message_get_args(reply, &error,
3020                                    DBUS_TYPE_STRING, &text,
3021                                    DBUS_TYPE_INVALID)) {
3022                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3023                 r = -EIO;
3024                 goto finish;
3025         }
3026
3027         fputs(text, stdout);
3028
3029 finish:
3030         if (reply)
3031                 dbus_message_unref(reply);
3032
3033         dbus_error_free(&error);
3034
3035         return r;
3036 }
3037
3038 static int snapshot(DBusConnection *bus, char **args) {
3039         DBusMessage *reply = NULL;
3040         DBusError error;
3041         int r;
3042         dbus_bool_t cleanup = FALSE;
3043         DBusMessageIter iter, sub;
3044         const char
3045                 *name = "", *path, *id,
3046                 *interface = "org.freedesktop.systemd1.Unit",
3047                 *property = "Id";
3048         char *n;
3049
3050         dbus_error_init(&error);
3051
3052         if (strv_length(args) > 1)
3053                 name = args[1];
3054
3055         n = unit_name_mangle(name);
3056         r = bus_method_call_with_reply (
3057                         bus,
3058                         "org.freedesktop.systemd1",
3059                         "/org/freedesktop/systemd1",
3060                         "org.freedesktop.systemd1.Manager",
3061                         "CreateSnapshot",
3062                         &reply,
3063                         NULL,
3064                         DBUS_TYPE_STRING, n ? (const char**) &n : &name,
3065                         DBUS_TYPE_BOOLEAN, &cleanup,
3066                         DBUS_TYPE_INVALID);
3067         free(n);
3068         if (r)
3069                 goto finish;
3070
3071         if (!dbus_message_get_args(reply, &error,
3072                                    DBUS_TYPE_OBJECT_PATH, &path,
3073                                    DBUS_TYPE_INVALID)) {
3074                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3075                 r = -EIO;
3076                 goto finish;
3077         }
3078
3079         dbus_message_unref(reply);
3080         r = bus_method_call_with_reply (
3081                         bus,
3082                         "org.freedesktop.systemd1",
3083                         path,
3084                         "org.freedesktop.DBus.Properties",
3085                         "Get",
3086                         &reply,
3087                         NULL,
3088                         DBUS_TYPE_STRING, &interface,
3089                         DBUS_TYPE_STRING, &property,
3090                         DBUS_TYPE_INVALID);
3091         if (r)
3092                 goto finish;
3093
3094         if (!dbus_message_iter_init(reply, &iter) ||
3095             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3096                 log_error("Failed to parse reply.");
3097                 r = -EIO;
3098                 goto finish;
3099         }
3100
3101         dbus_message_iter_recurse(&iter, &sub);
3102
3103         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3104                 log_error("Failed to parse reply.");
3105                 r = -EIO;
3106                 goto finish;
3107         }
3108
3109         dbus_message_iter_get_basic(&sub, &id);
3110
3111         if (!arg_quiet)
3112                 puts(id);
3113
3114 finish:
3115         if (reply)
3116                 dbus_message_unref(reply);
3117
3118         dbus_error_free(&error);
3119
3120         return r;
3121 }
3122
3123 static int delete_snapshot(DBusConnection *bus, char **args) {
3124         DBusMessage *reply = NULL;
3125         int r = 0;
3126         DBusError error;
3127         char **name;
3128
3129         assert(args);
3130
3131         dbus_error_init(&error);
3132
3133         STRV_FOREACH(name, args+1) {
3134                 const char *path = NULL;
3135                 char *n;
3136
3137                 n = unit_name_mangle(*name);
3138                 r = bus_method_call_with_reply (
3139                                 bus,
3140                                 "org.freedesktop.systemd1",
3141                                 "/org/freedesktop/systemd1",
3142                                 "org.freedesktop.systemd1.Manager",
3143                                 "GetUnit",
3144                                 &reply,
3145                                 NULL,
3146                                 DBUS_TYPE_STRING, n ? &n : name,
3147                                 DBUS_TYPE_INVALID);
3148                 free(n);
3149                 if (r)
3150                         goto finish;
3151
3152                 if (!dbus_message_get_args(reply, &error,
3153                                            DBUS_TYPE_OBJECT_PATH, &path,
3154                                            DBUS_TYPE_INVALID)) {
3155                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3156                         r = -EIO;
3157                         dbus_message_unref(reply);
3158                         dbus_error_free(&error);
3159                         goto finish;
3160                 }
3161                 dbus_message_unref(reply);
3162
3163                 r = bus_method_call_with_reply (
3164                                 bus,
3165                                 "org.freedesktop.systemd1",
3166                                 path,
3167                                 "org.freedesktop.systemd1.Snapshot",
3168                                 "Remove",
3169                                 NULL,
3170                                 NULL,
3171                                 DBUS_TYPE_INVALID);
3172                 if (r)
3173                         goto finish;
3174         }
3175
3176 finish:
3177         return r;
3178 }
3179
3180 static int daemon_reload(DBusConnection *bus, char **args) {
3181         int r;
3182         const char *method;
3183         DBusError error;
3184
3185         if (arg_action == ACTION_RELOAD)
3186                 method = "Reload";
3187         else if (arg_action == ACTION_REEXEC)
3188                 method = "Reexecute";
3189         else {
3190                 assert(arg_action == ACTION_SYSTEMCTL);
3191
3192                 method =
3193                         streq(args[0], "clear-jobs")    ||
3194                         streq(args[0], "cancel")        ? "ClearJobs" :
3195                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3196                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3197                         streq(args[0], "halt")          ? "Halt" :
3198                         streq(args[0], "poweroff")      ? "PowerOff" :
3199                         streq(args[0], "reboot")        ? "Reboot" :
3200                         streq(args[0], "kexec")         ? "KExec" :
3201                         streq(args[0], "exit")          ? "Exit" :
3202                                     /* "daemon-reload" */ "Reload";
3203         }
3204
3205         r = bus_method_call_with_reply (
3206                         bus,
3207                         "org.freedesktop.systemd1",
3208                         "/org/freedesktop/systemd1",
3209                         "org.freedesktop.systemd1.Manager",
3210                         method,
3211                         NULL,
3212                         &error,
3213                         DBUS_TYPE_INVALID);
3214
3215         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3216                 /* There's always a fallback possible for
3217                  * legacy actions. */
3218                 r = -EADDRNOTAVAIL;
3219         else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3220                 /* On reexecution, we expect a disconnect, not
3221                  * a reply */
3222                 r = 0;
3223         else if (r)
3224                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3225         dbus_error_free(&error);
3226
3227         return r;
3228 }
3229
3230 static int reset_failed(DBusConnection *bus, char **args) {
3231         int r = 0;
3232         char **name, *n;
3233
3234         if (strv_length(args) <= 1)
3235                 return daemon_reload(bus, args);
3236
3237         STRV_FOREACH(name, args+1) {
3238                 n = unit_name_mangle(*name);
3239                 r = bus_method_call_with_reply (
3240                                 bus,
3241                                 "org.freedesktop.systemd1",
3242                                 "/org/freedesktop/systemd1",
3243                                 "org.freedesktop.systemd1.Manager",
3244                                 "ResetFailedUnit",
3245                                 NULL,
3246                                 NULL,
3247                                 DBUS_TYPE_STRING, n ? &n : name,
3248                                 DBUS_TYPE_INVALID);
3249                 free(n);
3250                 if (r)
3251                         goto finish;
3252         }
3253
3254 finish:
3255         return r;
3256 }
3257
3258 static int show_enviroment(DBusConnection *bus, char **args) {
3259         DBusMessage *reply = NULL;
3260         DBusMessageIter iter, sub, sub2;
3261         int r;
3262         const char
3263                 *interface = "org.freedesktop.systemd1.Manager",
3264                 *property = "Environment";
3265
3266         pager_open_if_enabled();
3267
3268         r = bus_method_call_with_reply (
3269                         bus,
3270                         "org.freedesktop.systemd1",
3271                         "/org/freedesktop/systemd1",
3272                         "org.freedesktop.DBus.Properties",
3273                         "Get",
3274                         &reply,
3275                         NULL,
3276                         DBUS_TYPE_STRING, &interface,
3277                         DBUS_TYPE_STRING, &property,
3278                         DBUS_TYPE_INVALID);
3279         if (r)
3280                 goto finish;
3281
3282         if (!dbus_message_iter_init(reply, &iter) ||
3283             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3284                 log_error("Failed to parse reply.");
3285                 r = -EIO;
3286                 goto finish;
3287         }
3288
3289         dbus_message_iter_recurse(&iter, &sub);
3290
3291         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3292             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3293                 log_error("Failed to parse reply.");
3294                 r = -EIO;
3295                 goto finish;
3296         }
3297
3298         dbus_message_iter_recurse(&sub, &sub2);
3299
3300         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3301                 const char *text;
3302
3303                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3304                         log_error("Failed to parse reply.");
3305                         r = -EIO;
3306                         goto finish;
3307                 }
3308
3309                 dbus_message_iter_get_basic(&sub2, &text);
3310                 printf("%s\n", text);
3311
3312                 dbus_message_iter_next(&sub2);
3313         }
3314
3315         r = 0;
3316
3317 finish:
3318         if (reply)
3319                 dbus_message_unref(reply);
3320
3321         return r;
3322 }
3323
3324 static int switch_root(DBusConnection *bus, char **args) {
3325         unsigned l;
3326         const char *root, *init;
3327
3328         l = strv_length(args);
3329         if (l < 2 || l > 3) {
3330                 log_error("Wrong number of arguments.");
3331                 return -EINVAL;
3332         }
3333
3334         root = args[1];
3335         init = l >= 3 ? args[2] : "";
3336
3337         return bus_method_call_with_reply (
3338                         bus,
3339                         "org.freedesktop.systemd1",
3340                         "/org/freedesktop/systemd1",
3341                         "org.freedesktop.systemd1.Manager",
3342                         "SwitchRoot",
3343                         NULL,
3344                         NULL,
3345                         DBUS_TYPE_STRING, &root,
3346                         DBUS_TYPE_STRING, &init,
3347                         DBUS_TYPE_INVALID);
3348 }
3349
3350 static int set_environment(DBusConnection *bus, char **args) {
3351         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
3352         DBusError error;
3353         const char *method;
3354         DBusMessageIter iter;
3355         int r;
3356
3357         assert(bus);
3358
3359         dbus_error_init(&error);
3360
3361         method = streq(args[0], "set-environment")
3362                 ? "SetEnvironment"
3363                 : "UnsetEnvironment";
3364
3365         m = dbus_message_new_method_call(
3366                         "org.freedesktop.systemd1",
3367                         "/org/freedesktop/systemd1",
3368                         "org.freedesktop.systemd1.Manager",
3369                         method);
3370         if (!m)
3371                 return log_oom();
3372
3373         dbus_message_iter_init_append(m, &iter);
3374
3375         r = bus_append_strv_iter(&iter, args + 1);
3376         if (r < 0)
3377                 return log_oom();
3378
3379         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3380         if (!reply) {
3381                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3382                 r = -EIO;
3383                 goto finish;
3384         }
3385
3386         r = 0;
3387
3388 finish:
3389         dbus_error_free(&error);
3390         return r;
3391 }
3392
3393 static int enable_sysv_units(char **args) {
3394         int r = 0;
3395
3396 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3397         const char *verb = args[0];
3398         unsigned f = 1, t = 1;
3399         LookupPaths paths;
3400
3401         if (arg_scope != UNIT_FILE_SYSTEM)
3402                 return 0;
3403
3404         if (!streq(verb, "enable") &&
3405             !streq(verb, "disable") &&
3406             !streq(verb, "is-enabled"))
3407                 return 0;
3408
3409         /* Processes all SysV units, and reshuffles the array so that
3410          * afterwards only the native units remain */
3411
3412         zero(paths);
3413         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
3414         if (r < 0)
3415                 return r;
3416
3417         r = 0;
3418         for (f = 1; args[f]; f++) {
3419                 const char *name;
3420                 char *p;
3421                 bool found_native = false, found_sysv;
3422                 unsigned c = 1;
3423                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3424                 char **k, *l, *q = NULL;
3425                 int j;
3426                 pid_t pid;
3427                 siginfo_t status;
3428
3429                 name = args[f];
3430
3431                 if (!endswith(name, ".service"))
3432                         continue;
3433
3434                 if (path_is_absolute(name))
3435                         continue;
3436
3437                 STRV_FOREACH(k, paths.unit_path) {
3438                         p = NULL;
3439
3440                         if (!isempty(arg_root))
3441                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3442                         else
3443                                 asprintf(&p, "%s/%s", *k, name);
3444
3445                         if (!p) {
3446                                 r = log_oom();
3447                                 goto finish;
3448                         }
3449
3450                         found_native = access(p, F_OK) >= 0;
3451                         free(p);
3452
3453                         if (found_native)
3454                                 break;
3455                 }
3456
3457                 if (found_native)
3458                         continue;
3459
3460                 p = NULL;
3461                 if (!isempty(arg_root))
3462                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3463                 else
3464                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3465                 if (!p) {
3466                         r = log_oom();
3467                         goto finish;
3468                 }
3469
3470                 p[strlen(p) - sizeof(".service") + 1] = 0;
3471                 found_sysv = access(p, F_OK) >= 0;
3472
3473                 if (!found_sysv) {
3474                         free(p);
3475                         continue;
3476                 }
3477
3478                 /* Mark this entry, so that we don't try enabling it as native unit */
3479                 args[f] = (char*) "";
3480
3481                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3482
3483                 if (!isempty(arg_root))
3484                         argv[c++] = q = strappend("--root=", arg_root);
3485
3486                 argv[c++] = path_get_file_name(p);
3487                 argv[c++] =
3488                         streq(verb, "enable") ? "on" :
3489                         streq(verb, "disable") ? "off" : "--level=5";
3490                 argv[c] = NULL;
3491
3492                 l = strv_join((char**)argv, " ");
3493                 if (!l) {
3494                         free(q);
3495                         free(p);
3496                         r = log_oom();
3497                         goto finish;
3498                 }
3499
3500                 log_info("Executing %s", l);
3501                 free(l);
3502
3503                 pid = fork();
3504                 if (pid < 0) {
3505                         log_error("Failed to fork: %m");
3506                         free(p);
3507                         free(q);
3508                         r = -errno;
3509                         goto finish;
3510                 } else if (pid == 0) {
3511                         /* Child */
3512
3513                         execv(argv[0], (char**) argv);
3514                         _exit(EXIT_FAILURE);
3515                 }
3516
3517                 free(p);
3518                 free(q);
3519
3520                 j = wait_for_terminate(pid, &status);
3521                 if (j < 0) {
3522                         log_error("Failed to wait for child: %s", strerror(-r));
3523                         r = j;
3524                         goto finish;
3525                 }
3526
3527                 if (status.si_code == CLD_EXITED) {
3528                         if (streq(verb, "is-enabled")) {
3529                                 if (status.si_status == 0) {
3530                                         if (!arg_quiet)
3531                                                 puts("enabled");
3532                                         r = 1;
3533                                 } else {
3534                                         if (!arg_quiet)
3535                                                 puts("disabled");
3536                                 }
3537
3538                         } else if (status.si_status != 0) {
3539                                 r = -EINVAL;
3540                                 goto finish;
3541                         }
3542                 } else {
3543                         r = -EPROTO;
3544                         goto finish;
3545                 }
3546         }
3547
3548 finish:
3549         lookup_paths_free(&paths);
3550
3551         /* Drop all SysV units */
3552         for (f = 1, t = 1; args[f]; f++) {
3553
3554                 if (isempty(args[f]))
3555                         continue;
3556
3557                 args[t++] = args[f];
3558         }
3559
3560         args[t] = NULL;
3561
3562 #endif
3563         return r;
3564 }
3565
3566 static int mangle_names(char **original_names, char ***mangled_names) {
3567         char **i, **l, **name;
3568
3569         l = new(char*, strv_length(original_names) + 1);
3570         if (!l)
3571                 return log_oom();
3572
3573         i = l;
3574         STRV_FOREACH(name, original_names) {
3575
3576                 /* When enabling units qualified path names are OK,
3577                  * too, hence allow them explicitly. */
3578
3579                 if (is_path(*name))
3580                         *i = strdup(*name);
3581                 else
3582                         *i = unit_name_mangle(*name);
3583
3584                 if (!*i) {
3585                         strv_free(l);
3586                         return log_oom();
3587                 }
3588
3589                 i++;
3590         }
3591
3592         *i = NULL;
3593         *mangled_names = l;
3594
3595         return 0;
3596 }
3597
3598 static int enable_unit(DBusConnection *bus, char **args) {
3599         const char *verb = args[0];
3600         UnitFileChange *changes = NULL;
3601         unsigned n_changes = 0, i;
3602         int carries_install_info = -1;
3603         DBusMessage *m = NULL, *reply = NULL;
3604         int r;
3605         DBusError error;
3606         char **mangled_names = NULL;
3607
3608         r = enable_sysv_units(args);
3609         if (r < 0)
3610                 return r;
3611
3612         if (!args[1])
3613                 return 0;
3614
3615         dbus_error_init(&error);
3616
3617         if (!bus || avoid_bus()) {
3618                 if (streq(verb, "enable")) {
3619                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3620                         carries_install_info = r;
3621                 } else if (streq(verb, "disable"))
3622                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3623                 else if (streq(verb, "reenable")) {
3624                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3625                         carries_install_info = r;
3626                 } else if (streq(verb, "link"))
3627                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3628                 else if (streq(verb, "preset")) {
3629                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3630                         carries_install_info = r;
3631                 } else if (streq(verb, "mask"))
3632                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3633                 else if (streq(verb, "unmask"))
3634                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3635                 else
3636                         assert_not_reached("Unknown verb");
3637
3638                 if (r < 0) {
3639                         log_error("Operation failed: %s", strerror(-r));
3640                         goto finish;
3641                 }
3642
3643                 if (!arg_quiet) {
3644                         for (i = 0; i < n_changes; i++) {
3645                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3646                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3647                                 else
3648                                         log_info("rm '%s'", changes[i].path);
3649                         }
3650                 }
3651
3652                 r = 0;
3653         } else {
3654                 const char *method;
3655                 bool send_force = true, expect_carries_install_info = false;
3656                 dbus_bool_t a, b;
3657                 DBusMessageIter iter, sub, sub2;
3658
3659                 if (streq(verb, "enable")) {
3660                         method = "EnableUnitFiles";
3661                         expect_carries_install_info = true;
3662                 } else if (streq(verb, "disable")) {
3663                         method = "DisableUnitFiles";
3664                         send_force = false;
3665                 } else if (streq(verb, "reenable")) {
3666                         method = "ReenableUnitFiles";
3667                         expect_carries_install_info = true;
3668                 } else if (streq(verb, "link"))
3669                         method = "LinkUnitFiles";
3670                 else if (streq(verb, "preset")) {
3671                         method = "PresetUnitFiles";
3672                         expect_carries_install_info = true;
3673                 } else if (streq(verb, "mask"))
3674                         method = "MaskUnitFiles";
3675                 else if (streq(verb, "unmask")) {
3676                         method = "UnmaskUnitFiles";
3677                         send_force = false;
3678                 } else
3679                         assert_not_reached("Unknown verb");
3680
3681                 m = dbus_message_new_method_call(
3682                                 "org.freedesktop.systemd1",
3683                                 "/org/freedesktop/systemd1",
3684                                 "org.freedesktop.systemd1.Manager",
3685                                 method);
3686                 if (!m) {
3687                         r = log_oom();
3688                         goto finish;
3689                 }
3690
3691                 dbus_message_iter_init_append(m, &iter);
3692
3693                 r = mangle_names(args+1, &mangled_names);
3694                 if(r < 0)
3695                         goto finish;
3696
3697                 r = bus_append_strv_iter(&iter, mangled_names);
3698                 if (r < 0) {
3699                         log_error("Failed to append unit files.");
3700                         goto finish;
3701                 }
3702
3703                 a = arg_runtime;
3704                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3705                         log_error("Failed to append runtime boolean.");
3706                         r = -ENOMEM;
3707                         goto finish;
3708                 }
3709
3710                 if (send_force) {
3711                         b = arg_force;
3712
3713                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3714                                 log_error("Failed to append force boolean.");
3715                                 r = -ENOMEM;
3716                                 goto finish;
3717                         }
3718                 }
3719
3720                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3721                 if (!reply) {
3722                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3723                         r = -EIO;
3724                         goto finish;
3725                 }
3726
3727                 if (!dbus_message_iter_init(reply, &iter)) {
3728                         log_error("Failed to initialize iterator.");
3729                         goto finish;
3730                 }
3731
3732                 if (expect_carries_install_info) {
3733                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3734                         if (r < 0) {
3735                                 log_error("Failed to parse reply.");
3736                                 goto finish;
3737                         }
3738
3739                         carries_install_info = b;
3740                 }
3741
3742                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3743                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3744                         log_error("Failed to parse reply.");
3745                         r = -EIO;
3746                         goto finish;
3747                 }
3748
3749                 dbus_message_iter_recurse(&iter, &sub);
3750                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3751                         const char *type, *path, *source;
3752
3753                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3754                                 log_error("Failed to parse reply.");
3755                                 r = -EIO;
3756                                 goto finish;
3757                         }
3758
3759                         dbus_message_iter_recurse(&sub, &sub2);
3760
3761                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3762                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3763                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3764                                 log_error("Failed to parse reply.");
3765                                 r = -EIO;
3766                                 goto finish;
3767                         }
3768
3769                         if (!arg_quiet) {
3770                                 if (streq(type, "symlink"))
3771                                         log_info("ln -s '%s' '%s'", source, path);
3772                                 else
3773                                         log_info("rm '%s'", path);
3774                         }
3775
3776                         dbus_message_iter_next(&sub);
3777                 }
3778
3779                 /* Try to reload if enabeld */
3780                 if (!arg_no_reload)
3781                         r = daemon_reload(bus, args);
3782         }
3783
3784         if (carries_install_info == 0)
3785                 log_warning(
3786 "The unit files have no [Install] section. They are not meant to be enabled\n"
3787 "using systemctl.\n"
3788 "Possible reasons for having this kind of units are:\n"
3789 "1) A unit may be statically enabled by being symlinked from another unit's\n"
3790 "   .wants/ or .requires/ directory.\n"
3791 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
3792 "   a requirement dependency on it.\n"
3793 "3) A unit may be started when needed via activation (socket, path, timer,\n"
3794 "   D-Bus, udev, scripted systemctl call, ...).\n");
3795
3796 finish:
3797         if (m)
3798                 dbus_message_unref(m);
3799
3800         if (reply)
3801                 dbus_message_unref(reply);
3802
3803         unit_file_changes_free(changes, n_changes);
3804
3805         dbus_error_free(&error);
3806
3807         strv_free(mangled_names);
3808
3809         return r;
3810 }
3811
3812 static int unit_is_enabled(DBusConnection *bus, char **args) {
3813         DBusError error;
3814         int r;
3815         DBusMessage *reply = NULL;
3816         bool enabled;
3817         char **name;
3818
3819         dbus_error_init(&error);
3820
3821         r = enable_sysv_units(args);
3822         if (r < 0)
3823                 return r;
3824
3825         enabled = r > 0;
3826
3827         if (!bus || avoid_bus()) {
3828
3829                 STRV_FOREACH(name, args+1) {
3830                         UnitFileState state;
3831
3832                         state = unit_file_get_state(arg_scope, arg_root, *name);
3833                         if (state < 0) {
3834                                 r = state;
3835                                 goto finish;
3836                         }
3837
3838                         if (state == UNIT_FILE_ENABLED ||
3839                             state == UNIT_FILE_ENABLED_RUNTIME ||
3840                             state == UNIT_FILE_STATIC)
3841                                 enabled = true;
3842
3843                         if (!arg_quiet)
3844                                 puts(unit_file_state_to_string(state));
3845                 }
3846
3847         } else {
3848                 STRV_FOREACH(name, args+1) {
3849                         const char *s;
3850
3851                         r = bus_method_call_with_reply (
3852                                         bus,
3853                                         "org.freedesktop.systemd1",
3854                                         "/org/freedesktop/systemd1",
3855                                         "org.freedesktop.systemd1.Manager",
3856                                         "GetUnitFileState",
3857                                         &reply,
3858                                         NULL,
3859                                         DBUS_TYPE_STRING, name,
3860                                         DBUS_TYPE_INVALID);
3861                         if (r)
3862                                 goto finish;
3863
3864                         if (!dbus_message_get_args(reply, &error,
3865                                                    DBUS_TYPE_STRING, &s,
3866                                                    DBUS_TYPE_INVALID)) {
3867                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3868                                 r = -EIO;
3869                                 goto finish;
3870                         }
3871
3872                         dbus_message_unref(reply);
3873                         reply = NULL;
3874
3875                         if (streq(s, "enabled") ||
3876                             streq(s, "enabled-runtime") ||
3877                             streq(s, "static"))
3878                                 enabled = true;
3879
3880                         if (!arg_quiet)
3881                                 puts(s);
3882                 }
3883         }
3884
3885         r = enabled ? 0 : 1;
3886
3887 finish:
3888         if (reply)
3889                 dbus_message_unref(reply);
3890
3891         dbus_error_free(&error);
3892         return r;
3893 }
3894
3895 static int systemctl_help(void) {
3896
3897         pager_open_if_enabled();
3898
3899         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3900                "Query or send control commands to the systemd manager.\n\n"
3901                "  -h --help           Show this help\n"
3902                "     --version        Show package version\n"
3903                "  -t --type=TYPE      List only units of a particular type\n"
3904                "  -p --property=NAME  Show only properties by this name\n"
3905                "  -a --all            Show all units/properties, including dead/empty ones\n"
3906                "     --failed         Show only failed units\n"
3907                "     --full           Don't ellipsize unit names on output\n"
3908                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
3909                "                      pending\n"
3910                "     --ignore-dependencies\n"
3911                "                      When queueing a new job, ignore all its dependencies\n"
3912                "     --kill-who=WHO   Who to send signal to\n"
3913                "  -s --signal=SIGNAL  Which signal to send\n"
3914                "  -H --host=[USER@]HOST\n"
3915                "                      Show information for remote host\n"
3916                "  -P --privileged     Acquire privileges before execution\n"
3917                "  -q --quiet          Suppress output\n"
3918                "     --no-block       Do not wait until operation finished\n"
3919                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
3920                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
3921                "                      configuration\n"
3922                "     --no-legend      Do not print a legend (column headers and hints)\n"
3923                "     --no-pager       Do not pipe output into a pager\n"
3924                "     --no-ask-password\n"
3925                "                      Do not ask for system passwords\n"
3926                "     --order          When generating graph for dot, show only order\n"
3927                "     --require        When generating graph for dot, show only requirement\n"
3928                "     --system         Connect to system manager\n"
3929                "     --user           Connect to user service manager\n"
3930                "     --global         Enable/disable unit files globally\n"
3931                "  -f --force          When enabling unit files, override existing symlinks\n"
3932                "                      When shutting down, execute action immediately\n"
3933                "     --root=PATH      Enable unit files in the specified root directory\n"
3934                "     --runtime        Enable unit files only temporarily until next reboot\n"
3935                "  -n --lines=INTEGER  Journal entries to show\n"
3936                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
3937                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
3938                "Unit Commands:\n"
3939                "  list-units                      List loaded units\n"
3940                "  start [NAME...]                 Start (activate) one or more units\n"
3941                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
3942                "  reload [NAME...]                Reload one or more units\n"
3943                "  restart [NAME...]               Start or restart one or more units\n"
3944                "  try-restart [NAME...]           Restart one or more units if active\n"
3945                "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
3946                "                                  otherwise start or restart\n"
3947                "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
3948                "                                  otherwise restart if active\n"
3949                "  isolate [NAME]                  Start one unit and stop all others\n"
3950                "  kill [NAME...]                  Send signal to processes of a unit\n"
3951                "  is-active [NAME...]             Check whether units are active\n"
3952                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
3953                "  show [NAME...|JOB...]           Show properties of one or more\n"
3954                "                                  units/jobs or the manager\n"
3955                "  help [NAME...|PID...]            Show manual for one or more units\n"
3956                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
3957                "                                  units\n"
3958                "  load [NAME...]                  Load one or more units\n\n"
3959                "Unit File Commands:\n"
3960                "  list-unit-files                 List installed unit files\n"
3961                "  enable [NAME...]                Enable one or more unit files\n"
3962                "  disable [NAME...]               Disable one or more unit files\n"
3963                "  reenable [NAME...]              Reenable one or more unit files\n"
3964                "  preset [NAME...]                Enable/disable one or more unit files\n"
3965                "                                  based on preset configuration\n"
3966                "  mask [NAME...]                  Mask one or more units\n"
3967                "  unmask [NAME...]                Unmask one or more units\n"
3968                "  link [PATH...]                  Link one or more units files into\n"
3969                "                                  the search path\n"
3970                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
3971                "Job Commands:\n"
3972                "  list-jobs                       List jobs\n"
3973                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
3974                "Status Commands:\n"
3975                "  dump                            Dump server status\n"
3976                "  dot                             Dump dependency graph for dot(1)\n\n"
3977                "Snapshot Commands:\n"
3978                "  snapshot [NAME]                 Create a snapshot\n"
3979                "  delete [NAME...]                Remove one or more snapshots\n\n"
3980                "Environment Commands:\n"
3981                "  show-environment                Dump environment\n"
3982                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
3983                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
3984                "Manager Lifecycle Commands:\n"
3985                "  daemon-reload                   Reload systemd manager configuration\n"
3986                "  daemon-reexec                   Reexecute systemd manager\n\n"
3987                "System Commands:\n"
3988                "  default                         Enter system default mode\n"
3989                "  rescue                          Enter system rescue mode\n"
3990                "  emergency                       Enter system emergency mode\n"
3991                "  halt                            Shut down and halt the system\n"
3992                "  poweroff                        Shut down and power-off the system\n"
3993                "  reboot                          Shut down and reboot the system\n"
3994                "  kexec                           Shut down and reboot the system with kexec\n"
3995                "  exit                            Request user instance exit\n"
3996                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
3997                "  suspend                         Suspend the system\n"
3998                "  hibernate                       Hibernate the system\n"
3999                "  hybrid-sleep                    Hibernate and suspend the system\n",
4000                program_invocation_short_name);
4001
4002         return 0;
4003 }
4004
4005 static int halt_help(void) {
4006
4007         printf("%s [OPTIONS...]\n\n"
4008                "%s the system.\n\n"
4009                "     --help      Show this help\n"
4010                "     --halt      Halt the machine\n"
4011                "  -p --poweroff  Switch off the machine\n"
4012                "     --reboot    Reboot the machine\n"
4013                "  -f --force     Force immediate halt/power-off/reboot\n"
4014                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4015                "  -d --no-wtmp   Don't write wtmp record\n"
4016                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4017                program_invocation_short_name,
4018                arg_action == ACTION_REBOOT   ? "Reboot" :
4019                arg_action == ACTION_POWEROFF ? "Power off" :
4020                                                "Halt");
4021
4022         return 0;
4023 }
4024
4025 static int shutdown_help(void) {
4026
4027         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4028                "Shut down the system.\n\n"
4029                "     --help      Show this help\n"
4030                "  -H --halt      Halt the machine\n"
4031                "  -P --poweroff  Power-off the machine\n"
4032                "  -r --reboot    Reboot the machine\n"
4033                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4034                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4035                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4036                "  -c             Cancel a pending shutdown\n",
4037                program_invocation_short_name);
4038
4039         return 0;
4040 }
4041
4042 static int telinit_help(void) {
4043
4044         printf("%s [OPTIONS...] {COMMAND}\n\n"
4045                "Send control commands to the init daemon.\n\n"
4046                "     --help      Show this help\n"
4047                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4048                "Commands:\n"
4049                "  0              Power-off the machine\n"
4050                "  6              Reboot the machine\n"
4051                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4052                "  1, s, S        Enter rescue mode\n"
4053                "  q, Q           Reload init daemon configuration\n"
4054                "  u, U           Reexecute init daemon\n",
4055                program_invocation_short_name);
4056
4057         return 0;
4058 }
4059
4060 static int runlevel_help(void) {
4061
4062         printf("%s [OPTIONS...]\n\n"
4063                "Prints the previous and current runlevel of the init system.\n\n"
4064                "     --help      Show this help\n",
4065                program_invocation_short_name);
4066
4067         return 0;
4068 }
4069
4070 static int help_types(void) {
4071         int i;
4072
4073         puts("Available unit types:");
4074         for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++)
4075                 if (unit_type_table[i])
4076                         puts(unit_type_table[i]);
4077
4078         puts("\nAvailable unit load states: ");
4079         for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++)
4080                 if (unit_type_table[i])
4081                         puts(unit_load_state_table[i]);
4082
4083         return 0;
4084 }
4085
4086 static int systemctl_parse_argv(int argc, char *argv[]) {
4087
4088         enum {
4089                 ARG_FAIL = 0x100,
4090                 ARG_IGNORE_DEPENDENCIES,
4091                 ARG_VERSION,
4092                 ARG_USER,
4093                 ARG_SYSTEM,
4094                 ARG_GLOBAL,
4095                 ARG_NO_BLOCK,
4096                 ARG_NO_LEGEND,
4097                 ARG_NO_PAGER,
4098                 ARG_NO_WALL,
4099                 ARG_ORDER,
4100                 ARG_REQUIRE,
4101                 ARG_ROOT,
4102                 ARG_FULL,
4103                 ARG_NO_RELOAD,
4104                 ARG_KILL_WHO,
4105                 ARG_NO_ASK_PASSWORD,
4106                 ARG_FAILED,
4107                 ARG_RUNTIME,
4108                 ARG_FORCE
4109         };
4110
4111         static const struct option options[] = {
4112                 { "help",      no_argument,       NULL, 'h'           },
4113                 { "version",   no_argument,       NULL, ARG_VERSION   },
4114                 { "type",      required_argument, NULL, 't'           },
4115                 { "property",  required_argument, NULL, 'p'           },
4116                 { "all",       no_argument,       NULL, 'a'           },
4117                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4118                 { "full",      no_argument,       NULL, ARG_FULL      },
4119                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4120                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4121                 { "user",      no_argument,       NULL, ARG_USER      },
4122                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4123                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4124                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4125                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4126                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4127                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4128                 { "quiet",     no_argument,       NULL, 'q'           },
4129                 { "order",     no_argument,       NULL, ARG_ORDER     },
4130                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4131                 { "root",      required_argument, NULL, ARG_ROOT      },
4132                 { "force",     no_argument,       NULL, ARG_FORCE     },
4133                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4134                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4135                 { "signal",    required_argument, NULL, 's'           },
4136                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4137                 { "host",      required_argument, NULL, 'H'           },
4138                 { "privileged",no_argument,       NULL, 'P'           },
4139                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4140                 { "lines",     required_argument, NULL, 'n'           },
4141                 { "output",    required_argument, NULL, 'o'           },
4142                 { NULL,        0,                 NULL, 0             }
4143         };
4144
4145         int c;
4146
4147         assert(argc >= 0);
4148         assert(argv);
4149
4150         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4151
4152                 switch (c) {
4153
4154                 case 'h':
4155                         systemctl_help();
4156                         return 0;
4157
4158                 case ARG_VERSION:
4159                         puts(PACKAGE_STRING);
4160                         puts(DISTRIBUTION);
4161                         puts(SYSTEMD_FEATURES);
4162                         return 0;
4163
4164                 case 't':
4165                         if (streq(optarg, "help")) {
4166                                 help_types();
4167                                 return 0;
4168                         }
4169
4170                         if (unit_type_from_string(optarg) >= 0) {
4171                                 arg_type = optarg;
4172                                 break;
4173                         }
4174                         if (unit_load_state_from_string(optarg) >= 0) {
4175                                 arg_load_state = optarg;
4176                                 break;
4177                         }
4178                         log_error("Unkown unit type or load state '%s'.",
4179                                   optarg);
4180                         log_info("Use -t help to see a list of allowed values.");
4181                         return -EINVAL;
4182                 case 'p': {
4183                         char **l;
4184
4185                         if (!(l = strv_append(arg_property, optarg)))
4186                                 return -ENOMEM;
4187
4188                         strv_free(arg_property);
4189                         arg_property = l;
4190
4191                         /* If the user asked for a particular
4192                          * property, show it to him, even if it is
4193                          * empty. */
4194                         arg_all = true;
4195                         break;
4196                 }
4197
4198                 case 'a':
4199                         arg_all = true;
4200                         break;
4201
4202                 case ARG_FAIL:
4203                         arg_job_mode = "fail";
4204                         break;
4205
4206                 case ARG_IGNORE_DEPENDENCIES:
4207                         arg_job_mode = "ignore-dependencies";
4208                         break;
4209
4210                 case ARG_USER:
4211                         arg_scope = UNIT_FILE_USER;
4212                         break;
4213
4214                 case ARG_SYSTEM:
4215                         arg_scope = UNIT_FILE_SYSTEM;
4216                         break;
4217
4218                 case ARG_GLOBAL:
4219                         arg_scope = UNIT_FILE_GLOBAL;
4220                         break;
4221
4222                 case ARG_NO_BLOCK:
4223                         arg_no_block = true;
4224                         break;
4225
4226                 case ARG_NO_LEGEND:
4227                         arg_no_legend = true;
4228                         break;
4229
4230                 case ARG_NO_PAGER:
4231                         arg_no_pager = true;
4232                         break;
4233
4234                 case ARG_NO_WALL:
4235                         arg_no_wall = true;
4236                         break;
4237
4238                 case ARG_ORDER:
4239                         arg_dot = DOT_ORDER;
4240                         break;
4241
4242                 case ARG_REQUIRE:
4243                         arg_dot = DOT_REQUIRE;
4244                         break;
4245
4246                 case ARG_ROOT:
4247                         arg_root = optarg;
4248                         break;
4249
4250                 case ARG_FULL:
4251                         arg_full = true;
4252                         break;
4253
4254                 case ARG_FAILED:
4255                         arg_failed = true;
4256                         break;
4257
4258                 case 'q':
4259                         arg_quiet = true;
4260                         break;
4261
4262                 case ARG_FORCE:
4263                         arg_force ++;
4264                         break;
4265
4266                 case 'f':
4267                         arg_force ++;
4268                         break;
4269
4270                 case ARG_NO_RELOAD:
4271                         arg_no_reload = true;
4272                         break;
4273
4274                 case ARG_KILL_WHO:
4275                         arg_kill_who = optarg;
4276                         break;
4277
4278                 case 's':
4279                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4280                                 log_error("Failed to parse signal string %s.", optarg);
4281                                 return -EINVAL;
4282                         }
4283                         break;
4284
4285                 case ARG_NO_ASK_PASSWORD:
4286                         arg_ask_password = false;
4287                         break;
4288
4289                 case 'P':
4290                         arg_transport = TRANSPORT_POLKIT;
4291                         break;
4292
4293                 case 'H':
4294                         arg_transport = TRANSPORT_SSH;
4295                         arg_host = optarg;
4296                         break;
4297
4298                 case ARG_RUNTIME:
4299                         arg_runtime = true;
4300                         break;
4301
4302                 case 'n':
4303                         if (safe_atou(optarg, &arg_lines) < 0) {
4304                                 log_error("Failed to parse lines '%s'", optarg);
4305                                 return -EINVAL;
4306                         }
4307                         break;
4308
4309                 case 'o':
4310                         arg_output = output_mode_from_string(optarg);
4311                         if (arg_output < 0) {
4312                                 log_error("Unknown output '%s'.", optarg);
4313                                 return -EINVAL;
4314                         }
4315                         break;
4316
4317                 case '?':
4318                         return -EINVAL;
4319
4320                 default:
4321                         log_error("Unknown option code '%c'.", c);
4322                         return -EINVAL;
4323                 }
4324         }
4325
4326         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4327                 log_error("Cannot access user instance remotely.");
4328                 return -EINVAL;
4329         }
4330
4331         return 1;
4332 }
4333
4334 static int halt_parse_argv(int argc, char *argv[]) {
4335
4336         enum {
4337                 ARG_HELP = 0x100,
4338                 ARG_HALT,
4339                 ARG_REBOOT,
4340                 ARG_NO_WALL
4341         };
4342
4343         static const struct option options[] = {
4344                 { "help",      no_argument,       NULL, ARG_HELP    },
4345                 { "halt",      no_argument,       NULL, ARG_HALT    },
4346                 { "poweroff",  no_argument,       NULL, 'p'         },
4347                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4348                 { "force",     no_argument,       NULL, 'f'         },
4349                 { "wtmp-only", no_argument,       NULL, 'w'         },
4350                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4351                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4352                 { NULL,        0,                 NULL, 0           }
4353         };
4354
4355         int c, runlevel;
4356
4357         assert(argc >= 0);
4358         assert(argv);
4359
4360         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4361                 if (runlevel == '0' || runlevel == '6')
4362                         arg_force = 2;
4363
4364         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4365                 switch (c) {
4366
4367                 case ARG_HELP:
4368                         halt_help();
4369                         return 0;
4370
4371                 case ARG_HALT:
4372                         arg_action = ACTION_HALT;
4373                         break;
4374
4375                 case 'p':
4376                         if (arg_action != ACTION_REBOOT)
4377                                 arg_action = ACTION_POWEROFF;
4378                         break;
4379
4380                 case ARG_REBOOT:
4381                         arg_action = ACTION_REBOOT;
4382                         break;
4383
4384                 case 'f':
4385                         arg_force = 2;
4386                         break;
4387
4388                 case 'w':
4389                         arg_dry = true;
4390                         break;
4391
4392                 case 'd':
4393                         arg_no_wtmp = true;
4394                         break;
4395
4396                 case ARG_NO_WALL:
4397                         arg_no_wall = true;
4398                         break;
4399
4400                 case 'i':
4401                 case 'h':
4402                 case 'n':
4403                         /* Compatibility nops */
4404                         break;
4405
4406                 case '?':
4407                         return -EINVAL;
4408
4409                 default:
4410                         log_error("Unknown option code '%c'.", c);
4411                         return -EINVAL;
4412                 }
4413         }
4414
4415         if (optind < argc) {
4416                 log_error("Too many arguments.");
4417                 return -EINVAL;
4418         }
4419
4420         return 1;
4421 }
4422
4423 static int parse_time_spec(const char *t, usec_t *_u) {
4424         assert(t);
4425         assert(_u);
4426
4427         if (streq(t, "now"))
4428                 *_u = 0;
4429         else if (!strchr(t, ':')) {
4430                 uint64_t u;
4431
4432                 if (safe_atou64(t, &u) < 0)
4433                         return -EINVAL;
4434
4435                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4436         } else {
4437                 char *e = NULL;
4438                 long hour, minute;
4439                 struct tm tm;
4440                 time_t s;
4441                 usec_t n;
4442
4443                 errno = 0;
4444                 hour = strtol(t, &e, 10);
4445                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4446                         return -EINVAL;
4447
4448                 minute = strtol(e+1, &e, 10);
4449                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4450                         return -EINVAL;
4451
4452                 n = now(CLOCK_REALTIME);
4453                 s = (time_t) (n / USEC_PER_SEC);
4454
4455                 zero(tm);
4456                 assert_se(localtime_r(&s, &tm));
4457
4458                 tm.tm_hour = (int) hour;
4459                 tm.tm_min = (int) minute;
4460                 tm.tm_sec = 0;
4461
4462                 assert_se(s = mktime(&tm));
4463
4464                 *_u = (usec_t) s * USEC_PER_SEC;
4465
4466                 while (*_u <= n)
4467                         *_u += USEC_PER_DAY;
4468         }
4469
4470         return 0;
4471 }
4472
4473 static int shutdown_parse_argv(int argc, char *argv[]) {
4474
4475         enum {
4476                 ARG_HELP = 0x100,
4477                 ARG_NO_WALL
4478         };
4479
4480         static const struct option options[] = {
4481                 { "help",      no_argument,       NULL, ARG_HELP    },
4482                 { "halt",      no_argument,       NULL, 'H'         },
4483                 { "poweroff",  no_argument,       NULL, 'P'         },
4484                 { "reboot",    no_argument,       NULL, 'r'         },
4485                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4486                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4487                 { NULL,        0,                 NULL, 0           }
4488         };
4489
4490         int c, r;
4491
4492         assert(argc >= 0);
4493         assert(argv);
4494
4495         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4496                 switch (c) {
4497
4498                 case ARG_HELP:
4499                         shutdown_help();
4500                         return 0;
4501
4502                 case 'H':
4503                         arg_action = ACTION_HALT;
4504                         break;
4505
4506                 case 'P':
4507                         arg_action = ACTION_POWEROFF;
4508                         break;
4509
4510                 case 'r':
4511                         if (kexec_loaded())
4512                                 arg_action = ACTION_KEXEC;
4513                         else
4514                                 arg_action = ACTION_REBOOT;
4515                         break;
4516
4517                 case 'K':
4518                         arg_action = ACTION_KEXEC;
4519                         break;
4520
4521                 case 'h':
4522                         if (arg_action != ACTION_HALT)
4523                                 arg_action = ACTION_POWEROFF;
4524                         break;
4525
4526                 case 'k':
4527                         arg_dry = true;
4528                         break;
4529
4530                 case ARG_NO_WALL:
4531                         arg_no_wall = true;
4532                         break;
4533
4534                 case 't':
4535                 case 'a':
4536                         /* Compatibility nops */
4537                         break;
4538
4539                 case 'c':
4540                         arg_action = ACTION_CANCEL_SHUTDOWN;
4541                         break;
4542
4543                 case '?':
4544                         return -EINVAL;
4545
4546                 default:
4547                         log_error("Unknown option code '%c'.", c);
4548                         return -EINVAL;
4549                 }
4550         }
4551
4552         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4553                 r = parse_time_spec(argv[optind], &arg_when);
4554                 if (r < 0) {
4555                         log_error("Failed to parse time specification: %s", argv[optind]);
4556                         return r;
4557                 }
4558         } else
4559                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4560
4561         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4562                 /* No time argument for shutdown cancel */
4563                 arg_wall = argv + optind;
4564         else if (argc > optind + 1)
4565                 /* We skip the time argument */
4566                 arg_wall = argv + optind + 1;
4567
4568         optind = argc;
4569
4570         return 1;
4571 }
4572
4573 static int telinit_parse_argv(int argc, char *argv[]) {
4574
4575         enum {
4576                 ARG_HELP = 0x100,
4577                 ARG_NO_WALL
4578         };
4579
4580         static const struct option options[] = {
4581                 { "help",      no_argument,       NULL, ARG_HELP    },
4582                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4583                 { NULL,        0,                 NULL, 0           }
4584         };
4585
4586         static const struct {
4587                 char from;
4588                 enum action to;
4589         } table[] = {
4590                 { '0', ACTION_POWEROFF },
4591                 { '6', ACTION_REBOOT },
4592                 { '1', ACTION_RESCUE },
4593                 { '2', ACTION_RUNLEVEL2 },
4594                 { '3', ACTION_RUNLEVEL3 },
4595                 { '4', ACTION_RUNLEVEL4 },
4596                 { '5', ACTION_RUNLEVEL5 },
4597                 { 's', ACTION_RESCUE },
4598                 { 'S', ACTION_RESCUE },
4599                 { 'q', ACTION_RELOAD },
4600                 { 'Q', ACTION_RELOAD },
4601                 { 'u', ACTION_REEXEC },
4602                 { 'U', ACTION_REEXEC }
4603         };
4604
4605         unsigned i;
4606         int c;
4607
4608         assert(argc >= 0);
4609         assert(argv);
4610
4611         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4612                 switch (c) {
4613
4614                 case ARG_HELP:
4615                         telinit_help();
4616                         return 0;
4617
4618                 case ARG_NO_WALL:
4619                         arg_no_wall = true;
4620                         break;
4621
4622                 case '?':
4623                         return -EINVAL;
4624
4625                 default:
4626                         log_error("Unknown option code '%c'.", c);
4627                         return -EINVAL;
4628                 }
4629         }
4630
4631         if (optind >= argc) {
4632                 telinit_help();
4633                 return -EINVAL;
4634         }
4635
4636         if (optind + 1 < argc) {
4637                 log_error("Too many arguments.");
4638                 return -EINVAL;
4639         }
4640
4641         if (strlen(argv[optind]) != 1) {
4642                 log_error("Expected single character argument.");
4643                 return -EINVAL;
4644         }
4645
4646         for (i = 0; i < ELEMENTSOF(table); i++)
4647                 if (table[i].from == argv[optind][0])
4648                         break;
4649
4650         if (i >= ELEMENTSOF(table)) {
4651                 log_error("Unknown command '%s'.", argv[optind]);
4652                 return -EINVAL;
4653         }
4654
4655         arg_action = table[i].to;
4656
4657         optind ++;
4658
4659         return 1;
4660 }
4661
4662 static int runlevel_parse_argv(int argc, char *argv[]) {
4663
4664         enum {
4665                 ARG_HELP = 0x100,
4666         };
4667
4668         static const struct option options[] = {
4669                 { "help",      no_argument,       NULL, ARG_HELP    },
4670                 { NULL,        0,                 NULL, 0           }
4671         };
4672
4673         int c;
4674
4675         assert(argc >= 0);
4676         assert(argv);
4677
4678         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4679                 switch (c) {
4680
4681                 case ARG_HELP:
4682                         runlevel_help();
4683                         return 0;
4684
4685                 case '?':
4686                         return -EINVAL;
4687
4688                 default:
4689                         log_error("Unknown option code '%c'.", c);
4690                         return -EINVAL;
4691                 }
4692         }
4693
4694         if (optind < argc) {
4695                 log_error("Too many arguments.");
4696                 return -EINVAL;
4697         }
4698
4699         return 1;
4700 }
4701
4702 static int parse_argv(int argc, char *argv[]) {
4703         assert(argc >= 0);
4704         assert(argv);
4705
4706         if (program_invocation_short_name) {
4707
4708                 if (strstr(program_invocation_short_name, "halt")) {
4709                         arg_action = ACTION_HALT;
4710                         return halt_parse_argv(argc, argv);
4711                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4712                         arg_action = ACTION_POWEROFF;
4713                         return halt_parse_argv(argc, argv);
4714                 } else if (strstr(program_invocation_short_name, "reboot")) {
4715                         if (kexec_loaded())
4716                                 arg_action = ACTION_KEXEC;
4717                         else
4718                                 arg_action = ACTION_REBOOT;
4719                         return halt_parse_argv(argc, argv);
4720                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4721                         arg_action = ACTION_POWEROFF;
4722                         return shutdown_parse_argv(argc, argv);
4723                 } else if (strstr(program_invocation_short_name, "init")) {
4724
4725                         if (sd_booted() > 0) {
4726                                 arg_action = ACTION_INVALID;
4727                                 return telinit_parse_argv(argc, argv);
4728                         } else {
4729                                 /* Hmm, so some other init system is
4730                                  * running, we need to forward this
4731                                  * request to it. For now we simply
4732                                  * guess that it is Upstart. */
4733
4734                                 execv("/lib/upstart/telinit", argv);
4735
4736                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4737                                 return -EIO;
4738                         }
4739
4740                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4741                         arg_action = ACTION_RUNLEVEL;
4742                         return runlevel_parse_argv(argc, argv);
4743                 }
4744         }
4745
4746         arg_action = ACTION_SYSTEMCTL;
4747         return systemctl_parse_argv(argc, argv);
4748 }
4749
4750 static int action_to_runlevel(void) {
4751
4752         static const char table[_ACTION_MAX] = {
4753                 [ACTION_HALT] =      '0',
4754                 [ACTION_POWEROFF] =  '0',
4755                 [ACTION_REBOOT] =    '6',
4756                 [ACTION_RUNLEVEL2] = '2',
4757                 [ACTION_RUNLEVEL3] = '3',
4758                 [ACTION_RUNLEVEL4] = '4',
4759                 [ACTION_RUNLEVEL5] = '5',
4760                 [ACTION_RESCUE] =    '1'
4761         };
4762
4763         assert(arg_action < _ACTION_MAX);
4764
4765         return table[arg_action];
4766 }
4767
4768 static int talk_upstart(void) {
4769         DBusMessage *m = NULL, *reply = NULL;
4770         DBusError error;
4771         int previous, rl, r;
4772         char
4773                 env1_buf[] = "RUNLEVEL=X",
4774                 env2_buf[] = "PREVLEVEL=X";
4775         char *env1 = env1_buf, *env2 = env2_buf;
4776         const char *emit = "runlevel";
4777         dbus_bool_t b_false = FALSE;
4778         DBusMessageIter iter, sub;
4779         DBusConnection *bus;
4780
4781         dbus_error_init(&error);
4782
4783         if (!(rl = action_to_runlevel()))
4784                 return 0;
4785
4786         if (utmp_get_runlevel(&previous, NULL) < 0)
4787                 previous = 'N';
4788
4789         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4790                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4791                         r = 0;
4792                         goto finish;
4793                 }
4794
4795                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4796                 r = -EIO;
4797                 goto finish;
4798         }
4799
4800         if ((r = bus_check_peercred(bus)) < 0) {
4801                 log_error("Failed to verify owner of bus.");
4802                 goto finish;
4803         }
4804
4805         if (!(m = dbus_message_new_method_call(
4806                               "com.ubuntu.Upstart",
4807                               "/com/ubuntu/Upstart",
4808                               "com.ubuntu.Upstart0_6",
4809                               "EmitEvent"))) {
4810
4811                 log_error("Could not allocate message.");
4812                 r = -ENOMEM;
4813                 goto finish;
4814         }
4815
4816         dbus_message_iter_init_append(m, &iter);
4817
4818         env1_buf[sizeof(env1_buf)-2] = rl;
4819         env2_buf[sizeof(env2_buf)-2] = previous;
4820
4821         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4822             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4823             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4824             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4825             !dbus_message_iter_close_container(&iter, &sub) ||
4826             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4827                 log_error("Could not append arguments to message.");
4828                 r = -ENOMEM;
4829                 goto finish;
4830         }
4831
4832         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4833
4834                 if (bus_error_is_no_service(&error)) {
4835                         r = -EADDRNOTAVAIL;
4836                         goto finish;
4837                 }
4838
4839                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4840                 r = -EIO;
4841                 goto finish;
4842         }
4843
4844         r = 1;
4845
4846 finish:
4847         if (m)
4848                 dbus_message_unref(m);
4849
4850         if (reply)
4851                 dbus_message_unref(reply);
4852
4853         if (bus) {
4854                 dbus_connection_flush(bus);
4855                 dbus_connection_close(bus);
4856                 dbus_connection_unref(bus);
4857         }
4858
4859         dbus_error_free(&error);
4860
4861         return r;
4862 }
4863
4864 static int talk_initctl(void) {
4865         struct init_request request;
4866         int r, fd;
4867         char rl;
4868
4869         if (!(rl = action_to_runlevel()))
4870                 return 0;
4871
4872         zero(request);
4873         request.magic = INIT_MAGIC;
4874         request.sleeptime = 0;
4875         request.cmd = INIT_CMD_RUNLVL;
4876         request.runlevel = rl;
4877
4878         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4879
4880                 if (errno == ENOENT)
4881                         return 0;
4882
4883                 log_error("Failed to open "INIT_FIFO": %m");
4884                 return -errno;
4885         }
4886
4887         errno = 0;
4888         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4889         close_nointr_nofail(fd);
4890
4891         if (r < 0) {
4892                 log_error("Failed to write to "INIT_FIFO": %m");
4893                 return errno ? -errno : -EIO;
4894         }
4895
4896         return 1;
4897 }
4898
4899 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4900
4901         static const struct {
4902                 const char* verb;
4903                 const enum {
4904                         MORE,
4905                         LESS,
4906                         EQUAL
4907                 } argc_cmp;
4908                 const int argc;
4909                 int (* const dispatch)(DBusConnection *bus, char **args);
4910         } verbs[] = {
4911                 { "list-units",            LESS,  1, list_units        },
4912                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
4913                 { "list-jobs",             EQUAL, 1, list_jobs         },
4914                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
4915                 { "load",                  MORE,  2, load_unit         },
4916                 { "cancel",                MORE,  2, cancel_job        },
4917                 { "start",                 MORE,  2, start_unit        },
4918                 { "stop",                  MORE,  2, start_unit        },
4919                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4920                 { "reload",                MORE,  2, start_unit        },
4921                 { "restart",               MORE,  2, start_unit        },
4922                 { "try-restart",           MORE,  2, start_unit        },
4923                 { "reload-or-restart",     MORE,  2, start_unit        },
4924                 { "reload-or-try-restart", MORE,  2, start_unit        },
4925                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
4926                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4927                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
4928                 { "isolate",               EQUAL, 2, start_unit        },
4929                 { "kill",                  MORE,  2, kill_unit         },
4930                 { "is-active",             MORE,  2, check_unit        },
4931                 { "check",                 MORE,  2, check_unit        },
4932                 { "show",                  MORE,  1, show              },
4933                 { "status",                MORE,  2, show              },
4934                 { "help",                  MORE,  2, show              },
4935                 { "dump",                  EQUAL, 1, dump              },
4936                 { "dot",                   EQUAL, 1, dot               },
4937                 { "snapshot",              LESS,  2, snapshot          },
4938                 { "delete",                MORE,  2, delete_snapshot   },
4939                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
4940                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
4941                 { "show-environment",      EQUAL, 1, show_enviroment   },
4942                 { "set-environment",       MORE,  2, set_environment   },
4943                 { "unset-environment",     MORE,  2, set_environment   },
4944                 { "halt",                  EQUAL, 1, start_special     },
4945                 { "poweroff",              EQUAL, 1, start_special     },
4946                 { "reboot",                EQUAL, 1, start_special     },
4947                 { "kexec",                 EQUAL, 1, start_special     },
4948                 { "suspend",               EQUAL, 1, start_special     },
4949                 { "hibernate",             EQUAL, 1, start_special     },
4950                 { "hybrid-sleep",          EQUAL, 1, start_special     },
4951                 { "default",               EQUAL, 1, start_special     },
4952                 { "rescue",                EQUAL, 1, start_special     },
4953                 { "emergency",             EQUAL, 1, start_special     },
4954                 { "exit",                  EQUAL, 1, start_special     },
4955                 { "reset-failed",          MORE,  1, reset_failed      },
4956                 { "enable",                MORE,  2, enable_unit       },
4957                 { "disable",               MORE,  2, enable_unit       },
4958                 { "is-enabled",            MORE,  2, unit_is_enabled   },
4959                 { "reenable",              MORE,  2, enable_unit       },
4960                 { "preset",                MORE,  2, enable_unit       },
4961                 { "mask",                  MORE,  2, enable_unit       },
4962                 { "unmask",                MORE,  2, enable_unit       },
4963                 { "link",                  MORE,  2, enable_unit       },
4964                 { "switch-root",           MORE,  2, switch_root       },
4965         };
4966
4967         int left;
4968         unsigned i;
4969
4970         assert(argc >= 0);
4971         assert(argv);
4972         assert(error);
4973
4974         left = argc - optind;
4975
4976         if (left <= 0)
4977                 /* Special rule: no arguments means "list-units" */
4978                 i = 0;
4979         else {
4980                 if (streq(argv[optind], "help") && !argv[optind+1]) {
4981                         log_error("This command expects one or more "
4982                                   "unit names. Did you mean --help?");
4983                         return -EINVAL;
4984                 }
4985
4986                 for (i = 0; i < ELEMENTSOF(verbs); i++)
4987                         if (streq(argv[optind], verbs[i].verb))
4988                                 break;
4989
4990                 if (i >= ELEMENTSOF(verbs)) {
4991                         log_error("Unknown operation '%s'.", argv[optind]);
4992                         return -EINVAL;
4993                 }
4994         }
4995
4996         switch (verbs[i].argc_cmp) {
4997
4998         case EQUAL:
4999                 if (left != verbs[i].argc) {
5000                         log_error("Invalid number of arguments.");
5001                         return -EINVAL;
5002                 }
5003
5004                 break;
5005
5006         case MORE:
5007                 if (left < verbs[i].argc) {
5008                         log_error("Too few arguments.");
5009                         return -EINVAL;
5010                 }
5011
5012                 break;
5013
5014         case LESS:
5015                 if (left > verbs[i].argc) {
5016                         log_error("Too many arguments.");
5017                         return -EINVAL;
5018                 }
5019
5020                 break;
5021
5022         default:
5023                 assert_not_reached("Unknown comparison operator.");
5024         }
5025
5026         /* Require a bus connection for all operations but
5027          * enable/disable */
5028         if (!streq(verbs[i].verb, "enable") &&
5029             !streq(verbs[i].verb, "disable") &&
5030             !streq(verbs[i].verb, "is-enabled") &&
5031             !streq(verbs[i].verb, "list-unit-files") &&
5032             !streq(verbs[i].verb, "reenable") &&
5033             !streq(verbs[i].verb, "preset") &&
5034             !streq(verbs[i].verb, "mask") &&
5035             !streq(verbs[i].verb, "unmask") &&
5036             !streq(verbs[i].verb, "link")) {
5037
5038                 if (running_in_chroot() > 0) {
5039                         log_info("Running in chroot, ignoring request.");
5040                         return 0;
5041                 }
5042
5043                 if (((!streq(verbs[i].verb, "reboot") &&
5044                       !streq(verbs[i].verb, "halt") &&
5045                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5046                         log_error("Failed to get D-Bus connection: %s",
5047                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5048                         return -EIO;
5049                 }
5050
5051         } else {
5052
5053                 if (!bus && !avoid_bus()) {
5054                         log_error("Failed to get D-Bus connection: %s",
5055                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5056                         return -EIO;
5057                 }
5058         }
5059
5060         return verbs[i].dispatch(bus, argv + optind);
5061 }
5062
5063 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5064         int fd;
5065         struct msghdr msghdr;
5066         struct iovec iovec[2];
5067         union sockaddr_union sockaddr;
5068         struct sd_shutdown_command c;
5069
5070         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5071         if (fd < 0)
5072                 return -errno;
5073
5074         zero(c);
5075         c.usec = t;
5076         c.mode = mode;
5077         c.dry_run = dry_run;
5078         c.warn_wall = warn;
5079
5080         zero(sockaddr);
5081         sockaddr.sa.sa_family = AF_UNIX;
5082         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5083
5084         zero(msghdr);
5085         msghdr.msg_name = &sockaddr;
5086         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5087
5088         zero(iovec);
5089         iovec[0].iov_base = (char*) &c;
5090         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5091
5092         if (isempty(message))
5093                 msghdr.msg_iovlen = 1;
5094         else {
5095                 iovec[1].iov_base = (char*) message;
5096                 iovec[1].iov_len = strlen(message);
5097                 msghdr.msg_iovlen = 2;
5098         }
5099         msghdr.msg_iov = iovec;
5100
5101         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5102                 close_nointr_nofail(fd);
5103                 return -errno;
5104         }
5105
5106         close_nointr_nofail(fd);
5107         return 0;
5108 }
5109
5110 static int reload_with_fallback(DBusConnection *bus) {
5111
5112         if (bus) {
5113                 /* First, try systemd via D-Bus. */
5114                 if (daemon_reload(bus, NULL) >= 0)
5115                         return 0;
5116         }
5117
5118         /* Nothing else worked, so let's try signals */
5119         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5120
5121         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5122                 log_error("kill() failed: %m");
5123                 return -errno;
5124         }
5125
5126         return 0;
5127 }
5128
5129 static int start_with_fallback(DBusConnection *bus) {
5130
5131         if (bus) {
5132                 /* First, try systemd via D-Bus. */
5133                 if (start_unit(bus, NULL) >= 0)
5134                         goto done;
5135         }
5136
5137         /* Hmm, talking to systemd via D-Bus didn't work. Then
5138          * let's try to talk to Upstart via D-Bus. */
5139         if (talk_upstart() > 0)
5140                 goto done;
5141
5142         /* Nothing else worked, so let's try
5143          * /dev/initctl */
5144         if (talk_initctl() > 0)
5145                 goto done;
5146
5147         log_error("Failed to talk to init daemon.");
5148         return -EIO;
5149
5150 done:
5151         warn_wall(arg_action);
5152         return 0;
5153 }
5154
5155 static _noreturn_ void halt_now(enum action a) {
5156
5157        /* Make sure C-A-D is handled by the kernel from this
5158          * point on... */
5159         reboot(RB_ENABLE_CAD);
5160
5161         switch (a) {
5162
5163         case ACTION_HALT:
5164                 log_info("Halting.");
5165                 reboot(RB_HALT_SYSTEM);
5166                 break;
5167
5168         case ACTION_POWEROFF:
5169                 log_info("Powering off.");
5170                 reboot(RB_POWER_OFF);
5171                 break;
5172
5173         case ACTION_REBOOT:
5174                 log_info("Rebooting.");
5175                 reboot(RB_AUTOBOOT);
5176                 break;
5177
5178         default:
5179                 assert_not_reached("Unknown halt action.");
5180         }
5181
5182         assert_not_reached("Uh? This shouldn't happen.");
5183 }
5184
5185 static int halt_main(DBusConnection *bus) {
5186         int r;
5187
5188         if (geteuid() != 0) {
5189                 /* Try logind if we are a normal user and no special
5190                  * mode applies. Maybe PolicyKit allows us to shutdown
5191                  * the machine. */
5192
5193                 if (arg_when <= 0 &&
5194                     !arg_dry &&
5195                     !arg_force &&
5196                     (arg_action == ACTION_POWEROFF ||
5197                      arg_action == ACTION_REBOOT)) {
5198                         r = reboot_with_logind(bus, arg_action);
5199                         if (r >= 0)
5200                                 return r;
5201                 }
5202
5203                 log_error("Must be root.");
5204                 return -EPERM;
5205         }
5206
5207         if (arg_when > 0) {
5208                 char *m;
5209
5210                 m = strv_join(arg_wall, " ");
5211                 r = send_shutdownd(arg_when,
5212                                    arg_action == ACTION_HALT     ? 'H' :
5213                                    arg_action == ACTION_POWEROFF ? 'P' :
5214                                    arg_action == ACTION_KEXEC    ? 'K' :
5215                                                                    'r',
5216                                    arg_dry,
5217                                    !arg_no_wall,
5218                                    m);
5219                 free(m);
5220
5221                 if (r < 0)
5222                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5223                 else {
5224                         char date[FORMAT_TIMESTAMP_MAX];
5225
5226                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5227                                  format_timestamp(date, sizeof(date), arg_when));
5228                         return 0;
5229                 }
5230         }
5231
5232         if (!arg_dry && !arg_force)
5233                 return start_with_fallback(bus);
5234
5235         if (!arg_no_wtmp) {
5236                 if (sd_booted() > 0)
5237                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5238                 else {
5239                         r = utmp_put_shutdown();
5240                         if (r < 0)
5241                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5242                 }
5243         }
5244
5245         if (arg_dry)
5246                 return 0;
5247
5248         halt_now(arg_action);
5249         /* We should never reach this. */
5250         return -ENOSYS;
5251 }
5252
5253 static int runlevel_main(void) {
5254         int r, runlevel, previous;
5255
5256         r = utmp_get_runlevel(&runlevel, &previous);
5257         if (r < 0) {
5258                 puts("unknown");
5259                 return r;
5260         }
5261
5262         printf("%c %c\n",
5263                previous <= 0 ? 'N' : previous,
5264                runlevel <= 0 ? 'N' : runlevel);
5265
5266         return 0;
5267 }
5268
5269 int main(int argc, char*argv[]) {
5270         int r, retval = EXIT_FAILURE;
5271         DBusConnection *bus = NULL;
5272         DBusError error;
5273
5274         dbus_error_init(&error);
5275
5276         setlocale(LC_ALL, "");
5277         log_parse_environment();
5278         log_open();
5279
5280         r = parse_argv(argc, argv);
5281         if (r < 0)
5282                 goto finish;
5283         else if (r == 0) {
5284                 retval = EXIT_SUCCESS;
5285                 goto finish;
5286         }
5287
5288         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5289          * let's shortcut this */
5290         if (arg_action == ACTION_RUNLEVEL) {
5291                 r = runlevel_main();
5292                 retval = r < 0 ? EXIT_FAILURE : r;
5293                 goto finish;
5294         }
5295
5296         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5297                 log_info("Running in chroot, ignoring request.");
5298                 retval = 0;
5299                 goto finish;
5300         }
5301
5302         if (!avoid_bus()) {
5303                 if (arg_transport == TRANSPORT_NORMAL)
5304                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5305                 else if (arg_transport == TRANSPORT_POLKIT) {
5306                         bus_connect_system_polkit(&bus, &error);
5307                         private_bus = false;
5308                 } else if (arg_transport == TRANSPORT_SSH) {
5309                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5310                         private_bus = false;
5311                 } else
5312                         assert_not_reached("Uh, invalid transport...");
5313         }
5314
5315         switch (arg_action) {
5316
5317         case ACTION_SYSTEMCTL:
5318                 r = systemctl_main(bus, argc, argv, &error);
5319                 break;
5320
5321         case ACTION_HALT:
5322         case ACTION_POWEROFF:
5323         case ACTION_REBOOT:
5324         case ACTION_KEXEC:
5325                 r = halt_main(bus);
5326                 break;
5327
5328         case ACTION_RUNLEVEL2:
5329         case ACTION_RUNLEVEL3:
5330         case ACTION_RUNLEVEL4:
5331         case ACTION_RUNLEVEL5:
5332         case ACTION_RESCUE:
5333         case ACTION_EMERGENCY:
5334         case ACTION_DEFAULT:
5335                 r = start_with_fallback(bus);
5336                 break;
5337
5338         case ACTION_RELOAD:
5339         case ACTION_REEXEC:
5340                 r = reload_with_fallback(bus);
5341                 break;
5342
5343         case ACTION_CANCEL_SHUTDOWN: {
5344                 char *m = NULL;
5345
5346                 if (arg_wall) {
5347                         m = strv_join(arg_wall, " ");
5348                         if (!m) {
5349                                 retval = EXIT_FAILURE;
5350                                 goto finish;
5351                         }
5352                 }
5353                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5354                 if (r < 0)
5355                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5356                 free(m);
5357                 break;
5358         }
5359
5360         case ACTION_INVALID:
5361         case ACTION_RUNLEVEL:
5362         default:
5363                 assert_not_reached("Unknown action");
5364         }
5365
5366         retval = r < 0 ? EXIT_FAILURE : r;
5367
5368 finish:
5369         if (bus) {
5370                 dbus_connection_flush(bus);
5371                 dbus_connection_close(bus);
5372                 dbus_connection_unref(bus);
5373         }
5374
5375         dbus_error_free(&error);
5376
5377         dbus_shutdown();
5378
5379         strv_free(arg_property);
5380
5381         pager_close();
5382         ask_password_agent_close();
5383         polkit_agent_close();
5384
5385         return retval;
5386 }