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