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