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