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