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