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