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