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