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