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