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