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