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