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