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