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