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