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