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