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