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