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