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