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