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