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