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