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