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