chiark / gitweb /
build-sys: fix built with --disable-logind
[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 start_unit_one(
1504                 DBusConnection *bus,
1505                 const char *method,
1506                 const char *name,
1507                 const char *mode,
1508                 DBusError *error,
1509                 Set *s) {
1510
1511         DBusMessage *m = NULL, *reply = NULL;
1512         const char *path;
1513         int r;
1514
1515         assert(bus);
1516         assert(method);
1517         assert(name);
1518         assert(mode);
1519         assert(error);
1520         assert(arg_no_block || s);
1521
1522         if (!(m = dbus_message_new_method_call(
1523                               "org.freedesktop.systemd1",
1524                               "/org/freedesktop/systemd1",
1525                               "org.freedesktop.systemd1.Manager",
1526                               method))) {
1527                 log_error("Could not allocate message.");
1528                 r = -ENOMEM;
1529                 goto finish;
1530         }
1531
1532         if (!dbus_message_append_args(m,
1533                                       DBUS_TYPE_STRING, &name,
1534                                       DBUS_TYPE_STRING, &mode,
1535                                       DBUS_TYPE_INVALID)) {
1536                 log_error("Could not append arguments to message.");
1537                 r = -ENOMEM;
1538                 goto finish;
1539         }
1540
1541         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1542
1543                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1544                         /* There's always a fallback possible for
1545                          * legacy actions. */
1546                         r = -EADDRNOTAVAIL;
1547                         goto finish;
1548                 }
1549
1550                 log_error("Failed to issue method call: %s", bus_error_message(error));
1551                 r = -EIO;
1552                 goto finish;
1553         }
1554
1555         if (!dbus_message_get_args(reply, error,
1556                                    DBUS_TYPE_OBJECT_PATH, &path,
1557                                    DBUS_TYPE_INVALID)) {
1558                 log_error("Failed to parse reply: %s", bus_error_message(error));
1559                 r = -EIO;
1560                 goto finish;
1561         }
1562
1563         if (need_daemon_reload(bus, name))
1564                 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1565                             arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1566
1567         if (!arg_no_block) {
1568                 char *p;
1569
1570                 if (!(p = strdup(path))) {
1571                         log_error("Failed to duplicate path.");
1572                         r = -ENOMEM;
1573                         goto finish;
1574                 }
1575
1576                 if ((r = set_put(s, p)) < 0) {
1577                         free(p);
1578                         log_error("Failed to add path to set.");
1579                         goto finish;
1580                 }
1581         }
1582
1583         r = 0;
1584
1585 finish:
1586         if (m)
1587                 dbus_message_unref(m);
1588
1589         if (reply)
1590                 dbus_message_unref(reply);
1591
1592         return r;
1593 }
1594
1595 static enum action verb_to_action(const char *verb) {
1596         if (streq(verb, "halt"))
1597                 return ACTION_HALT;
1598         else if (streq(verb, "poweroff"))
1599                 return ACTION_POWEROFF;
1600         else if (streq(verb, "reboot"))
1601                 return ACTION_REBOOT;
1602         else if (streq(verb, "kexec"))
1603                 return ACTION_KEXEC;
1604         else if (streq(verb, "rescue"))
1605                 return ACTION_RESCUE;
1606         else if (streq(verb, "emergency"))
1607                 return ACTION_EMERGENCY;
1608         else if (streq(verb, "default"))
1609                 return ACTION_DEFAULT;
1610         else if (streq(verb, "exit"))
1611                 return ACTION_EXIT;
1612         else if (streq(verb, "suspend"))
1613                 return ACTION_SUSPEND;
1614         else if (streq(verb, "hibernate"))
1615                 return ACTION_HIBERNATE;
1616         else
1617                 return ACTION_INVALID;
1618 }
1619
1620 static int start_unit(DBusConnection *bus, char **args) {
1621
1622         static const char * const table[_ACTION_MAX] = {
1623                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1624                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1625                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1626                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1627                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1628                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1629                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1630                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1631                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1632                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1633                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1634                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1635                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1636                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
1637         };
1638
1639         int r, ret = 0;
1640         const char *method, *mode, *one_name;
1641         Set *s = NULL;
1642         DBusError error;
1643         char **name;
1644
1645         dbus_error_init(&error);
1646
1647         assert(bus);
1648
1649         ask_password_agent_open_if_enabled();
1650
1651         if (arg_action == ACTION_SYSTEMCTL) {
1652                 method =
1653                         streq(args[0], "stop") ||
1654                         streq(args[0], "condstop")              ? "StopUnit" :
1655                         streq(args[0], "reload")                ? "ReloadUnit" :
1656                         streq(args[0], "restart")               ? "RestartUnit" :
1657
1658                         streq(args[0], "try-restart")           ||
1659                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1660
1661                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1662
1663                         streq(args[0], "reload-or-try-restart") ||
1664                         streq(args[0], "condreload") ||
1665
1666                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1667                                                                   "StartUnit";
1668
1669                 mode =
1670                         (streq(args[0], "isolate") ||
1671                          streq(args[0], "rescue")  ||
1672                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1673
1674                 one_name = table[verb_to_action(args[0])];
1675
1676         } else {
1677                 assert(arg_action < ELEMENTSOF(table));
1678                 assert(table[arg_action]);
1679
1680                 method = "StartUnit";
1681
1682                 mode = (arg_action == ACTION_EMERGENCY ||
1683                         arg_action == ACTION_RESCUE ||
1684                         arg_action == ACTION_RUNLEVEL2 ||
1685                         arg_action == ACTION_RUNLEVEL3 ||
1686                         arg_action == ACTION_RUNLEVEL4 ||
1687                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1688
1689                 one_name = table[arg_action];
1690         }
1691
1692         if (!arg_no_block) {
1693                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1694                         log_error("Could not watch jobs: %s", strerror(-ret));
1695                         goto finish;
1696                 }
1697
1698                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1699                         log_error("Failed to allocate set.");
1700                         ret = -ENOMEM;
1701                         goto finish;
1702                 }
1703         }
1704
1705         if (one_name) {
1706                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1707                         goto finish;
1708         } else {
1709                 STRV_FOREACH(name, args+1)
1710                         if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1711                                 ret = translate_bus_error_to_exit_status(r, &error);
1712                                 dbus_error_free(&error);
1713                         }
1714         }
1715
1716         if (!arg_no_block)
1717                 if ((r = wait_for_jobs(bus, s)) < 0) {
1718                         ret = r;
1719                         goto finish;
1720                 }
1721
1722 finish:
1723         if (s)
1724                 set_free_free(s);
1725
1726         dbus_error_free(&error);
1727
1728         return ret;
1729 }
1730
1731 /* Ask systemd-logind, which might grant access to unprivileged users
1732  * through PolicyKit */
1733 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1734 #ifdef HAVE_LOGIND
1735         const char *method;
1736         DBusMessage *m = NULL, *reply = NULL;
1737         DBusError error;
1738         dbus_bool_t interactive = true;
1739         int r;
1740
1741         dbus_error_init(&error);
1742
1743         polkit_agent_open_if_enabled();
1744
1745         switch (a) {
1746
1747         case ACTION_REBOOT:
1748                 method = "Reboot";
1749                 break;
1750
1751         case ACTION_POWEROFF:
1752                 method = "PowerOff";
1753                 break;
1754
1755         case ACTION_SUSPEND:
1756                 method = "Suspend";
1757                 break;
1758
1759         case ACTION_HIBERNATE:
1760                 method = "Hibernate";
1761                 break;
1762
1763         default:
1764                 return -EINVAL;
1765         }
1766
1767         m = dbus_message_new_method_call(
1768                                 "org.freedesktop.login1",
1769                                 "/org/freedesktop/login1",
1770                                 "org.freedesktop.login1.Manager",
1771                                 method);
1772         if (!m) {
1773                 log_error("Could not allocate message.");
1774                 r = -ENOMEM;
1775                 goto finish;
1776         }
1777
1778         if (!dbus_message_append_args(m,
1779                                       DBUS_TYPE_BOOLEAN, &interactive,
1780                                       DBUS_TYPE_INVALID)) {
1781                 log_error("Could not append arguments to message.");
1782                 r = -ENOMEM;
1783                 goto finish;
1784         }
1785
1786         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1787         if (!reply) {
1788                 if (error_is_no_service(&error)) {
1789                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
1790                         r = -ENOENT;
1791                         goto finish;
1792                 }
1793
1794                 if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
1795                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
1796                         r = -EACCES;
1797                         goto finish;
1798                 }
1799
1800                 log_info("Failed to issue method call: %s", bus_error_message(&error));
1801                 r = -EIO;
1802                 goto finish;
1803         }
1804
1805         r = 0;
1806
1807 finish:
1808         if (m)
1809                 dbus_message_unref(m);
1810
1811         if (reply)
1812                 dbus_message_unref(reply);
1813
1814         dbus_error_free(&error);
1815
1816         return r;
1817 #else
1818         return -ENOSYS;
1819 #endif
1820 }
1821
1822 static int start_special(DBusConnection *bus, char **args) {
1823         enum action a;
1824         int r;
1825
1826         assert(args);
1827
1828         a = verb_to_action(args[0]);
1829
1830         if (arg_force >= 2 && geteuid() != 0) {
1831                 log_error("Must be root.");
1832                 return -EPERM;
1833         }
1834
1835         if (arg_force >= 2 &&
1836             (a == ACTION_HALT ||
1837              a == ACTION_POWEROFF ||
1838              a == ACTION_REBOOT))
1839                 halt_now(a);
1840
1841         if (arg_force >= 1 &&
1842             (a == ACTION_HALT ||
1843              a == ACTION_POWEROFF ||
1844              a == ACTION_REBOOT ||
1845              a == ACTION_KEXEC ||
1846              a == ACTION_EXIT))
1847                 return daemon_reload(bus, args);
1848
1849         /* first try logind, to allow authentication with polkit */
1850         if (geteuid() != 0 &&
1851             (a == ACTION_POWEROFF ||
1852              a == ACTION_REBOOT ||
1853              a == ACTION_SUSPEND ||
1854              a == ACTION_HIBERNATE)) {
1855                 r = reboot_with_logind(bus, a);
1856                 if (r >= 0)
1857                         return r;
1858         }
1859
1860         r = start_unit(bus, args);
1861         if (r >= 0)
1862                 warn_wall(a);
1863
1864         return r;
1865 }
1866
1867 static int check_unit(DBusConnection *bus, char **args) {
1868         DBusMessage *m = NULL, *reply = NULL;
1869         const char
1870                 *interface = "org.freedesktop.systemd1.Unit",
1871                 *property = "ActiveState";
1872         int r = 3; /* According to LSB: "program is not running" */
1873         DBusError error;
1874         char **name;
1875
1876         assert(bus);
1877         assert(args);
1878
1879         dbus_error_init(&error);
1880
1881         STRV_FOREACH(name, args+1) {
1882                 const char *path = NULL;
1883                 const char *state;
1884                 DBusMessageIter iter, sub;
1885
1886                 if (!(m = dbus_message_new_method_call(
1887                                       "org.freedesktop.systemd1",
1888                                       "/org/freedesktop/systemd1",
1889                                       "org.freedesktop.systemd1.Manager",
1890                                       "GetUnit"))) {
1891                         log_error("Could not allocate message.");
1892                         r = -ENOMEM;
1893                         goto finish;
1894                 }
1895
1896                 if (!dbus_message_append_args(m,
1897                                               DBUS_TYPE_STRING, name,
1898                                               DBUS_TYPE_INVALID)) {
1899                         log_error("Could not append arguments to message.");
1900                         r = -ENOMEM;
1901                         goto finish;
1902                 }
1903
1904                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1905
1906                         /* Hmm, cannot figure out anything about this unit... */
1907                         if (!arg_quiet)
1908                                 puts("unknown");
1909
1910                         dbus_error_free(&error);
1911                         dbus_message_unref(m);
1912                         m = NULL;
1913                         continue;
1914                 }
1915
1916                 if (!dbus_message_get_args(reply, &error,
1917                                            DBUS_TYPE_OBJECT_PATH, &path,
1918                                            DBUS_TYPE_INVALID)) {
1919                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1920                         r = -EIO;
1921                         goto finish;
1922                 }
1923
1924                 dbus_message_unref(m);
1925                 if (!(m = dbus_message_new_method_call(
1926                                       "org.freedesktop.systemd1",
1927                                       path,
1928                                       "org.freedesktop.DBus.Properties",
1929                                       "Get"))) {
1930                         log_error("Could not allocate message.");
1931                         r = -ENOMEM;
1932                         goto finish;
1933                 }
1934
1935                 if (!dbus_message_append_args(m,
1936                                               DBUS_TYPE_STRING, &interface,
1937                                               DBUS_TYPE_STRING, &property,
1938                                               DBUS_TYPE_INVALID)) {
1939                         log_error("Could not append arguments to message.");
1940                         r = -ENOMEM;
1941                         goto finish;
1942                 }
1943
1944                 dbus_message_unref(reply);
1945                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1946                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1947                         r = -EIO;
1948                         goto finish;
1949                 }
1950
1951                 if (!dbus_message_iter_init(reply, &iter) ||
1952                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1953                         log_error("Failed to parse reply.");
1954                         r = -EIO;
1955                         goto finish;
1956                 }
1957
1958                 dbus_message_iter_recurse(&iter, &sub);
1959
1960                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1961                         log_error("Failed to parse reply.");
1962                         r = -EIO;
1963                         goto finish;
1964                 }
1965
1966                 dbus_message_iter_get_basic(&sub, &state);
1967
1968                 if (!arg_quiet)
1969                         puts(state);
1970
1971                 if (streq(state, "active") || streq(state, "reloading"))
1972                         r = 0;
1973
1974                 dbus_message_unref(m);
1975                 dbus_message_unref(reply);
1976                 m = reply = NULL;
1977         }
1978
1979 finish:
1980         if (m)
1981                 dbus_message_unref(m);
1982
1983         if (reply)
1984                 dbus_message_unref(reply);
1985
1986         dbus_error_free(&error);
1987
1988         return r;
1989 }
1990
1991 static int kill_unit(DBusConnection *bus, char **args) {
1992         DBusMessage *m = NULL;
1993         int r = 0;
1994         DBusError error;
1995         char **name;
1996
1997         assert(bus);
1998         assert(args);
1999
2000         dbus_error_init(&error);
2001
2002         if (!arg_kill_who)
2003                 arg_kill_who = "all";
2004
2005         if (!arg_kill_mode)
2006                 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
2007
2008         STRV_FOREACH(name, args+1) {
2009                 DBusMessage *reply;
2010
2011                 if (!(m = dbus_message_new_method_call(
2012                                       "org.freedesktop.systemd1",
2013                                       "/org/freedesktop/systemd1",
2014                                       "org.freedesktop.systemd1.Manager",
2015                                       "KillUnit"))) {
2016                         log_error("Could not allocate message.");
2017                         r = -ENOMEM;
2018                         goto finish;
2019                 }
2020
2021                 if (!dbus_message_append_args(m,
2022                                               DBUS_TYPE_STRING, name,
2023                                               DBUS_TYPE_STRING, &arg_kill_who,
2024                                               DBUS_TYPE_STRING, &arg_kill_mode,
2025                                               DBUS_TYPE_INT32, &arg_signal,
2026                                               DBUS_TYPE_INVALID)) {
2027                         log_error("Could not append arguments to message.");
2028                         r = -ENOMEM;
2029                         goto finish;
2030                 }
2031
2032                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2033                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2034                         dbus_error_free(&error);
2035                         r = -EIO;
2036                 }
2037
2038                 dbus_message_unref(m);
2039
2040                 if (reply)
2041                         dbus_message_unref(reply);
2042                 m = reply = NULL;
2043         }
2044
2045 finish:
2046         if (m)
2047                 dbus_message_unref(m);
2048
2049         dbus_error_free(&error);
2050
2051         return r;
2052 }
2053
2054 typedef struct ExecStatusInfo {
2055         char *name;
2056
2057         char *path;
2058         char **argv;
2059
2060         bool ignore;
2061
2062         usec_t start_timestamp;
2063         usec_t exit_timestamp;
2064         pid_t pid;
2065         int code;
2066         int status;
2067
2068         LIST_FIELDS(struct ExecStatusInfo, exec);
2069 } ExecStatusInfo;
2070
2071 static void exec_status_info_free(ExecStatusInfo *i) {
2072         assert(i);
2073
2074         free(i->name);
2075         free(i->path);
2076         strv_free(i->argv);
2077         free(i);
2078 }
2079
2080 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2081         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2082         DBusMessageIter sub2, sub3;
2083         const char*path;
2084         unsigned n;
2085         uint32_t pid;
2086         int32_t code, status;
2087         dbus_bool_t ignore;
2088
2089         assert(i);
2090         assert(i);
2091
2092         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2093                 return -EIO;
2094
2095         dbus_message_iter_recurse(sub, &sub2);
2096
2097         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2098                 return -EIO;
2099
2100         if (!(i->path = strdup(path)))
2101                 return -ENOMEM;
2102
2103         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2104             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2105                 return -EIO;
2106
2107         n = 0;
2108         dbus_message_iter_recurse(&sub2, &sub3);
2109         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2110                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2111                 dbus_message_iter_next(&sub3);
2112                 n++;
2113         }
2114
2115
2116         if (!(i->argv = new0(char*, n+1)))
2117                 return -ENOMEM;
2118
2119         n = 0;
2120         dbus_message_iter_recurse(&sub2, &sub3);
2121         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2122                 const char *s;
2123
2124                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2125                 dbus_message_iter_get_basic(&sub3, &s);
2126                 dbus_message_iter_next(&sub3);
2127
2128                 if (!(i->argv[n++] = strdup(s)))
2129                         return -ENOMEM;
2130         }
2131
2132         if (!dbus_message_iter_next(&sub2) ||
2133             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2134             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2135             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2136             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2137             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2138             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2139             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2140             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2141                 return -EIO;
2142
2143         i->ignore = ignore;
2144         i->start_timestamp = (usec_t) start_timestamp;
2145         i->exit_timestamp = (usec_t) exit_timestamp;
2146         i->pid = (pid_t) pid;
2147         i->code = code;
2148         i->status = status;
2149
2150         return 0;
2151 }
2152
2153 typedef struct UnitStatusInfo {
2154         const char *id;
2155         const char *load_state;
2156         const char *active_state;
2157         const char *sub_state;
2158         const char *unit_file_state;
2159
2160         const char *description;
2161         const char *following;
2162
2163         char **documentation;
2164
2165         const char *fragment_path;
2166         const char *source_path;
2167         const char *default_control_group;
2168
2169         const char *load_error;
2170         const char *result;
2171
2172         usec_t inactive_exit_timestamp;
2173         usec_t inactive_exit_timestamp_monotonic;
2174         usec_t active_enter_timestamp;
2175         usec_t active_exit_timestamp;
2176         usec_t inactive_enter_timestamp;
2177
2178         bool need_daemon_reload;
2179
2180         /* Service */
2181         pid_t main_pid;
2182         pid_t control_pid;
2183         const char *status_text;
2184         bool running:1;
2185
2186         usec_t start_timestamp;
2187         usec_t exit_timestamp;
2188
2189         int exit_code, exit_status;
2190
2191         usec_t condition_timestamp;
2192         bool condition_result;
2193
2194         /* Socket */
2195         unsigned n_accepted;
2196         unsigned n_connections;
2197         bool accept;
2198
2199         /* Device */
2200         const char *sysfs_path;
2201
2202         /* Mount, Automount */
2203         const char *where;
2204
2205         /* Swap */
2206         const char *what;
2207
2208         LIST_HEAD(ExecStatusInfo, exec);
2209 } UnitStatusInfo;
2210
2211 static void print_status_info(UnitStatusInfo *i) {
2212         ExecStatusInfo *p;
2213         const char *on, *off, *ss;
2214         usec_t timestamp;
2215         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2216         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2217         const char *path;
2218
2219         assert(i);
2220
2221         /* This shows pretty information about a unit. See
2222          * print_property() for a low-level property printer */
2223
2224         printf("%s", strna(i->id));
2225
2226         if (i->description && !streq_ptr(i->id, i->description))
2227                 printf(" - %s", i->description);
2228
2229         printf("\n");
2230
2231         if (i->following)
2232                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2233
2234         if (streq_ptr(i->load_state, "error")) {
2235                 on = ansi_highlight_red(true);
2236                 off = ansi_highlight_red(false);
2237         } else
2238                 on = off = "";
2239
2240         path = i->source_path ? i->source_path : i->fragment_path;
2241
2242         if (i->load_error)
2243                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2244         else if (path && i->unit_file_state)
2245                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2246         else if (path)
2247                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2248         else
2249                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2250
2251         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2252
2253         if (streq_ptr(i->active_state, "failed")) {
2254                 on = ansi_highlight_red(true);
2255                 off = ansi_highlight_red(false);
2256         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2257                 on = ansi_highlight_green(true);
2258                 off = ansi_highlight_green(false);
2259         } else
2260                 on = off = "";
2261
2262         if (ss)
2263                 printf("\t  Active: %s%s (%s)%s",
2264                        on,
2265                        strna(i->active_state),
2266                        ss,
2267                        off);
2268         else
2269                 printf("\t  Active: %s%s%s",
2270                        on,
2271                        strna(i->active_state),
2272                        off);
2273
2274         if (!isempty(i->result) && !streq(i->result, "success"))
2275                 printf(" (Result: %s)", i->result);
2276
2277         timestamp = (streq_ptr(i->active_state, "active")      ||
2278                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2279                     (streq_ptr(i->active_state, "inactive")    ||
2280                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2281                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2282                                                                   i->active_exit_timestamp;
2283
2284         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2285         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2286
2287         if (s1)
2288                 printf(" since %s; %s\n", s2, s1);
2289         else if (s2)
2290                 printf(" since %s\n", s2);
2291         else
2292                 printf("\n");
2293
2294         if (!i->condition_result && i->condition_timestamp > 0) {
2295                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2296                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2297
2298                 if (s1)
2299                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2300                 else if (s2)
2301                         printf("\t          start condition failed at %s\n", s2);
2302         }
2303
2304         if (i->sysfs_path)
2305                 printf("\t  Device: %s\n", i->sysfs_path);
2306         if (i->where)
2307                 printf("\t   Where: %s\n", i->where);
2308         if (i->what)
2309                 printf("\t    What: %s\n", i->what);
2310
2311         if (!strv_isempty(i->documentation)) {
2312                 char **t;
2313                 bool first = true;
2314
2315                 STRV_FOREACH(t, i->documentation) {
2316                         if (first) {
2317                                 printf("\t    Docs: %s\n", *t);
2318                                 first = false;
2319                         } else
2320                                 printf("\t          %s\n", *t);
2321                 }
2322         }
2323
2324         if (i->accept)
2325                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2326
2327         LIST_FOREACH(exec, p, i->exec) {
2328                 char *t;
2329                 bool good;
2330
2331                 /* Only show exited processes here */
2332                 if (p->code == 0)
2333                         continue;
2334
2335                 t = strv_join(p->argv, " ");
2336                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2337                 free(t);
2338
2339                 good = is_clean_exit_lsb(p->code, p->status);
2340                 if (!good) {
2341                         on = ansi_highlight_red(true);
2342                         off = ansi_highlight_red(false);
2343                 } else
2344                         on = off = "";
2345
2346                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2347
2348                 if (p->code == CLD_EXITED) {
2349                         const char *c;
2350
2351                         printf("status=%i", p->status);
2352
2353                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2354                         if (c)
2355                                 printf("/%s", c);
2356
2357                 } else
2358                         printf("signal=%s", signal_to_string(p->status));
2359
2360                 printf(")%s\n", off);
2361
2362                 if (i->main_pid == p->pid &&
2363                     i->start_timestamp == p->start_timestamp &&
2364                     i->exit_timestamp == p->start_timestamp)
2365                         /* Let's not show this twice */
2366                         i->main_pid = 0;
2367
2368                 if (p->pid == i->control_pid)
2369                         i->control_pid = 0;
2370         }
2371
2372         if (i->main_pid > 0 || i->control_pid > 0) {
2373                 printf("\t");
2374
2375                 if (i->main_pid > 0) {
2376                         printf("Main PID: %u", (unsigned) i->main_pid);
2377
2378                         if (i->running) {
2379                                 char *t = NULL;
2380                                 get_process_comm(i->main_pid, &t);
2381                                 if (t) {
2382                                         printf(" (%s)", t);
2383                                         free(t);
2384                                 }
2385                         } else if (i->exit_code > 0) {
2386                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2387
2388                                 if (i->exit_code == CLD_EXITED) {
2389                                         const char *c;
2390
2391                                         printf("status=%i", i->exit_status);
2392
2393                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2394                                         if (c)
2395                                                 printf("/%s", c);
2396
2397                                 } else
2398                                         printf("signal=%s", signal_to_string(i->exit_status));
2399                                 printf(")");
2400                         }
2401                 }
2402
2403                 if (i->main_pid > 0 && i->control_pid > 0)
2404                         printf(";");
2405
2406                 if (i->control_pid > 0) {
2407                         char *t = NULL;
2408
2409                         printf(" Control: %u", (unsigned) i->control_pid);
2410
2411                         get_process_comm(i->control_pid, &t);
2412                         if (t) {
2413                                 printf(" (%s)", t);
2414                                 free(t);
2415                         }
2416                 }
2417
2418                 printf("\n");
2419         }
2420
2421         if (i->status_text)
2422                 printf("\t  Status: \"%s\"\n", i->status_text);
2423
2424         if (i->default_control_group) {
2425                 unsigned c;
2426
2427                 printf("\t  CGroup: %s\n", i->default_control_group);
2428
2429                 if (arg_transport != TRANSPORT_SSH) {
2430                         unsigned k = 0;
2431                         pid_t extra[2];
2432
2433                         c = columns();
2434                         if (c > 18)
2435                                 c -= 18;
2436                         else
2437                                 c = 0;
2438
2439                         if (i->main_pid > 0)
2440                                 extra[k++] = i->main_pid;
2441
2442                         if (i->control_pid > 0)
2443                                 extra[k++] = i->control_pid;
2444
2445                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2446                 }
2447         }
2448
2449         if (i->id && arg_transport != TRANSPORT_SSH) {
2450                 printf("\n");
2451                 show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
2452         }
2453
2454         if (i->need_daemon_reload)
2455                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2456                        ansi_highlight_red(true),
2457                        ansi_highlight_red(false),
2458                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2459 }
2460
2461 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2462
2463         assert(name);
2464         assert(iter);
2465         assert(i);
2466
2467         switch (dbus_message_iter_get_arg_type(iter)) {
2468
2469         case DBUS_TYPE_STRING: {
2470                 const char *s;
2471
2472                 dbus_message_iter_get_basic(iter, &s);
2473
2474                 if (!isempty(s)) {
2475                         if (streq(name, "Id"))
2476                                 i->id = s;
2477                         else if (streq(name, "LoadState"))
2478                                 i->load_state = s;
2479                         else if (streq(name, "ActiveState"))
2480                                 i->active_state = s;
2481                         else if (streq(name, "SubState"))
2482                                 i->sub_state = s;
2483                         else if (streq(name, "Description"))
2484                                 i->description = s;
2485                         else if (streq(name, "FragmentPath"))
2486                                 i->fragment_path = s;
2487                         else if (streq(name, "SourcePath"))
2488                                 i->source_path = s;
2489                         else if (streq(name, "DefaultControlGroup"))
2490                                 i->default_control_group = s;
2491                         else if (streq(name, "StatusText"))
2492                                 i->status_text = s;
2493                         else if (streq(name, "SysFSPath"))
2494                                 i->sysfs_path = s;
2495                         else if (streq(name, "Where"))
2496                                 i->where = s;
2497                         else if (streq(name, "What"))
2498                                 i->what = s;
2499                         else if (streq(name, "Following"))
2500                                 i->following = s;
2501                         else if (streq(name, "UnitFileState"))
2502                                 i->unit_file_state = s;
2503                         else if (streq(name, "Result"))
2504                                 i->result = s;
2505                 }
2506
2507                 break;
2508         }
2509
2510         case DBUS_TYPE_BOOLEAN: {
2511                 dbus_bool_t b;
2512
2513                 dbus_message_iter_get_basic(iter, &b);
2514
2515                 if (streq(name, "Accept"))
2516                         i->accept = b;
2517                 else if (streq(name, "NeedDaemonReload"))
2518                         i->need_daemon_reload = b;
2519                 else if (streq(name, "ConditionResult"))
2520                         i->condition_result = b;
2521
2522                 break;
2523         }
2524
2525         case DBUS_TYPE_UINT32: {
2526                 uint32_t u;
2527
2528                 dbus_message_iter_get_basic(iter, &u);
2529
2530                 if (streq(name, "MainPID")) {
2531                         if (u > 0) {
2532                                 i->main_pid = (pid_t) u;
2533                                 i->running = true;
2534                         }
2535                 } else if (streq(name, "ControlPID"))
2536                         i->control_pid = (pid_t) u;
2537                 else if (streq(name, "ExecMainPID")) {
2538                         if (u > 0)
2539                                 i->main_pid = (pid_t) u;
2540                 } else if (streq(name, "NAccepted"))
2541                         i->n_accepted = u;
2542                 else if (streq(name, "NConnections"))
2543                         i->n_connections = u;
2544
2545                 break;
2546         }
2547
2548         case DBUS_TYPE_INT32: {
2549                 int32_t j;
2550
2551                 dbus_message_iter_get_basic(iter, &j);
2552
2553                 if (streq(name, "ExecMainCode"))
2554                         i->exit_code = (int) j;
2555                 else if (streq(name, "ExecMainStatus"))
2556                         i->exit_status = (int) j;
2557
2558                 break;
2559         }
2560
2561         case DBUS_TYPE_UINT64: {
2562                 uint64_t u;
2563
2564                 dbus_message_iter_get_basic(iter, &u);
2565
2566                 if (streq(name, "ExecMainStartTimestamp"))
2567                         i->start_timestamp = (usec_t) u;
2568                 else if (streq(name, "ExecMainExitTimestamp"))
2569                         i->exit_timestamp = (usec_t) u;
2570                 else if (streq(name, "ActiveEnterTimestamp"))
2571                         i->active_enter_timestamp = (usec_t) u;
2572                 else if (streq(name, "InactiveEnterTimestamp"))
2573                         i->inactive_enter_timestamp = (usec_t) u;
2574                 else if (streq(name, "InactiveExitTimestamp"))
2575                         i->inactive_exit_timestamp = (usec_t) u;
2576                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2577                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2578                 else if (streq(name, "ActiveExitTimestamp"))
2579                         i->active_exit_timestamp = (usec_t) u;
2580                 else if (streq(name, "ConditionTimestamp"))
2581                         i->condition_timestamp = (usec_t) u;
2582
2583                 break;
2584         }
2585
2586         case DBUS_TYPE_ARRAY: {
2587
2588                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2589                     startswith(name, "Exec")) {
2590                         DBusMessageIter sub;
2591
2592                         dbus_message_iter_recurse(iter, &sub);
2593                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2594                                 ExecStatusInfo *info;
2595                                 int r;
2596
2597                                 if (!(info = new0(ExecStatusInfo, 1)))
2598                                         return -ENOMEM;
2599
2600                                 if (!(info->name = strdup(name))) {
2601                                         free(info);
2602                                         return -ENOMEM;
2603                                 }
2604
2605                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2606                                         free(info);
2607                                         return r;
2608                                 }
2609
2610                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2611
2612                                 dbus_message_iter_next(&sub);
2613                         }
2614                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2615                            streq(name, "Documentation")) {
2616
2617                         DBusMessageIter sub;
2618
2619                         dbus_message_iter_recurse(iter, &sub);
2620                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2621                                 const char *s;
2622                                 char **l;
2623
2624                                 dbus_message_iter_get_basic(&sub, &s);
2625
2626                                 l = strv_append(i->documentation, s);
2627                                 if (!l)
2628                                         return -ENOMEM;
2629
2630                                 strv_free(i->documentation);
2631                                 i->documentation = l;
2632
2633                                 dbus_message_iter_next(&sub);
2634                         }
2635                 }
2636
2637                 break;
2638         }
2639
2640         case DBUS_TYPE_STRUCT: {
2641
2642                 if (streq(name, "LoadError")) {
2643                         DBusMessageIter sub;
2644                         const char *n, *message;
2645                         int r;
2646
2647                         dbus_message_iter_recurse(iter, &sub);
2648
2649                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2650                         if (r < 0)
2651                                 return r;
2652
2653                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2654                         if (r < 0)
2655                                 return r;
2656
2657                         if (!isempty(message))
2658                                 i->load_error = message;
2659                 }
2660
2661                 break;
2662         }
2663         }
2664
2665         return 0;
2666 }
2667
2668 static int print_property(const char *name, DBusMessageIter *iter) {
2669         assert(name);
2670         assert(iter);
2671
2672         /* This is a low-level property printer, see
2673          * print_status_info() for the nicer output */
2674
2675         if (arg_property && !strv_find(arg_property, name))
2676                 return 0;
2677
2678         switch (dbus_message_iter_get_arg_type(iter)) {
2679
2680         case DBUS_TYPE_STRUCT: {
2681                 DBusMessageIter sub;
2682                 dbus_message_iter_recurse(iter, &sub);
2683
2684                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2685                         uint32_t u;
2686
2687                         dbus_message_iter_get_basic(&sub, &u);
2688
2689                         if (u)
2690                                 printf("%s=%u\n", name, (unsigned) u);
2691                         else if (arg_all)
2692                                 printf("%s=\n", name);
2693
2694                         return 0;
2695                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2696                         const char *s;
2697
2698                         dbus_message_iter_get_basic(&sub, &s);
2699
2700                         if (arg_all || s[0])
2701                                 printf("%s=%s\n", name, s);
2702
2703                         return 0;
2704                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2705                         const char *a = NULL, *b = NULL;
2706
2707                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2708                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2709
2710                         if (arg_all || !isempty(a) || !isempty(b))
2711                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2712
2713                         return 0;
2714                 }
2715
2716                 break;
2717         }
2718
2719         case DBUS_TYPE_ARRAY:
2720
2721                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2722                         DBusMessageIter sub, sub2;
2723
2724                         dbus_message_iter_recurse(iter, &sub);
2725                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2726                                 const char *path;
2727                                 dbus_bool_t ignore;
2728
2729                                 dbus_message_iter_recurse(&sub, &sub2);
2730
2731                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2732                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2733                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2734
2735                                 dbus_message_iter_next(&sub);
2736                         }
2737
2738                         return 0;
2739
2740                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2741                         DBusMessageIter sub, sub2;
2742
2743                         dbus_message_iter_recurse(iter, &sub);
2744                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2745                                 const char *type, *path;
2746
2747                                 dbus_message_iter_recurse(&sub, &sub2);
2748
2749                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2750                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2751                                         printf("%s=%s\n", type, path);
2752
2753                                 dbus_message_iter_next(&sub);
2754                         }
2755
2756                         return 0;
2757
2758                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2759                         DBusMessageIter sub, sub2;
2760
2761                         dbus_message_iter_recurse(iter, &sub);
2762                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2763                                 const char *base;
2764                                 uint64_t value, next_elapse;
2765
2766                                 dbus_message_iter_recurse(&sub, &sub2);
2767
2768                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2769                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2770                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2771                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2772
2773                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2774                                                base,
2775                                                format_timespan(timespan1, sizeof(timespan1), value),
2776                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2777                                 }
2778
2779                                 dbus_message_iter_next(&sub);
2780                         }
2781
2782                         return 0;
2783
2784                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2785                         DBusMessageIter sub, sub2;
2786
2787                         dbus_message_iter_recurse(iter, &sub);
2788                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2789                                 const char *controller, *attr, *value;
2790
2791                                 dbus_message_iter_recurse(&sub, &sub2);
2792
2793                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2794                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2795                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2796
2797                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2798                                                controller,
2799                                                attr,
2800                                                value);
2801                                 }
2802
2803                                 dbus_message_iter_next(&sub);
2804                         }
2805
2806                         return 0;
2807
2808                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2809                         DBusMessageIter sub;
2810
2811                         dbus_message_iter_recurse(iter, &sub);
2812                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2813                                 ExecStatusInfo info;
2814
2815                                 zero(info);
2816                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2817                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2818                                         char *t;
2819
2820                                         t = strv_join(info.argv, " ");
2821
2822                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2823                                                name,
2824                                                strna(info.path),
2825                                                strna(t),
2826                                                yes_no(info.ignore),
2827                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2828                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2829                                                (unsigned) info. pid,
2830                                                sigchld_code_to_string(info.code),
2831                                                info.status,
2832                                                info.code == CLD_EXITED ? "" : "/",
2833                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2834
2835                                         free(t);
2836                                 }
2837
2838                                 free(info.path);
2839                                 strv_free(info.argv);
2840
2841                                 dbus_message_iter_next(&sub);
2842                         }
2843
2844                         return 0;
2845                 }
2846
2847                 break;
2848         }
2849
2850         if (generic_print_property(name, iter, arg_all) > 0)
2851                 return 0;
2852
2853         if (arg_all)
2854                 printf("%s=[unprintable]\n", name);
2855
2856         return 0;
2857 }
2858
2859 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2860         DBusMessage *m = NULL, *reply = NULL;
2861         const char *interface = "";
2862         int r;
2863         DBusError error;
2864         DBusMessageIter iter, sub, sub2, sub3;
2865         UnitStatusInfo info;
2866         ExecStatusInfo *p;
2867
2868         assert(bus);
2869         assert(path);
2870         assert(new_line);
2871
2872         zero(info);
2873         dbus_error_init(&error);
2874
2875         if (!(m = dbus_message_new_method_call(
2876                               "org.freedesktop.systemd1",
2877                               path,
2878                               "org.freedesktop.DBus.Properties",
2879                               "GetAll"))) {
2880                 log_error("Could not allocate message.");
2881                 r = -ENOMEM;
2882                 goto finish;
2883         }
2884
2885         if (!dbus_message_append_args(m,
2886                                       DBUS_TYPE_STRING, &interface,
2887                                       DBUS_TYPE_INVALID)) {
2888                 log_error("Could not append arguments to message.");
2889                 r = -ENOMEM;
2890                 goto finish;
2891         }
2892
2893         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2894                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2895                 r = -EIO;
2896                 goto finish;
2897         }
2898
2899         if (!dbus_message_iter_init(reply, &iter) ||
2900             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2901             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2902                 log_error("Failed to parse reply.");
2903                 r = -EIO;
2904                 goto finish;
2905         }
2906
2907         dbus_message_iter_recurse(&iter, &sub);
2908
2909         if (*new_line)
2910                 printf("\n");
2911
2912         *new_line = true;
2913
2914         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2915                 const char *name;
2916
2917                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2918                         log_error("Failed to parse reply.");
2919                         r = -EIO;
2920                         goto finish;
2921                 }
2922
2923                 dbus_message_iter_recurse(&sub, &sub2);
2924
2925                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2926                         log_error("Failed to parse reply.");
2927                         r = -EIO;
2928                         goto finish;
2929                 }
2930
2931                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2932                         log_error("Failed to parse reply.");
2933                         r = -EIO;
2934                         goto finish;
2935                 }
2936
2937                 dbus_message_iter_recurse(&sub2, &sub3);
2938
2939                 if (show_properties)
2940                         r = print_property(name, &sub3);
2941                 else
2942                         r = status_property(name, &sub3, &info);
2943
2944                 if (r < 0) {
2945                         log_error("Failed to parse reply.");
2946                         r = -EIO;
2947                         goto finish;
2948                 }
2949
2950                 dbus_message_iter_next(&sub);
2951         }
2952
2953         r = 0;
2954
2955         if (!show_properties)
2956                 print_status_info(&info);
2957
2958         strv_free(info.documentation);
2959
2960         if (!streq_ptr(info.active_state, "active") &&
2961             !streq_ptr(info.active_state, "reloading") &&
2962             streq(verb, "status"))
2963                 /* According to LSB: "program not running" */
2964                 r = 3;
2965
2966         while ((p = info.exec)) {
2967                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2968                 exec_status_info_free(p);
2969         }
2970
2971 finish:
2972         if (m)
2973                 dbus_message_unref(m);
2974
2975         if (reply)
2976                 dbus_message_unref(reply);
2977
2978         dbus_error_free(&error);
2979
2980         return r;
2981 }
2982
2983 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
2984         DBusMessage *m = NULL, *reply = NULL;
2985         const char *path = NULL;
2986         DBusError error;
2987         int r;
2988
2989         dbus_error_init(&error);
2990
2991         m = dbus_message_new_method_call(
2992                               "org.freedesktop.systemd1",
2993                               "/org/freedesktop/systemd1",
2994                               "org.freedesktop.systemd1.Manager",
2995                               "GetUnitByPID");
2996         if (!m) {
2997                 log_error("Could not allocate message.");
2998                 r = -ENOMEM;
2999                 goto finish;
3000         }
3001
3002         if (!dbus_message_append_args(m,
3003                                       DBUS_TYPE_UINT32, &pid,
3004                                       DBUS_TYPE_INVALID)) {
3005                 log_error("Could not append arguments to message.");
3006                 r = -ENOMEM;
3007                 goto finish;
3008         }
3009
3010         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3011         if (!reply) {
3012                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3013                 r = -EIO;
3014                 goto finish;
3015         }
3016
3017         if (!dbus_message_get_args(reply, &error,
3018                                    DBUS_TYPE_OBJECT_PATH, &path,
3019                                    DBUS_TYPE_INVALID)) {
3020                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3021                 r = -EIO;
3022                 goto finish;
3023         }
3024
3025         r = show_one(verb, bus, path, false, new_line);
3026
3027 finish:
3028         if (m)
3029                 dbus_message_unref(m);
3030
3031         if (reply)
3032                 dbus_message_unref(reply);
3033
3034         dbus_error_free(&error);
3035
3036         return r;
3037 }
3038
3039 static int show(DBusConnection *bus, char **args) {
3040         int r, ret = 0;
3041         bool show_properties, new_line = false;
3042         char **name;
3043
3044         assert(bus);
3045         assert(args);
3046
3047         show_properties = !streq(args[0], "status");
3048
3049         if (show_properties)
3050                 pager_open_if_enabled();
3051
3052         if (show_properties && strv_length(args) <= 1) {
3053                 /* If not argument is specified inspect the manager
3054                  * itself */
3055
3056                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3057         }
3058
3059         STRV_FOREACH(name, args+1) {
3060                 uint32_t id;
3061
3062                 if (safe_atou32(*name, &id) < 0) {
3063
3064                         /* Interpret as unit name */
3065
3066                         char *e, *p;
3067                         e = bus_path_escape(*name);
3068                         if (!e)
3069                                 return -ENOMEM;
3070                         p = strappend("/org/freedesktop/systemd1/unit/", e);
3071                         free(e);
3072                         if (!p)
3073                                 return -ENOMEM;
3074
3075                         r = show_one(args[0], bus, p, show_properties, &new_line);
3076                         free(p);
3077
3078                         if (r != 0)
3079                                 ret = r;
3080
3081                 } else if (show_properties) {
3082
3083                         /* Interpret as job id */
3084
3085                         char *p;
3086                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3087                                 return -ENOMEM;
3088
3089                         r = show_one(args[0], bus, p, show_properties, &new_line);
3090                         free(p);
3091
3092                         if (r != 0)
3093                                 ret = r;
3094
3095                 } else {
3096
3097                         /* Interpret as PID */
3098
3099                         r = show_one_by_pid(args[0], bus, id, &new_line);
3100                         if (r != 0)
3101                                 ret = r;
3102                 }
3103         }
3104
3105         return ret;
3106 }
3107
3108 static int dump(DBusConnection *bus, char **args) {
3109         DBusMessage *m = NULL, *reply = NULL;
3110         DBusError error;
3111         int r;
3112         const char *text;
3113
3114         dbus_error_init(&error);
3115
3116         pager_open_if_enabled();
3117
3118         if (!(m = dbus_message_new_method_call(
3119                               "org.freedesktop.systemd1",
3120                               "/org/freedesktop/systemd1",
3121                               "org.freedesktop.systemd1.Manager",
3122                               "Dump"))) {
3123                 log_error("Could not allocate message.");
3124                 return -ENOMEM;
3125         }
3126
3127         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3128                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3129                 r = -EIO;
3130                 goto finish;
3131         }
3132
3133         if (!dbus_message_get_args(reply, &error,
3134                                    DBUS_TYPE_STRING, &text,
3135                                    DBUS_TYPE_INVALID)) {
3136                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3137                 r = -EIO;
3138                 goto finish;
3139         }
3140
3141         fputs(text, stdout);
3142
3143         r = 0;
3144
3145 finish:
3146         if (m)
3147                 dbus_message_unref(m);
3148
3149         if (reply)
3150                 dbus_message_unref(reply);
3151
3152         dbus_error_free(&error);
3153
3154         return r;
3155 }
3156
3157 static int snapshot(DBusConnection *bus, char **args) {
3158         DBusMessage *m = NULL, *reply = NULL;
3159         DBusError error;
3160         int r;
3161         const char *name = "", *path, *id;
3162         dbus_bool_t cleanup = FALSE;
3163         DBusMessageIter iter, sub;
3164         const char
3165                 *interface = "org.freedesktop.systemd1.Unit",
3166                 *property = "Id";
3167
3168         dbus_error_init(&error);
3169
3170         if (!(m = dbus_message_new_method_call(
3171                               "org.freedesktop.systemd1",
3172                               "/org/freedesktop/systemd1",
3173                               "org.freedesktop.systemd1.Manager",
3174                               "CreateSnapshot"))) {
3175                 log_error("Could not allocate message.");
3176                 return -ENOMEM;
3177         }
3178
3179         if (strv_length(args) > 1)
3180                 name = args[1];
3181
3182         if (!dbus_message_append_args(m,
3183                                       DBUS_TYPE_STRING, &name,
3184                                       DBUS_TYPE_BOOLEAN, &cleanup,
3185                                       DBUS_TYPE_INVALID)) {
3186                 log_error("Could not append arguments to message.");
3187                 r = -ENOMEM;
3188                 goto finish;
3189         }
3190
3191         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3192                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3193                 r = -EIO;
3194                 goto finish;
3195         }
3196
3197         if (!dbus_message_get_args(reply, &error,
3198                                    DBUS_TYPE_OBJECT_PATH, &path,
3199                                    DBUS_TYPE_INVALID)) {
3200                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3201                 r = -EIO;
3202                 goto finish;
3203         }
3204
3205         dbus_message_unref(m);
3206         if (!(m = dbus_message_new_method_call(
3207                               "org.freedesktop.systemd1",
3208                               path,
3209                               "org.freedesktop.DBus.Properties",
3210                               "Get"))) {
3211                 log_error("Could not allocate message.");
3212                 return -ENOMEM;
3213         }
3214
3215         if (!dbus_message_append_args(m,
3216                                       DBUS_TYPE_STRING, &interface,
3217                                       DBUS_TYPE_STRING, &property,
3218                                       DBUS_TYPE_INVALID)) {
3219                 log_error("Could not append arguments to message.");
3220                 r = -ENOMEM;
3221                 goto finish;
3222         }
3223
3224         dbus_message_unref(reply);
3225         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3226                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3227                 r = -EIO;
3228                 goto finish;
3229         }
3230
3231         if (!dbus_message_iter_init(reply, &iter) ||
3232             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3233                 log_error("Failed to parse reply.");
3234                 r = -EIO;
3235                 goto finish;
3236         }
3237
3238         dbus_message_iter_recurse(&iter, &sub);
3239
3240         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3241                 log_error("Failed to parse reply.");
3242                 r = -EIO;
3243                 goto finish;
3244         }
3245
3246         dbus_message_iter_get_basic(&sub, &id);
3247
3248         if (!arg_quiet)
3249                 puts(id);
3250         r = 0;
3251
3252 finish:
3253         if (m)
3254                 dbus_message_unref(m);
3255
3256         if (reply)
3257                 dbus_message_unref(reply);
3258
3259         dbus_error_free(&error);
3260
3261         return r;
3262 }
3263
3264 static int delete_snapshot(DBusConnection *bus, char **args) {
3265         DBusMessage *m = NULL, *reply = NULL;
3266         int r;
3267         DBusError error;
3268         char **name;
3269
3270         assert(bus);
3271         assert(args);
3272
3273         dbus_error_init(&error);
3274
3275         STRV_FOREACH(name, args+1) {
3276                 const char *path = NULL;
3277
3278                 if (!(m = dbus_message_new_method_call(
3279                                       "org.freedesktop.systemd1",
3280                                       "/org/freedesktop/systemd1",
3281                                       "org.freedesktop.systemd1.Manager",
3282                                       "GetUnit"))) {
3283                         log_error("Could not allocate message.");
3284                         r = -ENOMEM;
3285                         goto finish;
3286                 }
3287
3288                 if (!dbus_message_append_args(m,
3289                                               DBUS_TYPE_STRING, name,
3290                                               DBUS_TYPE_INVALID)) {
3291                         log_error("Could not append arguments to message.");
3292                         r = -ENOMEM;
3293                         goto finish;
3294                 }
3295
3296                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3297                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3298                         r = -EIO;
3299                         goto finish;
3300                 }
3301
3302                 if (!dbus_message_get_args(reply, &error,
3303                                            DBUS_TYPE_OBJECT_PATH, &path,
3304                                            DBUS_TYPE_INVALID)) {
3305                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3306                         r = -EIO;
3307                         goto finish;
3308                 }
3309
3310                 dbus_message_unref(m);
3311                 if (!(m = dbus_message_new_method_call(
3312                                       "org.freedesktop.systemd1",
3313                                       path,
3314                                       "org.freedesktop.systemd1.Snapshot",
3315                                       "Remove"))) {
3316                         log_error("Could not allocate message.");
3317                         r = -ENOMEM;
3318                         goto finish;
3319                 }
3320
3321                 dbus_message_unref(reply);
3322                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3323                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3324                         r = -EIO;
3325                         goto finish;
3326                 }
3327
3328                 dbus_message_unref(m);
3329                 dbus_message_unref(reply);
3330                 m = reply = NULL;
3331         }
3332
3333         r = 0;
3334
3335 finish:
3336         if (m)
3337                 dbus_message_unref(m);
3338
3339         if (reply)
3340                 dbus_message_unref(reply);
3341
3342         dbus_error_free(&error);
3343
3344         return r;
3345 }
3346
3347 static int daemon_reload(DBusConnection *bus, char **args) {
3348         DBusMessage *m = NULL, *reply = NULL;
3349         DBusError error;
3350         int r;
3351         const char *method;
3352
3353         dbus_error_init(&error);
3354
3355         if (arg_action == ACTION_RELOAD)
3356                 method = "Reload";
3357         else if (arg_action == ACTION_REEXEC)
3358                 method = "Reexecute";
3359         else {
3360                 assert(arg_action == ACTION_SYSTEMCTL);
3361
3362                 method =
3363                         streq(args[0], "clear-jobs")    ||
3364                         streq(args[0], "cancel")        ? "ClearJobs" :
3365                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3366                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3367                         streq(args[0], "halt")          ? "Halt" :
3368                         streq(args[0], "poweroff")      ? "PowerOff" :
3369                         streq(args[0], "reboot")        ? "Reboot" :
3370                         streq(args[0], "kexec")         ? "KExec" :
3371                         streq(args[0], "exit")          ? "Exit" :
3372                                     /* "daemon-reload" */ "Reload";
3373         }
3374
3375         if (!(m = dbus_message_new_method_call(
3376                               "org.freedesktop.systemd1",
3377                               "/org/freedesktop/systemd1",
3378                               "org.freedesktop.systemd1.Manager",
3379                               method))) {
3380                 log_error("Could not allocate message.");
3381                 return -ENOMEM;
3382         }
3383
3384         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3385
3386                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3387                         /* There's always a fallback possible for
3388                          * legacy actions. */
3389                         r = -EADDRNOTAVAIL;
3390                         goto finish;
3391                 }
3392
3393                 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3394                         /* On reexecution, we expect a disconnect, not
3395                          * a reply */
3396                         r = 0;
3397                         goto finish;
3398                 }
3399
3400                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3401                 r = -EIO;
3402                 goto finish;
3403         }
3404
3405         r = 0;
3406
3407 finish:
3408         if (m)
3409                 dbus_message_unref(m);
3410
3411         if (reply)
3412                 dbus_message_unref(reply);
3413
3414         dbus_error_free(&error);
3415
3416         return r;
3417 }
3418
3419 static int reset_failed(DBusConnection *bus, char **args) {
3420         DBusMessage *m = NULL;
3421         int r;
3422         DBusError error;
3423         char **name;
3424
3425         assert(bus);
3426         dbus_error_init(&error);
3427
3428         if (strv_length(args) <= 1)
3429                 return daemon_reload(bus, args);
3430
3431         STRV_FOREACH(name, args+1) {
3432                 DBusMessage *reply;
3433
3434                 if (!(m = dbus_message_new_method_call(
3435                                       "org.freedesktop.systemd1",
3436                                       "/org/freedesktop/systemd1",
3437                                       "org.freedesktop.systemd1.Manager",
3438                                       "ResetFailedUnit"))) {
3439                         log_error("Could not allocate message.");
3440                         r = -ENOMEM;
3441                         goto finish;
3442                 }
3443
3444                 if (!dbus_message_append_args(m,
3445                                               DBUS_TYPE_STRING, name,
3446                                               DBUS_TYPE_INVALID)) {
3447                         log_error("Could not append arguments to message.");
3448                         r = -ENOMEM;
3449                         goto finish;
3450                 }
3451
3452                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3453                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3454                         r = -EIO;
3455                         goto finish;
3456                 }
3457
3458                 dbus_message_unref(m);
3459                 dbus_message_unref(reply);
3460                 m = reply = NULL;
3461         }
3462
3463         r = 0;
3464
3465 finish:
3466         if (m)
3467                 dbus_message_unref(m);
3468
3469         dbus_error_free(&error);
3470
3471         return r;
3472 }
3473
3474 static int show_enviroment(DBusConnection *bus, char **args) {
3475         DBusMessage *m = NULL, *reply = NULL;
3476         DBusError error;
3477         DBusMessageIter iter, sub, sub2;
3478         int r;
3479         const char
3480                 *interface = "org.freedesktop.systemd1.Manager",
3481                 *property = "Environment";
3482
3483         dbus_error_init(&error);
3484
3485         pager_open_if_enabled();
3486
3487         if (!(m = dbus_message_new_method_call(
3488                               "org.freedesktop.systemd1",
3489                               "/org/freedesktop/systemd1",
3490                               "org.freedesktop.DBus.Properties",
3491                               "Get"))) {
3492                 log_error("Could not allocate message.");
3493                 return -ENOMEM;
3494         }
3495
3496         if (!dbus_message_append_args(m,
3497                                       DBUS_TYPE_STRING, &interface,
3498                                       DBUS_TYPE_STRING, &property,
3499                                       DBUS_TYPE_INVALID)) {
3500                 log_error("Could not append arguments to message.");
3501                 r = -ENOMEM;
3502                 goto finish;
3503         }
3504
3505         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3506                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3507                 r = -EIO;
3508                 goto finish;
3509         }
3510
3511         if (!dbus_message_iter_init(reply, &iter) ||
3512             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3513                 log_error("Failed to parse reply.");
3514                 r = -EIO;
3515                 goto finish;
3516         }
3517
3518         dbus_message_iter_recurse(&iter, &sub);
3519
3520         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3521             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3522                 log_error("Failed to parse reply.");
3523                 r = -EIO;
3524                 goto finish;
3525         }
3526
3527         dbus_message_iter_recurse(&sub, &sub2);
3528
3529         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3530                 const char *text;
3531
3532                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3533                         log_error("Failed to parse reply.");
3534                         r = -EIO;
3535                         goto finish;
3536                 }
3537
3538                 dbus_message_iter_get_basic(&sub2, &text);
3539                 printf("%s\n", text);
3540
3541                 dbus_message_iter_next(&sub2);
3542         }
3543
3544         r = 0;
3545
3546 finish:
3547         if (m)
3548                 dbus_message_unref(m);
3549
3550         if (reply)
3551                 dbus_message_unref(reply);
3552
3553         dbus_error_free(&error);
3554
3555         return r;
3556 }
3557
3558 static int switch_root(DBusConnection *bus, char **args) {
3559         DBusMessage *m = NULL, *reply = NULL;
3560         unsigned l;
3561         const char *root, *init;
3562         DBusError error;
3563         int r;
3564
3565         dbus_error_init(&error);
3566
3567         l = strv_length(args);
3568         if (l < 2 || l > 3) {
3569                 log_error("Wrong number of arguments.");
3570                 return -EINVAL;
3571         }
3572
3573         root = args[1];
3574         init = l >= 3 ? args[2] : "";
3575
3576         m = dbus_message_new_method_call(
3577                         "org.freedesktop.systemd1",
3578                         "/org/freedesktop/systemd1",
3579                         "org.freedesktop.systemd1.Manager",
3580                         "SwitchRoot");
3581         if (!m) {
3582                 log_error("Could not allocate message.");
3583                 return -ENOMEM;
3584         }
3585
3586         if (!dbus_message_append_args(
3587                             m,
3588                             DBUS_TYPE_STRING, &root,
3589                             DBUS_TYPE_STRING, &init,
3590                             DBUS_TYPE_INVALID)) {
3591                 log_error("Could not append arguments to message.");
3592                 r = -ENOMEM;
3593                 goto finish;
3594         }
3595
3596         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3597         if (!reply) {
3598                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3599                 r = -EIO;
3600                 goto finish;
3601         }
3602
3603         r = 0;
3604
3605 finish:
3606         if (m)
3607                 dbus_message_unref(m);
3608
3609         if (reply)
3610                 dbus_message_unref(reply);
3611
3612         dbus_error_free(&error);
3613
3614         return r;
3615 }
3616
3617 static int set_environment(DBusConnection *bus, char **args) {
3618         DBusMessage *m = NULL, *reply = NULL;
3619         DBusError error;
3620         int r;
3621         const char *method;
3622         DBusMessageIter iter, sub;
3623         char **name;
3624
3625         dbus_error_init(&error);
3626
3627         method = streq(args[0], "set-environment")
3628                 ? "SetEnvironment"
3629                 : "UnsetEnvironment";
3630
3631         if (!(m = dbus_message_new_method_call(
3632                               "org.freedesktop.systemd1",
3633                               "/org/freedesktop/systemd1",
3634                               "org.freedesktop.systemd1.Manager",
3635                               method))) {
3636
3637                 log_error("Could not allocate message.");
3638                 return -ENOMEM;
3639         }
3640
3641         dbus_message_iter_init_append(m, &iter);
3642
3643         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3644                 log_error("Could not append arguments to message.");
3645                 r = -ENOMEM;
3646                 goto finish;
3647         }
3648
3649         STRV_FOREACH(name, args+1)
3650                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3651                         log_error("Could not append arguments to message.");
3652                         r = -ENOMEM;
3653                         goto finish;
3654                 }
3655
3656         if (!dbus_message_iter_close_container(&iter, &sub)) {
3657                 log_error("Could not append arguments to message.");
3658                 r = -ENOMEM;
3659                 goto finish;
3660         }
3661
3662         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3663                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3664                 r = -EIO;
3665                 goto finish;
3666         }
3667
3668         r = 0;
3669
3670 finish:
3671         if (m)
3672                 dbus_message_unref(m);
3673
3674         if (reply)
3675                 dbus_message_unref(reply);
3676
3677         dbus_error_free(&error);
3678
3679         return r;
3680 }
3681
3682 static int enable_sysv_units(char **args) {
3683         int r = 0;
3684
3685 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3686         const char *verb = args[0];
3687         unsigned f = 1, t = 1;
3688         LookupPaths paths;
3689
3690         if (arg_scope != UNIT_FILE_SYSTEM)
3691                 return 0;
3692
3693         if (!streq(verb, "enable") &&
3694             !streq(verb, "disable") &&
3695             !streq(verb, "is-enabled"))
3696                 return 0;
3697
3698         /* Processes all SysV units, and reshuffles the array so that
3699          * afterwards only the native units remain */
3700
3701         zero(paths);
3702         r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
3703         if (r < 0)
3704                 return r;
3705
3706         r = 0;
3707         for (f = 1; args[f]; f++) {
3708                 const char *name;
3709                 char *p;
3710                 bool found_native = false, found_sysv;
3711                 unsigned c = 1;
3712                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3713                 char **k, *l, *q = NULL;
3714                 int j;
3715                 pid_t pid;
3716                 siginfo_t status;
3717
3718                 name = args[f];
3719
3720                 if (!endswith(name, ".service"))
3721                         continue;
3722
3723                 if (path_is_absolute(name))
3724                         continue;
3725
3726                 STRV_FOREACH(k, paths.unit_path) {
3727                         p = NULL;
3728
3729                         if (!isempty(arg_root))
3730                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3731                         else
3732                                 asprintf(&p, "%s/%s", *k, name);
3733
3734                         if (!p) {
3735                                 log_error("No memory");
3736                                 r = -ENOMEM;
3737                                 goto finish;
3738                         }
3739
3740                         found_native = access(p, F_OK) >= 0;
3741                         free(p);
3742
3743                         if (found_native)
3744                                 break;
3745                 }
3746
3747                 if (found_native)
3748                         continue;
3749
3750                 p = NULL;
3751                 if (!isempty(arg_root))
3752                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3753                 else
3754                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3755                 if (!p) {
3756                         log_error("No memory");
3757                         r = -ENOMEM;
3758                         goto finish;
3759                 }
3760
3761                 p[strlen(p) - sizeof(".service") + 1] = 0;
3762                 found_sysv = access(p, F_OK) >= 0;
3763
3764                 if (!found_sysv) {
3765                         free(p);
3766                         continue;
3767                 }
3768
3769                 /* Mark this entry, so that we don't try enabling it as native unit */
3770                 args[f] = (char*) "";
3771
3772                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3773
3774                 if (!isempty(arg_root))
3775                         argv[c++] = q = strappend("--root=", arg_root);
3776
3777                 argv[c++] = path_get_file_name(p);
3778                 argv[c++] =
3779                         streq(verb, "enable") ? "on" :
3780                         streq(verb, "disable") ? "off" : "--level=5";
3781                 argv[c] = NULL;
3782
3783                 l = strv_join((char**)argv, " ");
3784                 if (!l) {
3785                         log_error("No memory.");
3786                         free(q);
3787                         free(p);
3788                         r = -ENOMEM;
3789                         goto finish;
3790                 }
3791
3792                 log_info("Executing %s", l);
3793                 free(l);
3794
3795                 pid = fork();
3796                 if (pid < 0) {
3797                         log_error("Failed to fork: %m");
3798                         free(p);
3799                         free(q);
3800                         r = -errno;
3801                         goto finish;
3802                 } else if (pid == 0) {
3803                         /* Child */
3804
3805                         execv(argv[0], (char**) argv);
3806                         _exit(EXIT_FAILURE);
3807                 }
3808
3809                 free(p);
3810                 free(q);
3811
3812                 j = wait_for_terminate(pid, &status);
3813                 if (j < 0) {
3814                         log_error("Failed to wait for child: %s", strerror(-r));
3815                         r = j;
3816                         goto finish;
3817                 }
3818
3819                 if (status.si_code == CLD_EXITED) {
3820                         if (streq(verb, "is-enabled")) {
3821                                 if (status.si_status == 0) {
3822                                         if (!arg_quiet)
3823                                                 puts("enabled");
3824                                         r = 1;
3825                                 } else {
3826                                         if (!arg_quiet)
3827                                                 puts("disabled");
3828                                 }
3829
3830                         } else if (status.si_status != 0) {
3831                                 r = -EINVAL;
3832                                 goto finish;
3833                         }
3834                 } else {
3835                         r = -EPROTO;
3836                         goto finish;
3837                 }
3838         }
3839
3840 finish:
3841         lookup_paths_free(&paths);
3842
3843         /* Drop all SysV units */
3844         for (f = 1, t = 1; args[f]; f++) {
3845
3846                 if (isempty(args[f]))
3847                         continue;
3848
3849                 args[t++] = args[f];
3850         }
3851
3852         args[t] = NULL;
3853
3854 #endif
3855         return r;
3856 }
3857
3858 static int enable_unit(DBusConnection *bus, char **args) {
3859         const char *verb = args[0];
3860         UnitFileChange *changes = NULL;
3861         unsigned n_changes = 0, i;
3862         int carries_install_info = -1;
3863         DBusMessage *m = NULL, *reply = NULL;
3864         int r;
3865         DBusError error;
3866
3867         r = enable_sysv_units(args);
3868         if (r < 0)
3869                 return r;
3870
3871         if (!args[1])
3872                 return 0;
3873
3874         dbus_error_init(&error);
3875
3876         if (!bus || avoid_bus()) {
3877                 if (streq(verb, "enable")) {
3878                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3879                         carries_install_info = r;
3880                 } else if (streq(verb, "disable"))
3881                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3882                 else if (streq(verb, "reenable")) {
3883                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3884                         carries_install_info = r;
3885                 } else if (streq(verb, "link"))
3886                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3887                 else if (streq(verb, "preset")) {
3888                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3889                         carries_install_info = r;
3890                 } else if (streq(verb, "mask"))
3891                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3892                 else if (streq(verb, "unmask"))
3893                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3894                 else
3895                         assert_not_reached("Unknown verb");
3896
3897                 if (r < 0) {
3898                         log_error("Operation failed: %s", strerror(-r));
3899                         goto finish;
3900                 }
3901
3902                 if (!arg_quiet) {
3903                         for (i = 0; i < n_changes; i++) {
3904                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3905                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3906                                 else
3907                                         log_info("rm '%s'", changes[i].path);
3908                         }
3909                 }
3910
3911         } else {
3912                 const char *method;
3913                 bool send_force = true, expect_carries_install_info = false;
3914                 dbus_bool_t a, b;
3915                 DBusMessageIter iter, sub, sub2;
3916
3917                 if (streq(verb, "enable")) {
3918                         method = "EnableUnitFiles";
3919                         expect_carries_install_info = true;
3920                 } else if (streq(verb, "disable")) {
3921                         method = "DisableUnitFiles";
3922                         send_force = false;
3923                 } else if (streq(verb, "reenable")) {
3924                         method = "ReenableUnitFiles";
3925                         expect_carries_install_info = true;
3926                 } else if (streq(verb, "link"))
3927                         method = "LinkUnitFiles";
3928                 else if (streq(verb, "preset")) {
3929                         method = "PresetUnitFiles";
3930                         expect_carries_install_info = true;
3931                 } else if (streq(verb, "mask"))
3932                         method = "MaskUnitFiles";
3933                 else if (streq(verb, "unmask")) {
3934                         method = "UnmaskUnitFiles";
3935                         send_force = false;
3936                 } else
3937                         assert_not_reached("Unknown verb");
3938
3939                 m = dbus_message_new_method_call(
3940                                 "org.freedesktop.systemd1",
3941                                 "/org/freedesktop/systemd1",
3942                                 "org.freedesktop.systemd1.Manager",
3943                                 method);
3944                 if (!m) {
3945                         log_error("Out of memory");
3946                         r = -ENOMEM;
3947                         goto finish;
3948                 }
3949
3950                 dbus_message_iter_init_append(m, &iter);
3951
3952                 r = bus_append_strv_iter(&iter, args+1);
3953                 if (r < 0) {
3954                         log_error("Failed to append unit files.");
3955                         goto finish;
3956                 }
3957
3958                 a = arg_runtime;
3959                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3960                         log_error("Failed to append runtime boolean.");
3961                         r = -ENOMEM;
3962                         goto finish;
3963                 }
3964
3965                 if (send_force) {
3966                         b = arg_force;
3967
3968                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3969                                 log_error("Failed to append force boolean.");
3970                                 r = -ENOMEM;
3971                                 goto finish;
3972                         }
3973                 }
3974
3975                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3976                 if (!reply) {
3977                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3978                         r = -EIO;
3979                         goto finish;
3980                 }
3981
3982                 if (!dbus_message_iter_init(reply, &iter)) {
3983                         log_error("Failed to initialize iterator.");
3984                         goto finish;
3985                 }
3986
3987                 if (expect_carries_install_info) {
3988                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3989                         if (r < 0) {
3990                                 log_error("Failed to parse reply.");
3991                                 goto finish;
3992                         }
3993
3994                         carries_install_info = b;
3995                 }
3996
3997                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3998                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3999                         log_error("Failed to parse reply.");
4000                         r = -EIO;
4001                         goto finish;
4002                 }
4003
4004                 dbus_message_iter_recurse(&iter, &sub);
4005                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4006                         const char *type, *path, *source;
4007
4008                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4009                                 log_error("Failed to parse reply.");
4010                                 r = -EIO;
4011                                 goto finish;
4012                         }
4013
4014                         dbus_message_iter_recurse(&sub, &sub2);
4015
4016                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4017                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4018                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4019                                 log_error("Failed to parse reply.");
4020                                 r = -EIO;
4021                                 goto finish;
4022                         }
4023
4024                         if (!arg_quiet) {
4025                                 if (streq(type, "symlink"))
4026                                         log_info("ln -s '%s' '%s'", source, path);
4027                                 else
4028                                         log_info("rm '%s'", path);
4029                         }
4030
4031                         dbus_message_iter_next(&sub);
4032                 }
4033
4034                 /* Try to reload if enabeld */
4035                 if (!arg_no_reload)
4036                         r = daemon_reload(bus, args);
4037         }
4038
4039         if (carries_install_info == 0)
4040                 log_warning("Warning: unit files do not carry install information. No operation executed.");
4041
4042 finish:
4043         if (m)
4044                 dbus_message_unref(m);
4045
4046         if (reply)
4047                 dbus_message_unref(reply);
4048
4049         unit_file_changes_free(changes, n_changes);
4050
4051         dbus_error_free(&error);
4052         return r;
4053 }
4054
4055 static int unit_is_enabled(DBusConnection *bus, char **args) {
4056         DBusError error;
4057         int r;
4058         DBusMessage *m = NULL, *reply = NULL;
4059         bool enabled;
4060         char **name;
4061
4062         dbus_error_init(&error);
4063
4064         r = enable_sysv_units(args);
4065         if (r < 0)
4066                 return r;
4067
4068         enabled = r > 0;
4069
4070         if (!bus || avoid_bus()) {
4071
4072                 STRV_FOREACH(name, args+1) {
4073                         UnitFileState state;
4074
4075                         state = unit_file_get_state(arg_scope, arg_root, *name);
4076                         if (state < 0) {
4077                                 r = state;
4078                                 goto finish;
4079                         }
4080
4081                         if (state == UNIT_FILE_ENABLED ||
4082                             state == UNIT_FILE_ENABLED_RUNTIME ||
4083                             state == UNIT_FILE_STATIC)
4084                                 enabled = true;
4085
4086                         if (!arg_quiet)
4087                                 puts(unit_file_state_to_string(state));
4088                 }
4089
4090         } else {
4091                 STRV_FOREACH(name, args+1) {
4092                         const char *s;
4093
4094                         m = dbus_message_new_method_call(
4095                                         "org.freedesktop.systemd1",
4096                                         "/org/freedesktop/systemd1",
4097                                         "org.freedesktop.systemd1.Manager",
4098                                         "GetUnitFileState");
4099                         if (!m) {
4100                                 log_error("Out of memory");
4101                                 r = -ENOMEM;
4102                                 goto finish;
4103                         }
4104
4105                         if (!dbus_message_append_args(m,
4106                                                       DBUS_TYPE_STRING, name,
4107                                                       DBUS_TYPE_INVALID)) {
4108                                 log_error("Could not append arguments to message.");
4109                                 r = -ENOMEM;
4110                                 goto finish;
4111                         }
4112
4113                         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4114                         if (!reply) {
4115                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4116                                 r = -EIO;
4117                                 goto finish;
4118                         }
4119
4120                         if (!dbus_message_get_args(reply, &error,
4121                                                    DBUS_TYPE_STRING, &s,
4122                                                    DBUS_TYPE_INVALID)) {
4123                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4124                                 r = -EIO;
4125                                 goto finish;
4126                         }
4127
4128                         dbus_message_unref(m);
4129                         dbus_message_unref(reply);
4130                         m = reply = NULL;
4131
4132                         if (streq(s, "enabled") ||
4133                             streq(s, "enabled-runtime") ||
4134                             streq(s, "static"))
4135                                 enabled = true;
4136
4137                         if (!arg_quiet)
4138                                 puts(s);
4139                 }
4140         }
4141
4142         r = enabled ? 0 : 1;
4143
4144 finish:
4145         if (m)
4146                 dbus_message_unref(m);
4147
4148         if (reply)
4149                 dbus_message_unref(reply);
4150
4151         dbus_error_free(&error);
4152         return r;
4153 }
4154
4155 static int systemctl_help(void) {
4156
4157         pager_open_if_enabled();
4158
4159         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4160                "Query or send control commands to the systemd manager.\n\n"
4161                "  -h --help           Show this help\n"
4162                "     --version        Show package version\n"
4163                "  -t --type=TYPE      List only units of a particular type\n"
4164                "  -p --property=NAME  Show only properties by this name\n"
4165                "  -a --all            Show all units/properties, including dead/empty ones\n"
4166                "     --failed         Show only failed units\n"
4167                "     --full           Don't ellipsize unit names on output\n"
4168                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4169                "                      pending\n"
4170                "     --ignore-dependencies\n"
4171                "                      When queueing a new job, ignore all its dependencies\n"
4172                "     --kill-who=WHO   Who to send signal to\n"
4173                "  -s --signal=SIGNAL  Which signal to send\n"
4174                "  -H --host=[USER@]HOST\n"
4175                "                      Show information for remote host\n"
4176                "  -P --privileged     Acquire privileges before execution\n"
4177                "  -q --quiet          Suppress output\n"
4178                "     --no-block       Do not wait until operation finished\n"
4179                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4180                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4181                "                      configuration\n"
4182                "     --no-legend      Do not print a legend (column headers and hints)\n"
4183                "     --no-pager       Do not pipe output into a pager\n"
4184                "     --no-ask-password\n"
4185                "                      Do not ask for system passwords\n"
4186                "     --order          When generating graph for dot, show only order\n"
4187                "     --require        When generating graph for dot, show only requirement\n"
4188                "     --system         Connect to system manager\n"
4189                "     --user           Connect to user service manager\n"
4190                "     --global         Enable/disable unit files globally\n"
4191                "  -f --force          When enabling unit files, override existing symlinks\n"
4192                "                      When shutting down, execute action immediately\n"
4193                "     --root=PATH      Enable unit files in the specified root directory\n"
4194                "     --runtime        Enable unit files only temporarily until next reboot\n"
4195                "  -n --lines=INTEGER  Journal entries to show\n"
4196                "     --follow         Follow journal\n"
4197                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4198                "                      verbose, export, json, cat)\n\n"
4199                "Unit Commands:\n"
4200                "  list-units                      List loaded units\n"
4201                "  start [NAME...]                 Start (activate) one or more units\n"
4202                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4203                "  reload [NAME...]                Reload one or more units\n"
4204                "  restart [NAME...]               Start or restart one or more units\n"
4205                "  try-restart [NAME...]           Restart one or more units if active\n"
4206                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
4207                "                                  otherwise start or restart\n"
4208                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4209                "                                  otherwise restart if active\n"
4210                "  isolate [NAME]                  Start one unit and stop all others\n"
4211                "  kill [NAME...]                  Send signal to processes of a unit\n"
4212                "  is-active [NAME...]             Check whether units are active\n"
4213                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4214                "  show [NAME...|JOB...]           Show properties of one or more\n"
4215                "                                  units/jobs or the manager\n"
4216                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4217                "                                  units\n"
4218                "  load [NAME...]                  Load one or more units\n\n"
4219                "Unit File Commands:\n"
4220                "  list-unit-files                 List installed unit files\n"
4221                "  enable [NAME...]                Enable one or more unit files\n"
4222                "  disable [NAME...]               Disable one or more unit files\n"
4223                "  reenable [NAME...]              Reenable one or more unit files\n"
4224                "  preset [NAME...]                Enable/disable one or more unit files\n"
4225                "                                  based on preset configuration\n"
4226                "  mask [NAME...]                  Mask one or more units\n"
4227                "  unmask [NAME...]                Unmask one or more units\n"
4228                "  link [PATH...]                  Link one or more units files into\n"
4229                "                                  the search path\n"
4230                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4231                "Job Commands:\n"
4232                "  list-jobs                       List jobs\n"
4233                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4234                "Status Commands:\n"
4235                "  dump                            Dump server status\n"
4236                "  dot                             Dump dependency graph for dot(1)\n\n"
4237                "Snapshot Commands:\n"
4238                "  snapshot [NAME]                 Create a snapshot\n"
4239                "  delete [NAME...]                Remove one or more snapshots\n\n"
4240                "Environment Commands:\n"
4241                "  show-environment                Dump environment\n"
4242                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4243                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4244                "Manager Lifecycle Commands:\n"
4245                "  daemon-reload                   Reload systemd manager configuration\n"
4246                "  daemon-reexec                   Reexecute systemd manager\n\n"
4247                "System Commands:\n"
4248                "  default                         Enter system default mode\n"
4249                "  rescue                          Enter system rescue mode\n"
4250                "  emergency                       Enter system emergency mode\n"
4251                "  halt                            Shut down and halt the system\n"
4252                "  poweroff                        Shut down and power-off the system\n"
4253                "  reboot                          Shut down and reboot the system\n"
4254                "  kexec                           Shut down and reboot the system with kexec\n"
4255                "  exit                            Request user instance exit\n"
4256                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4257                "  suspend                         Suspend the system\n"
4258                "  hibernate                       Hibernate the system\n",
4259                program_invocation_short_name);
4260
4261         return 0;
4262 }
4263
4264 static int halt_help(void) {
4265
4266         printf("%s [OPTIONS...]\n\n"
4267                "%s the system.\n\n"
4268                "     --help      Show this help\n"
4269                "     --halt      Halt the machine\n"
4270                "  -p --poweroff  Switch off the machine\n"
4271                "     --reboot    Reboot the machine\n"
4272                "  -f --force     Force immediate halt/power-off/reboot\n"
4273                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4274                "  -d --no-wtmp   Don't write wtmp record\n"
4275                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
4276                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4277                program_invocation_short_name,
4278                arg_action == ACTION_REBOOT   ? "Reboot" :
4279                arg_action == ACTION_POWEROFF ? "Power off" :
4280                                                "Halt");
4281
4282         return 0;
4283 }
4284
4285 static int shutdown_help(void) {
4286
4287         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4288                "Shut down the system.\n\n"
4289                "     --help      Show this help\n"
4290                "  -H --halt      Halt the machine\n"
4291                "  -P --poweroff  Power-off the machine\n"
4292                "  -r --reboot    Reboot the machine\n"
4293                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4294                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4295                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4296                "  -c             Cancel a pending shutdown\n",
4297                program_invocation_short_name);
4298
4299         return 0;
4300 }
4301
4302 static int telinit_help(void) {
4303
4304         printf("%s [OPTIONS...] {COMMAND}\n\n"
4305                "Send control commands to the init daemon.\n\n"
4306                "     --help      Show this help\n"
4307                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4308                "Commands:\n"
4309                "  0              Power-off the machine\n"
4310                "  6              Reboot the machine\n"
4311                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4312                "  1, s, S        Enter rescue mode\n"
4313                "  q, Q           Reload init daemon configuration\n"
4314                "  u, U           Reexecute init daemon\n",
4315                program_invocation_short_name);
4316
4317         return 0;
4318 }
4319
4320 static int runlevel_help(void) {
4321
4322         printf("%s [OPTIONS...]\n\n"
4323                "Prints the previous and current runlevel of the init system.\n\n"
4324                "     --help      Show this help\n",
4325                program_invocation_short_name);
4326
4327         return 0;
4328 }
4329
4330 static int systemctl_parse_argv(int argc, char *argv[]) {
4331
4332         enum {
4333                 ARG_FAIL = 0x100,
4334                 ARG_IGNORE_DEPENDENCIES,
4335                 ARG_VERSION,
4336                 ARG_USER,
4337                 ARG_SYSTEM,
4338                 ARG_GLOBAL,
4339                 ARG_NO_BLOCK,
4340                 ARG_NO_LEGEND,
4341                 ARG_NO_PAGER,
4342                 ARG_NO_WALL,
4343                 ARG_ORDER,
4344                 ARG_REQUIRE,
4345                 ARG_ROOT,
4346                 ARG_FULL,
4347                 ARG_NO_RELOAD,
4348                 ARG_KILL_MODE,
4349                 ARG_KILL_WHO,
4350                 ARG_NO_ASK_PASSWORD,
4351                 ARG_FAILED,
4352                 ARG_RUNTIME,
4353                 ARG_FOLLOW,
4354                 ARG_FORCE
4355         };
4356
4357         static const struct option options[] = {
4358                 { "help",      no_argument,       NULL, 'h'           },
4359                 { "version",   no_argument,       NULL, ARG_VERSION   },
4360                 { "type",      required_argument, NULL, 't'           },
4361                 { "property",  required_argument, NULL, 'p'           },
4362                 { "all",       no_argument,       NULL, 'a'           },
4363                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4364                 { "full",      no_argument,       NULL, ARG_FULL      },
4365                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4366                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4367                 { "user",      no_argument,       NULL, ARG_USER      },
4368                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4369                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4370                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4371                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4372                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4373                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4374                 { "quiet",     no_argument,       NULL, 'q'           },
4375                 { "order",     no_argument,       NULL, ARG_ORDER     },
4376                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4377                 { "root",      required_argument, NULL, ARG_ROOT      },
4378                 { "force",     no_argument,       NULL, ARG_FORCE     },
4379                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4380                 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
4381                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4382                 { "signal",    required_argument, NULL, 's'           },
4383                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4384                 { "host",      required_argument, NULL, 'H'           },
4385                 { "privileged",no_argument,       NULL, 'P'           },
4386                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4387                 { "lines",     required_argument, NULL, 'n'           },
4388                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4389                 { "output",    required_argument, NULL, 'o'           },
4390                 { NULL,        0,                 NULL, 0             }
4391         };
4392
4393         int c;
4394
4395         assert(argc >= 0);
4396         assert(argv);
4397
4398         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4399
4400                 switch (c) {
4401
4402                 case 'h':
4403                         systemctl_help();
4404                         return 0;
4405
4406                 case ARG_VERSION:
4407                         puts(PACKAGE_STRING);
4408                         puts(DISTRIBUTION);
4409                         puts(SYSTEMD_FEATURES);
4410                         return 0;
4411
4412                 case 't':
4413                         arg_type = optarg;
4414                         break;
4415
4416                 case 'p': {
4417                         char **l;
4418
4419                         if (!(l = strv_append(arg_property, optarg)))
4420                                 return -ENOMEM;
4421
4422                         strv_free(arg_property);
4423                         arg_property = l;
4424
4425                         /* If the user asked for a particular
4426                          * property, show it to him, even if it is
4427                          * empty. */
4428                         arg_all = true;
4429                         break;
4430                 }
4431
4432                 case 'a':
4433                         arg_all = true;
4434                         break;
4435
4436                 case ARG_FAIL:
4437                         arg_job_mode = "fail";
4438                         break;
4439
4440                 case ARG_IGNORE_DEPENDENCIES:
4441                         arg_job_mode = "ignore-dependencies";
4442                         break;
4443
4444                 case ARG_USER:
4445                         arg_scope = UNIT_FILE_USER;
4446                         break;
4447
4448                 case ARG_SYSTEM:
4449                         arg_scope = UNIT_FILE_SYSTEM;
4450                         break;
4451
4452                 case ARG_GLOBAL:
4453                         arg_scope = UNIT_FILE_GLOBAL;
4454                         break;
4455
4456                 case ARG_NO_BLOCK:
4457                         arg_no_block = true;
4458                         break;
4459
4460                 case ARG_NO_LEGEND:
4461                         arg_no_legend = true;
4462                         break;
4463
4464                 case ARG_NO_PAGER:
4465                         arg_no_pager = true;
4466                         break;
4467
4468                 case ARG_NO_WALL:
4469                         arg_no_wall = true;
4470                         break;
4471
4472                 case ARG_ORDER:
4473                         arg_dot = DOT_ORDER;
4474                         break;
4475
4476                 case ARG_REQUIRE:
4477                         arg_dot = DOT_REQUIRE;
4478                         break;
4479
4480                 case ARG_ROOT:
4481                         arg_root = optarg;
4482                         break;
4483
4484                 case ARG_FULL:
4485                         arg_full = true;
4486                         break;
4487
4488                 case ARG_FAILED:
4489                         arg_failed = true;
4490                         break;
4491
4492                 case 'q':
4493                         arg_quiet = true;
4494                         break;
4495
4496                 case ARG_FORCE:
4497                         arg_force ++;
4498                         break;
4499
4500                 case ARG_FOLLOW:
4501                         arg_follow = true;
4502                         break;
4503
4504                 case 'f':
4505                         /* -f is short for both --follow and --force! */
4506                         arg_force ++;
4507                         arg_follow = true;
4508                         break;
4509
4510                 case ARG_NO_RELOAD:
4511                         arg_no_reload = true;
4512                         break;
4513
4514                 case ARG_KILL_WHO:
4515                         arg_kill_who = optarg;
4516                         break;
4517
4518                 case ARG_KILL_MODE:
4519                         arg_kill_mode = optarg;
4520                         break;
4521
4522                 case 's':
4523                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4524                                 log_error("Failed to parse signal string %s.", optarg);
4525                                 return -EINVAL;
4526                         }
4527                         break;
4528
4529                 case ARG_NO_ASK_PASSWORD:
4530                         arg_ask_password = false;
4531                         break;
4532
4533                 case 'P':
4534                         arg_transport = TRANSPORT_POLKIT;
4535                         break;
4536
4537                 case 'H':
4538                         arg_transport = TRANSPORT_SSH;
4539                         arg_host = optarg;
4540                         break;
4541
4542                 case ARG_RUNTIME:
4543                         arg_runtime = true;
4544                         break;
4545
4546                 case 'n':
4547                         if (safe_atou(optarg, &arg_lines) < 0) {
4548                                 log_error("Failed to parse lines '%s'", optarg);
4549                                 return -EINVAL;
4550                         }
4551                         break;
4552
4553                 case 'o':
4554                         arg_output = output_mode_from_string(optarg);
4555                         if (arg_output < 0) {
4556                                 log_error("Unknown output '%s'.", optarg);
4557                                 return -EINVAL;
4558                         }
4559                         break;
4560
4561                 case '?':
4562                         return -EINVAL;
4563
4564                 default:
4565                         log_error("Unknown option code %c", c);
4566                         return -EINVAL;
4567                 }
4568         }
4569
4570         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4571                 log_error("Cannot access user instance remotely.");
4572                 return -EINVAL;
4573         }
4574
4575         return 1;
4576 }
4577
4578 static int halt_parse_argv(int argc, char *argv[]) {
4579
4580         enum {
4581                 ARG_HELP = 0x100,
4582                 ARG_HALT,
4583                 ARG_REBOOT,
4584                 ARG_NO_WALL
4585         };
4586
4587         static const struct option options[] = {
4588                 { "help",      no_argument,       NULL, ARG_HELP    },
4589                 { "halt",      no_argument,       NULL, ARG_HALT    },
4590                 { "poweroff",  no_argument,       NULL, 'p'         },
4591                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4592                 { "force",     no_argument,       NULL, 'f'         },
4593                 { "wtmp-only", no_argument,       NULL, 'w'         },
4594                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4595                 { "no-sync",   no_argument,       NULL, 'n'         },
4596                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4597                 { NULL,        0,                 NULL, 0           }
4598         };
4599
4600         int c, runlevel;
4601
4602         assert(argc >= 0);
4603         assert(argv);
4604
4605         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4606                 if (runlevel == '0' || runlevel == '6')
4607                         arg_force = 2;
4608
4609         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4610                 switch (c) {
4611
4612                 case ARG_HELP:
4613                         halt_help();
4614                         return 0;
4615
4616                 case ARG_HALT:
4617                         arg_action = ACTION_HALT;
4618                         break;
4619
4620                 case 'p':
4621                         if (arg_action != ACTION_REBOOT)
4622                                 arg_action = ACTION_POWEROFF;
4623                         break;
4624
4625                 case ARG_REBOOT:
4626                         arg_action = ACTION_REBOOT;
4627                         break;
4628
4629                 case 'f':
4630                         arg_force = 2;
4631                         break;
4632
4633                 case 'w':
4634                         arg_dry = true;
4635                         break;
4636
4637                 case 'd':
4638                         arg_no_wtmp = true;
4639                         break;
4640
4641                 case 'n':
4642                         arg_no_sync = true;
4643                         break;
4644
4645                 case ARG_NO_WALL:
4646                         arg_no_wall = true;
4647                         break;
4648
4649                 case 'i':
4650                 case 'h':
4651                         /* Compatibility nops */
4652                         break;
4653
4654                 case '?':
4655                         return -EINVAL;
4656
4657                 default:
4658                         log_error("Unknown option code %c", c);
4659                         return -EINVAL;
4660                 }
4661         }
4662
4663         if (optind < argc) {
4664                 log_error("Too many arguments.");
4665                 return -EINVAL;
4666         }
4667
4668         return 1;
4669 }
4670
4671 static int parse_time_spec(const char *t, usec_t *_u) {
4672         assert(t);
4673         assert(_u);
4674
4675         if (streq(t, "now"))
4676                 *_u = 0;
4677         else if (!strchr(t, ':')) {
4678                 uint64_t u;
4679
4680                 if (safe_atou64(t, &u) < 0)
4681                         return -EINVAL;
4682
4683                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4684         } else {
4685                 char *e = NULL;
4686                 long hour, minute;
4687                 struct tm tm;
4688                 time_t s;
4689                 usec_t n;
4690
4691                 errno = 0;
4692                 hour = strtol(t, &e, 10);
4693                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4694                         return -EINVAL;
4695
4696                 minute = strtol(e+1, &e, 10);
4697                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4698                         return -EINVAL;
4699
4700                 n = now(CLOCK_REALTIME);
4701                 s = (time_t) (n / USEC_PER_SEC);
4702
4703                 zero(tm);
4704                 assert_se(localtime_r(&s, &tm));
4705
4706                 tm.tm_hour = (int) hour;
4707                 tm.tm_min = (int) minute;
4708                 tm.tm_sec = 0;
4709
4710                 assert_se(s = mktime(&tm));
4711
4712                 *_u = (usec_t) s * USEC_PER_SEC;
4713
4714                 while (*_u <= n)
4715                         *_u += USEC_PER_DAY;
4716         }
4717
4718         return 0;
4719 }
4720
4721 static int shutdown_parse_argv(int argc, char *argv[]) {
4722
4723         enum {
4724                 ARG_HELP = 0x100,
4725                 ARG_NO_WALL
4726         };
4727
4728         static const struct option options[] = {
4729                 { "help",      no_argument,       NULL, ARG_HELP    },
4730                 { "halt",      no_argument,       NULL, 'H'         },
4731                 { "poweroff",  no_argument,       NULL, 'P'         },
4732                 { "reboot",    no_argument,       NULL, 'r'         },
4733                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4734                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4735                 { NULL,        0,                 NULL, 0           }
4736         };
4737
4738         int c, r;
4739
4740         assert(argc >= 0);
4741         assert(argv);
4742
4743         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4744                 switch (c) {
4745
4746                 case ARG_HELP:
4747                         shutdown_help();
4748                         return 0;
4749
4750                 case 'H':
4751                         arg_action = ACTION_HALT;
4752                         break;
4753
4754                 case 'P':
4755                         arg_action = ACTION_POWEROFF;
4756                         break;
4757
4758                 case 'r':
4759                         if (kexec_loaded())
4760                                 arg_action = ACTION_KEXEC;
4761                         else
4762                                 arg_action = ACTION_REBOOT;
4763                         break;
4764
4765                 case 'K':
4766                         arg_action = ACTION_KEXEC;
4767                         break;
4768
4769                 case 'h':
4770                         if (arg_action != ACTION_HALT)
4771                                 arg_action = ACTION_POWEROFF;
4772                         break;
4773
4774                 case 'k':
4775                         arg_dry = true;
4776                         break;
4777
4778                 case ARG_NO_WALL:
4779                         arg_no_wall = true;
4780                         break;
4781
4782                 case 't':
4783                 case 'a':
4784                         /* Compatibility nops */
4785                         break;
4786
4787                 case 'c':
4788                         arg_action = ACTION_CANCEL_SHUTDOWN;
4789                         break;
4790
4791                 case '?':
4792                         return -EINVAL;
4793
4794                 default:
4795                         log_error("Unknown option code %c", c);
4796                         return -EINVAL;
4797                 }
4798         }
4799
4800         if (argc > optind) {
4801                 r = parse_time_spec(argv[optind], &arg_when);
4802                 if (r < 0) {
4803                         log_error("Failed to parse time specification: %s", argv[optind]);
4804                         return r;
4805                 }
4806         } else
4807                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4808
4809         /* We skip the time argument */
4810         if (argc > optind + 1)
4811                 arg_wall = argv + optind + 1;
4812
4813         optind = argc;
4814
4815         return 1;
4816 }
4817
4818 static int telinit_parse_argv(int argc, char *argv[]) {
4819
4820         enum {
4821                 ARG_HELP = 0x100,
4822                 ARG_NO_WALL
4823         };
4824
4825         static const struct option options[] = {
4826                 { "help",      no_argument,       NULL, ARG_HELP    },
4827                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4828                 { NULL,        0,                 NULL, 0           }
4829         };
4830
4831         static const struct {
4832                 char from;
4833                 enum action to;
4834         } table[] = {
4835                 { '0', ACTION_POWEROFF },
4836                 { '6', ACTION_REBOOT },
4837                 { '1', ACTION_RESCUE },
4838                 { '2', ACTION_RUNLEVEL2 },
4839                 { '3', ACTION_RUNLEVEL3 },
4840                 { '4', ACTION_RUNLEVEL4 },
4841                 { '5', ACTION_RUNLEVEL5 },
4842                 { 's', ACTION_RESCUE },
4843                 { 'S', ACTION_RESCUE },
4844                 { 'q', ACTION_RELOAD },
4845                 { 'Q', ACTION_RELOAD },
4846                 { 'u', ACTION_REEXEC },
4847                 { 'U', ACTION_REEXEC }
4848         };
4849
4850         unsigned i;
4851         int c;
4852
4853         assert(argc >= 0);
4854         assert(argv);
4855
4856         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4857                 switch (c) {
4858
4859                 case ARG_HELP:
4860                         telinit_help();
4861                         return 0;
4862
4863                 case ARG_NO_WALL:
4864                         arg_no_wall = true;
4865                         break;
4866
4867                 case '?':
4868                         return -EINVAL;
4869
4870                 default:
4871                         log_error("Unknown option code %c", c);
4872                         return -EINVAL;
4873                 }
4874         }
4875
4876         if (optind >= argc) {
4877                 telinit_help();
4878                 return -EINVAL;
4879         }
4880
4881         if (optind + 1 < argc) {
4882                 log_error("Too many arguments.");
4883                 return -EINVAL;
4884         }
4885
4886         if (strlen(argv[optind]) != 1) {
4887                 log_error("Expected single character argument.");
4888                 return -EINVAL;
4889         }
4890
4891         for (i = 0; i < ELEMENTSOF(table); i++)
4892                 if (table[i].from == argv[optind][0])
4893                         break;
4894
4895         if (i >= ELEMENTSOF(table)) {
4896                 log_error("Unknown command %s.", argv[optind]);
4897                 return -EINVAL;
4898         }
4899
4900         arg_action = table[i].to;
4901
4902         optind ++;
4903
4904         return 1;
4905 }
4906
4907 static int runlevel_parse_argv(int argc, char *argv[]) {
4908
4909         enum {
4910                 ARG_HELP = 0x100,
4911         };
4912
4913         static const struct option options[] = {
4914                 { "help",      no_argument,       NULL, ARG_HELP    },
4915                 { NULL,        0,                 NULL, 0           }
4916         };
4917
4918         int c;
4919
4920         assert(argc >= 0);
4921         assert(argv);
4922
4923         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4924                 switch (c) {
4925
4926                 case ARG_HELP:
4927                         runlevel_help();
4928                         return 0;
4929
4930                 case '?':
4931                         return -EINVAL;
4932
4933                 default:
4934                         log_error("Unknown option code %c", c);
4935                         return -EINVAL;
4936                 }
4937         }
4938
4939         if (optind < argc) {
4940                 log_error("Too many arguments.");
4941                 return -EINVAL;
4942         }
4943
4944         return 1;
4945 }
4946
4947 static int parse_argv(int argc, char *argv[]) {
4948         assert(argc >= 0);
4949         assert(argv);
4950
4951         if (program_invocation_short_name) {
4952
4953                 if (strstr(program_invocation_short_name, "halt")) {
4954                         arg_action = ACTION_HALT;
4955                         return halt_parse_argv(argc, argv);
4956                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4957                         arg_action = ACTION_POWEROFF;
4958                         return halt_parse_argv(argc, argv);
4959                 } else if (strstr(program_invocation_short_name, "reboot")) {
4960                         if (kexec_loaded())
4961                                 arg_action = ACTION_KEXEC;
4962                         else
4963                                 arg_action = ACTION_REBOOT;
4964                         return halt_parse_argv(argc, argv);
4965                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4966                         arg_action = ACTION_POWEROFF;
4967                         return shutdown_parse_argv(argc, argv);
4968                 } else if (strstr(program_invocation_short_name, "init")) {
4969
4970                         if (sd_booted() > 0) {
4971                                 arg_action = ACTION_INVALID;
4972                                 return telinit_parse_argv(argc, argv);
4973                         } else {
4974                                 /* Hmm, so some other init system is
4975                                  * running, we need to forward this
4976                                  * request to it. For now we simply
4977                                  * guess that it is Upstart. */
4978
4979                                 execv("/lib/upstart/telinit", argv);
4980
4981                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4982                                 return -EIO;
4983                         }
4984
4985                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4986                         arg_action = ACTION_RUNLEVEL;
4987                         return runlevel_parse_argv(argc, argv);
4988                 }
4989         }
4990
4991         arg_action = ACTION_SYSTEMCTL;
4992         return systemctl_parse_argv(argc, argv);
4993 }
4994
4995 static int action_to_runlevel(void) {
4996
4997         static const char table[_ACTION_MAX] = {
4998                 [ACTION_HALT] =      '0',
4999                 [ACTION_POWEROFF] =  '0',
5000                 [ACTION_REBOOT] =    '6',
5001                 [ACTION_RUNLEVEL2] = '2',
5002                 [ACTION_RUNLEVEL3] = '3',
5003                 [ACTION_RUNLEVEL4] = '4',
5004                 [ACTION_RUNLEVEL5] = '5',
5005                 [ACTION_RESCUE] =    '1'
5006         };
5007
5008         assert(arg_action < _ACTION_MAX);
5009
5010         return table[arg_action];
5011 }
5012
5013 static int talk_upstart(void) {
5014         DBusMessage *m = NULL, *reply = NULL;
5015         DBusError error;
5016         int previous, rl, r;
5017         char
5018                 env1_buf[] = "RUNLEVEL=X",
5019                 env2_buf[] = "PREVLEVEL=X";
5020         char *env1 = env1_buf, *env2 = env2_buf;
5021         const char *emit = "runlevel";
5022         dbus_bool_t b_false = FALSE;
5023         DBusMessageIter iter, sub;
5024         DBusConnection *bus;
5025
5026         dbus_error_init(&error);
5027
5028         if (!(rl = action_to_runlevel()))
5029                 return 0;
5030
5031         if (utmp_get_runlevel(&previous, NULL) < 0)
5032                 previous = 'N';
5033
5034         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5035                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5036                         r = 0;
5037                         goto finish;
5038                 }
5039
5040                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5041                 r = -EIO;
5042                 goto finish;
5043         }
5044
5045         if ((r = bus_check_peercred(bus)) < 0) {
5046                 log_error("Failed to verify owner of bus.");
5047                 goto finish;
5048         }
5049
5050         if (!(m = dbus_message_new_method_call(
5051                               "com.ubuntu.Upstart",
5052                               "/com/ubuntu/Upstart",
5053                               "com.ubuntu.Upstart0_6",
5054                               "EmitEvent"))) {
5055
5056                 log_error("Could not allocate message.");
5057                 r = -ENOMEM;
5058                 goto finish;
5059         }
5060
5061         dbus_message_iter_init_append(m, &iter);
5062
5063         env1_buf[sizeof(env1_buf)-2] = rl;
5064         env2_buf[sizeof(env2_buf)-2] = previous;
5065
5066         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5067             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5068             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5069             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5070             !dbus_message_iter_close_container(&iter, &sub) ||
5071             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5072                 log_error("Could not append arguments to message.");
5073                 r = -ENOMEM;
5074                 goto finish;
5075         }
5076
5077         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5078
5079                 if (error_is_no_service(&error)) {
5080                         r = -EADDRNOTAVAIL;
5081                         goto finish;
5082                 }
5083
5084                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5085                 r = -EIO;
5086                 goto finish;
5087         }
5088
5089         r = 1;
5090
5091 finish:
5092         if (m)
5093                 dbus_message_unref(m);
5094
5095         if (reply)
5096                 dbus_message_unref(reply);
5097
5098         if (bus) {
5099                 dbus_connection_flush(bus);
5100                 dbus_connection_close(bus);
5101                 dbus_connection_unref(bus);
5102         }
5103
5104         dbus_error_free(&error);
5105
5106         return r;
5107 }
5108
5109 static int talk_initctl(void) {
5110         struct init_request request;
5111         int r, fd;
5112         char rl;
5113
5114         if (!(rl = action_to_runlevel()))
5115                 return 0;
5116
5117         zero(request);
5118         request.magic = INIT_MAGIC;
5119         request.sleeptime = 0;
5120         request.cmd = INIT_CMD_RUNLVL;
5121         request.runlevel = rl;
5122
5123         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5124
5125                 if (errno == ENOENT)
5126                         return 0;
5127
5128                 log_error("Failed to open "INIT_FIFO": %m");
5129                 return -errno;
5130         }
5131
5132         errno = 0;
5133         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5134         close_nointr_nofail(fd);
5135
5136         if (r < 0) {
5137                 log_error("Failed to write to "INIT_FIFO": %m");
5138                 return errno ? -errno : -EIO;
5139         }
5140
5141         return 1;
5142 }
5143
5144 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5145
5146         static const struct {
5147                 const char* verb;
5148                 const enum {
5149                         MORE,
5150                         LESS,
5151                         EQUAL
5152                 } argc_cmp;
5153                 const int argc;
5154                 int (* const dispatch)(DBusConnection *bus, char **args);
5155         } verbs[] = {
5156                 { "list-units",            LESS,  1, list_units        },
5157                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5158                 { "list-jobs",             EQUAL, 1, list_jobs         },
5159                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5160                 { "load",                  MORE,  2, load_unit         },
5161                 { "cancel",                MORE,  2, cancel_job        },
5162                 { "start",                 MORE,  2, start_unit        },
5163                 { "stop",                  MORE,  2, start_unit        },
5164                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5165                 { "reload",                MORE,  2, start_unit        },
5166                 { "restart",               MORE,  2, start_unit        },
5167                 { "try-restart",           MORE,  2, start_unit        },
5168                 { "reload-or-restart",     MORE,  2, start_unit        },
5169                 { "reload-or-try-restart", MORE,  2, start_unit        },
5170                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5171                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5172                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5173                 { "isolate",               EQUAL, 2, start_unit        },
5174                 { "kill",                  MORE,  2, kill_unit         },
5175                 { "is-active",             MORE,  2, check_unit        },
5176                 { "check",                 MORE,  2, check_unit        },
5177                 { "show",                  MORE,  1, show              },
5178                 { "status",                MORE,  2, show              },
5179                 { "dump",                  EQUAL, 1, dump              },
5180                 { "dot",                   EQUAL, 1, dot               },
5181                 { "snapshot",              LESS,  2, snapshot          },
5182                 { "delete",                MORE,  2, delete_snapshot   },
5183                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5184                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5185                 { "show-environment",      EQUAL, 1, show_enviroment   },
5186                 { "set-environment",       MORE,  2, set_environment   },
5187                 { "unset-environment",     MORE,  2, set_environment   },
5188                 { "halt",                  EQUAL, 1, start_special     },
5189                 { "poweroff",              EQUAL, 1, start_special     },
5190                 { "reboot",                EQUAL, 1, start_special     },
5191                 { "kexec",                 EQUAL, 1, start_special     },
5192                 { "suspend",               EQUAL, 1, start_special     },
5193                 { "hibernate",             EQUAL, 1, start_special     },
5194                 { "default",               EQUAL, 1, start_special     },
5195                 { "rescue",                EQUAL, 1, start_special     },
5196                 { "emergency",             EQUAL, 1, start_special     },
5197                 { "exit",                  EQUAL, 1, start_special     },
5198                 { "reset-failed",          MORE,  1, reset_failed      },
5199                 { "enable",                MORE,  2, enable_unit       },
5200                 { "disable",               MORE,  2, enable_unit       },
5201                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5202                 { "reenable",              MORE,  2, enable_unit       },
5203                 { "preset",                MORE,  2, enable_unit       },
5204                 { "mask",                  MORE,  2, enable_unit       },
5205                 { "unmask",                MORE,  2, enable_unit       },
5206                 { "link",                  MORE,  2, enable_unit       },
5207                 { "switch-root",           MORE,  2, switch_root       },
5208         };
5209
5210         int left;
5211         unsigned i;
5212
5213         assert(argc >= 0);
5214         assert(argv);
5215         assert(error);
5216
5217         left = argc - optind;
5218
5219         if (left <= 0)
5220                 /* Special rule: no arguments means "list-units" */
5221                 i = 0;
5222         else {
5223                 if (streq(argv[optind], "help")) {
5224                         systemctl_help();
5225                         return 0;
5226                 }
5227
5228                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5229                         if (streq(argv[optind], verbs[i].verb))
5230                                 break;
5231
5232                 if (i >= ELEMENTSOF(verbs)) {
5233                         log_error("Unknown operation %s", argv[optind]);
5234                         return -EINVAL;
5235                 }
5236         }
5237
5238         switch (verbs[i].argc_cmp) {
5239
5240         case EQUAL:
5241                 if (left != verbs[i].argc) {
5242                         log_error("Invalid number of arguments.");
5243                         return -EINVAL;
5244                 }
5245
5246                 break;
5247
5248         case MORE:
5249                 if (left < verbs[i].argc) {
5250                         log_error("Too few arguments.");
5251                         return -EINVAL;
5252                 }
5253
5254                 break;
5255
5256         case LESS:
5257                 if (left > verbs[i].argc) {
5258                         log_error("Too many arguments.");
5259                         return -EINVAL;
5260                 }
5261
5262                 break;
5263
5264         default:
5265                 assert_not_reached("Unknown comparison operator.");
5266         }
5267
5268         /* Require a bus connection for all operations but
5269          * enable/disable */
5270         if (!streq(verbs[i].verb, "enable") &&
5271             !streq(verbs[i].verb, "disable") &&
5272             !streq(verbs[i].verb, "is-enabled") &&
5273             !streq(verbs[i].verb, "list-unit-files") &&
5274             !streq(verbs[i].verb, "reenable") &&
5275             !streq(verbs[i].verb, "preset") &&
5276             !streq(verbs[i].verb, "mask") &&
5277             !streq(verbs[i].verb, "unmask") &&
5278             !streq(verbs[i].verb, "link")) {
5279
5280                 if (running_in_chroot() > 0) {
5281                         log_info("Running in chroot, ignoring request.");
5282                         return 0;
5283                 }
5284
5285                 if (((!streq(verbs[i].verb, "reboot") &&
5286                       !streq(verbs[i].verb, "halt") &&
5287                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5288                         log_error("Failed to get D-Bus connection: %s",
5289                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5290                         return -EIO;
5291                 }
5292
5293         } else {
5294
5295                 if (!bus && !avoid_bus()) {
5296                         log_error("Failed to get D-Bus connection: %s",
5297                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5298                         return -EIO;
5299                 }
5300         }
5301
5302         return verbs[i].dispatch(bus, argv + optind);
5303 }
5304
5305 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5306         int fd;
5307         struct msghdr msghdr;
5308         struct iovec iovec[2];
5309         union sockaddr_union sockaddr;
5310         struct sd_shutdown_command c;
5311
5312         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5313         if (fd < 0)
5314                 return -errno;
5315
5316         zero(c);
5317         c.usec = t;
5318         c.mode = mode;
5319         c.dry_run = dry_run;
5320         c.warn_wall = warn;
5321
5322         zero(sockaddr);
5323         sockaddr.sa.sa_family = AF_UNIX;
5324         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5325
5326         zero(msghdr);
5327         msghdr.msg_name = &sockaddr;
5328         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5329
5330         zero(iovec);
5331         iovec[0].iov_base = (char*) &c;
5332         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5333
5334         if (isempty(message))
5335                 msghdr.msg_iovlen = 1;
5336         else {
5337                 iovec[1].iov_base = (char*) message;
5338                 iovec[1].iov_len = strlen(message);
5339                 msghdr.msg_iovlen = 2;
5340         }
5341         msghdr.msg_iov = iovec;
5342
5343         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5344                 close_nointr_nofail(fd);
5345                 return -errno;
5346         }
5347
5348         close_nointr_nofail(fd);
5349         return 0;
5350 }
5351
5352 static int reload_with_fallback(DBusConnection *bus) {
5353
5354         if (bus) {
5355                 /* First, try systemd via D-Bus. */
5356                 if (daemon_reload(bus, NULL) >= 0)
5357                         return 0;
5358         }
5359
5360         /* Nothing else worked, so let's try signals */
5361         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5362
5363         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5364                 log_error("kill() failed: %m");
5365                 return -errno;
5366         }
5367
5368         return 0;
5369 }
5370
5371 static int start_with_fallback(DBusConnection *bus) {
5372
5373         if (bus) {
5374                 /* First, try systemd via D-Bus. */
5375                 if (start_unit(bus, NULL) >= 0)
5376                         goto done;
5377         }
5378
5379         /* Hmm, talking to systemd via D-Bus didn't work. Then
5380          * let's try to talk to Upstart via D-Bus. */
5381         if (talk_upstart() > 0)
5382                 goto done;
5383
5384         /* Nothing else worked, so let's try
5385          * /dev/initctl */
5386         if (talk_initctl() > 0)
5387                 goto done;
5388
5389         log_error("Failed to talk to init daemon.");
5390         return -EIO;
5391
5392 done:
5393         warn_wall(arg_action);
5394         return 0;
5395 }
5396
5397 static void halt_now(enum action a) {
5398
5399        /* Make sure C-A-D is handled by the kernel from this
5400          * point on... */
5401         reboot(RB_ENABLE_CAD);
5402
5403         switch (a) {
5404
5405         case ACTION_HALT:
5406                 log_info("Halting.");
5407                 reboot(RB_HALT_SYSTEM);
5408                 break;
5409
5410         case ACTION_POWEROFF:
5411                 log_info("Powering off.");
5412                 reboot(RB_POWER_OFF);
5413                 break;
5414
5415         case ACTION_REBOOT:
5416                 log_info("Rebooting.");
5417                 reboot(RB_AUTOBOOT);
5418                 break;
5419
5420         default:
5421                 assert_not_reached("Unknown halt action.");
5422         }
5423
5424         assert_not_reached("Uh? This shouldn't happen.");
5425 }
5426
5427 static int halt_main(DBusConnection *bus) {
5428         int r;
5429
5430         if (geteuid() != 0) {
5431                 /* Try logind if we are a normal user and no special
5432                  * mode applies. Maybe PolicyKit allows us to shutdown
5433                  * the machine. */
5434
5435                 if (arg_when <= 0 &&
5436                     !arg_dry &&
5437                     !arg_force &&
5438                     (arg_action == ACTION_POWEROFF ||
5439                      arg_action == ACTION_REBOOT)) {
5440                         r = reboot_with_logind(bus, arg_action);
5441                         if (r >= 0)
5442                                 return r;
5443                 }
5444
5445                 log_error("Must be root.");
5446                 return -EPERM;
5447         }
5448
5449         if (arg_when > 0) {
5450                 char *m;
5451
5452                 m = strv_join(arg_wall, " ");
5453                 r = send_shutdownd(arg_when,
5454                                    arg_action == ACTION_HALT     ? 'H' :
5455                                    arg_action == ACTION_POWEROFF ? 'P' :
5456                                    arg_action == ACTION_KEXEC    ? 'K' :
5457                                                                    'r',
5458                                    arg_dry,
5459                                    !arg_no_wall,
5460                                    m);
5461                 free(m);
5462
5463                 if (r < 0)
5464                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5465                 else {
5466                         char date[FORMAT_TIMESTAMP_MAX];
5467
5468                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5469                                  format_timestamp(date, sizeof(date), arg_when));
5470                         return 0;
5471                 }
5472         }
5473
5474         if (!arg_dry && !arg_force)
5475                 return start_with_fallback(bus);
5476
5477         if (!arg_no_wtmp) {
5478                 if (sd_booted() > 0)
5479                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5480                 else {
5481                         r = utmp_put_shutdown();
5482                         if (r < 0)
5483                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5484                 }
5485         }
5486
5487         if (!arg_no_sync)
5488                 sync();
5489
5490         if (arg_dry)
5491                 return 0;
5492
5493         halt_now(arg_action);
5494         /* We should never reach this. */
5495         return -ENOSYS;
5496 }
5497
5498 static int runlevel_main(void) {
5499         int r, runlevel, previous;
5500
5501         r = utmp_get_runlevel(&runlevel, &previous);
5502         if (r < 0) {
5503                 puts("unknown");
5504                 return r;
5505         }
5506
5507         printf("%c %c\n",
5508                previous <= 0 ? 'N' : previous,
5509                runlevel <= 0 ? 'N' : runlevel);
5510
5511         return 0;
5512 }
5513
5514 int main(int argc, char*argv[]) {
5515         int r, retval = EXIT_FAILURE;
5516         DBusConnection *bus = NULL;
5517         DBusError error;
5518
5519         dbus_error_init(&error);
5520
5521         log_parse_environment();
5522         log_open();
5523
5524         r = parse_argv(argc, argv);
5525         if (r < 0)
5526                 goto finish;
5527         else if (r == 0) {
5528                 retval = EXIT_SUCCESS;
5529                 goto finish;
5530         }
5531
5532         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5533          * let's shortcut this */
5534         if (arg_action == ACTION_RUNLEVEL) {
5535                 r = runlevel_main();
5536                 retval = r < 0 ? EXIT_FAILURE : r;
5537                 goto finish;
5538         }
5539
5540         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5541                 log_info("Running in chroot, ignoring request.");
5542                 retval = 0;
5543                 goto finish;
5544         }
5545
5546         if (!avoid_bus()) {
5547                 if (arg_transport == TRANSPORT_NORMAL)
5548                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5549                 else if (arg_transport == TRANSPORT_POLKIT) {
5550                         bus_connect_system_polkit(&bus, &error);
5551                         private_bus = false;
5552                 } else if (arg_transport == TRANSPORT_SSH) {
5553                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5554                         private_bus = false;
5555                 } else
5556                         assert_not_reached("Uh, invalid transport...");
5557         }
5558
5559         switch (arg_action) {
5560
5561         case ACTION_SYSTEMCTL:
5562                 r = systemctl_main(bus, argc, argv, &error);
5563                 break;
5564
5565         case ACTION_HALT:
5566         case ACTION_POWEROFF:
5567         case ACTION_REBOOT:
5568         case ACTION_KEXEC:
5569                 r = halt_main(bus);
5570                 break;
5571
5572         case ACTION_RUNLEVEL2:
5573         case ACTION_RUNLEVEL3:
5574         case ACTION_RUNLEVEL4:
5575         case ACTION_RUNLEVEL5:
5576         case ACTION_RESCUE:
5577         case ACTION_EMERGENCY:
5578         case ACTION_DEFAULT:
5579                 r = start_with_fallback(bus);
5580                 break;
5581
5582         case ACTION_RELOAD:
5583         case ACTION_REEXEC:
5584                 r = reload_with_fallback(bus);
5585                 break;
5586
5587         case ACTION_CANCEL_SHUTDOWN:
5588                 r = send_shutdownd(0, 0, false, false, NULL);
5589                 break;
5590
5591         case ACTION_INVALID:
5592         case ACTION_RUNLEVEL:
5593         default:
5594                 assert_not_reached("Unknown action");
5595         }
5596
5597         retval = r < 0 ? EXIT_FAILURE : r;
5598
5599 finish:
5600         if (bus) {
5601                 dbus_connection_flush(bus);
5602                 dbus_connection_close(bus);
5603                 dbus_connection_unref(bus);
5604         }
5605
5606         dbus_error_free(&error);
5607
5608         dbus_shutdown();
5609
5610         strv_free(arg_property);
5611
5612         pager_close();
5613         ask_password_agent_close();
5614         polkit_agent_close();
5615
5616         return retval;
5617 }