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