chiark / gitweb /
util: simplify column caching logic
[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                         (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2297                         on_tty() * OUTPUT_COLOR |
2298                         arg_follow * OUTPUT_FOLLOW |
2299                         !arg_quiet * OUTPUT_WARN_CUTOFF;
2300
2301                 printf("\n");
2302                 show_journal_by_unit(stdout,
2303                                      i->id,
2304                                      arg_output,
2305                                      0,
2306                                      i->inactive_exit_timestamp_monotonic,
2307                                      arg_lines,
2308                                      flags);
2309         }
2310
2311         if (i->need_daemon_reload)
2312                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2313                        ansi_highlight_red(true),
2314                        ansi_highlight_red(false),
2315                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2316 }
2317
2318 static void show_unit_help(UnitStatusInfo *i) {
2319         char **p;
2320
2321         assert(i);
2322
2323         if (!i->documentation) {
2324                 log_info("Documentation for %s not known.", i->id);
2325                 return;
2326         }
2327
2328         STRV_FOREACH(p, i->documentation) {
2329
2330                 if (startswith(*p, "man:")) {
2331                         size_t k;
2332                         char *e = NULL;
2333                         char *page = NULL, *section = NULL;
2334                         const char *args[4] = { "man", NULL, NULL, NULL };
2335                         pid_t pid;
2336
2337                         k = strlen(*p);
2338
2339                         if ((*p)[k-1] == ')')
2340                                 e = strrchr(*p, '(');
2341
2342                         if (e) {
2343                                 page = strndup((*p) + 4, e - *p - 4);
2344                                 if (!page) {
2345                                         log_oom();
2346                                         return;
2347                                 }
2348
2349                                 section = strndup(e + 1, *p + k - e - 2);
2350                                 if (!section) {
2351                                         free(page);
2352                                         log_oom();
2353                                         return;
2354                                 }
2355
2356                                 args[1] = section;
2357                                 args[2] = page;
2358                         } else
2359                                 args[1] = *p + 4;
2360
2361                         pid = fork();
2362                         if (pid < 0) {
2363                                 log_error("Failed to fork: %m");
2364                                 free(page);
2365                                 free(section);
2366                                 continue;
2367                         }
2368
2369                         if (pid == 0) {
2370                                 /* Child */
2371                                 execvp(args[0], (char**) args);
2372                                 log_error("Failed to execute man: %m");
2373                                 _exit(EXIT_FAILURE);
2374                         }
2375
2376                         free(page);
2377                         free(section);
2378
2379                         wait_for_terminate(pid, NULL);
2380                 } else
2381                         log_info("Can't show: %s", *p);
2382         }
2383 }
2384
2385 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2386
2387         assert(name);
2388         assert(iter);
2389         assert(i);
2390
2391         switch (dbus_message_iter_get_arg_type(iter)) {
2392
2393         case DBUS_TYPE_STRING: {
2394                 const char *s;
2395
2396                 dbus_message_iter_get_basic(iter, &s);
2397
2398                 if (!isempty(s)) {
2399                         if (streq(name, "Id"))
2400                                 i->id = s;
2401                         else if (streq(name, "LoadState"))
2402                                 i->load_state = s;
2403                         else if (streq(name, "ActiveState"))
2404                                 i->active_state = s;
2405                         else if (streq(name, "SubState"))
2406                                 i->sub_state = s;
2407                         else if (streq(name, "Description"))
2408                                 i->description = s;
2409                         else if (streq(name, "FragmentPath"))
2410                                 i->fragment_path = s;
2411                         else if (streq(name, "SourcePath"))
2412                                 i->source_path = s;
2413                         else if (streq(name, "DefaultControlGroup"))
2414                                 i->default_control_group = s;
2415                         else if (streq(name, "StatusText"))
2416                                 i->status_text = s;
2417                         else if (streq(name, "SysFSPath"))
2418                                 i->sysfs_path = s;
2419                         else if (streq(name, "Where"))
2420                                 i->where = s;
2421                         else if (streq(name, "What"))
2422                                 i->what = s;
2423                         else if (streq(name, "Following"))
2424                                 i->following = s;
2425                         else if (streq(name, "UnitFileState"))
2426                                 i->unit_file_state = s;
2427                         else if (streq(name, "Result"))
2428                                 i->result = s;
2429                 }
2430
2431                 break;
2432         }
2433
2434         case DBUS_TYPE_BOOLEAN: {
2435                 dbus_bool_t b;
2436
2437                 dbus_message_iter_get_basic(iter, &b);
2438
2439                 if (streq(name, "Accept"))
2440                         i->accept = b;
2441                 else if (streq(name, "NeedDaemonReload"))
2442                         i->need_daemon_reload = b;
2443                 else if (streq(name, "ConditionResult"))
2444                         i->condition_result = b;
2445
2446                 break;
2447         }
2448
2449         case DBUS_TYPE_UINT32: {
2450                 uint32_t u;
2451
2452                 dbus_message_iter_get_basic(iter, &u);
2453
2454                 if (streq(name, "MainPID")) {
2455                         if (u > 0) {
2456                                 i->main_pid = (pid_t) u;
2457                                 i->running = true;
2458                         }
2459                 } else if (streq(name, "ControlPID"))
2460                         i->control_pid = (pid_t) u;
2461                 else if (streq(name, "ExecMainPID")) {
2462                         if (u > 0)
2463                                 i->main_pid = (pid_t) u;
2464                 } else if (streq(name, "NAccepted"))
2465                         i->n_accepted = u;
2466                 else if (streq(name, "NConnections"))
2467                         i->n_connections = u;
2468
2469                 break;
2470         }
2471
2472         case DBUS_TYPE_INT32: {
2473                 int32_t j;
2474
2475                 dbus_message_iter_get_basic(iter, &j);
2476
2477                 if (streq(name, "ExecMainCode"))
2478                         i->exit_code = (int) j;
2479                 else if (streq(name, "ExecMainStatus"))
2480                         i->exit_status = (int) j;
2481
2482                 break;
2483         }
2484
2485         case DBUS_TYPE_UINT64: {
2486                 uint64_t u;
2487
2488                 dbus_message_iter_get_basic(iter, &u);
2489
2490                 if (streq(name, "ExecMainStartTimestamp"))
2491                         i->start_timestamp = (usec_t) u;
2492                 else if (streq(name, "ExecMainExitTimestamp"))
2493                         i->exit_timestamp = (usec_t) u;
2494                 else if (streq(name, "ActiveEnterTimestamp"))
2495                         i->active_enter_timestamp = (usec_t) u;
2496                 else if (streq(name, "InactiveEnterTimestamp"))
2497                         i->inactive_enter_timestamp = (usec_t) u;
2498                 else if (streq(name, "InactiveExitTimestamp"))
2499                         i->inactive_exit_timestamp = (usec_t) u;
2500                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2501                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2502                 else if (streq(name, "ActiveExitTimestamp"))
2503                         i->active_exit_timestamp = (usec_t) u;
2504                 else if (streq(name, "ConditionTimestamp"))
2505                         i->condition_timestamp = (usec_t) u;
2506
2507                 break;
2508         }
2509
2510         case DBUS_TYPE_ARRAY: {
2511
2512                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2513                     startswith(name, "Exec")) {
2514                         DBusMessageIter sub;
2515
2516                         dbus_message_iter_recurse(iter, &sub);
2517                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2518                                 ExecStatusInfo *info;
2519                                 int r;
2520
2521                                 if (!(info = new0(ExecStatusInfo, 1)))
2522                                         return -ENOMEM;
2523
2524                                 if (!(info->name = strdup(name))) {
2525                                         free(info);
2526                                         return -ENOMEM;
2527                                 }
2528
2529                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2530                                         free(info);
2531                                         return r;
2532                                 }
2533
2534                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2535
2536                                 dbus_message_iter_next(&sub);
2537                         }
2538                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2539                            streq(name, "Documentation")) {
2540
2541                         DBusMessageIter sub;
2542
2543                         dbus_message_iter_recurse(iter, &sub);
2544                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2545                                 const char *s;
2546                                 char **l;
2547
2548                                 dbus_message_iter_get_basic(&sub, &s);
2549
2550                                 l = strv_append(i->documentation, s);
2551                                 if (!l)
2552                                         return -ENOMEM;
2553
2554                                 strv_free(i->documentation);
2555                                 i->documentation = l;
2556
2557                                 dbus_message_iter_next(&sub);
2558                         }
2559                 }
2560
2561                 break;
2562         }
2563
2564         case DBUS_TYPE_STRUCT: {
2565
2566                 if (streq(name, "LoadError")) {
2567                         DBusMessageIter sub;
2568                         const char *n, *message;
2569                         int r;
2570
2571                         dbus_message_iter_recurse(iter, &sub);
2572
2573                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2574                         if (r < 0)
2575                                 return r;
2576
2577                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2578                         if (r < 0)
2579                                 return r;
2580
2581                         if (!isempty(message))
2582                                 i->load_error = message;
2583                 }
2584
2585                 break;
2586         }
2587         }
2588
2589         return 0;
2590 }
2591
2592 static int print_property(const char *name, DBusMessageIter *iter) {
2593         assert(name);
2594         assert(iter);
2595
2596         /* This is a low-level property printer, see
2597          * print_status_info() for the nicer output */
2598
2599         if (arg_property && !strv_find(arg_property, name))
2600                 return 0;
2601
2602         switch (dbus_message_iter_get_arg_type(iter)) {
2603
2604         case DBUS_TYPE_STRUCT: {
2605                 DBusMessageIter sub;
2606                 dbus_message_iter_recurse(iter, &sub);
2607
2608                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2609                         uint32_t u;
2610
2611                         dbus_message_iter_get_basic(&sub, &u);
2612
2613                         if (u)
2614                                 printf("%s=%u\n", name, (unsigned) u);
2615                         else if (arg_all)
2616                                 printf("%s=\n", name);
2617
2618                         return 0;
2619                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2620                         const char *s;
2621
2622                         dbus_message_iter_get_basic(&sub, &s);
2623
2624                         if (arg_all || s[0])
2625                                 printf("%s=%s\n", name, s);
2626
2627                         return 0;
2628                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2629                         const char *a = NULL, *b = NULL;
2630
2631                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2632                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2633
2634                         if (arg_all || !isempty(a) || !isempty(b))
2635                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2636
2637                         return 0;
2638                 }
2639
2640                 break;
2641         }
2642
2643         case DBUS_TYPE_ARRAY:
2644
2645                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2646                         DBusMessageIter sub, sub2;
2647
2648                         dbus_message_iter_recurse(iter, &sub);
2649                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2650                                 const char *path;
2651                                 dbus_bool_t ignore;
2652
2653                                 dbus_message_iter_recurse(&sub, &sub2);
2654
2655                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2656                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2657                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2658
2659                                 dbus_message_iter_next(&sub);
2660                         }
2661
2662                         return 0;
2663
2664                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2665                         DBusMessageIter sub, sub2;
2666
2667                         dbus_message_iter_recurse(iter, &sub);
2668                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2669                                 const char *type, *path;
2670
2671                                 dbus_message_iter_recurse(&sub, &sub2);
2672
2673                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2674                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2675                                         printf("%s=%s\n", type, path);
2676
2677                                 dbus_message_iter_next(&sub);
2678                         }
2679
2680                         return 0;
2681
2682                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2683                         DBusMessageIter sub, sub2;
2684
2685                         dbus_message_iter_recurse(iter, &sub);
2686                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2687                                 const char *base;
2688                                 uint64_t value, next_elapse;
2689
2690                                 dbus_message_iter_recurse(&sub, &sub2);
2691
2692                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2693                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2694                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2695                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2696
2697                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2698                                                base,
2699                                                format_timespan(timespan1, sizeof(timespan1), value),
2700                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2701                                 }
2702
2703                                 dbus_message_iter_next(&sub);
2704                         }
2705
2706                         return 0;
2707
2708                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2709                         DBusMessageIter sub, sub2;
2710
2711                         dbus_message_iter_recurse(iter, &sub);
2712                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2713                                 const char *controller, *attr, *value;
2714
2715                                 dbus_message_iter_recurse(&sub, &sub2);
2716
2717                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2718                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2719                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2720
2721                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2722                                                controller,
2723                                                attr,
2724                                                value);
2725                                 }
2726
2727                                 dbus_message_iter_next(&sub);
2728                         }
2729
2730                         return 0;
2731
2732                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2733                         DBusMessageIter sub;
2734
2735                         dbus_message_iter_recurse(iter, &sub);
2736                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2737                                 ExecStatusInfo info;
2738
2739                                 zero(info);
2740                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2741                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2742                                         char *t;
2743
2744                                         t = strv_join(info.argv, " ");
2745
2746                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2747                                                name,
2748                                                strna(info.path),
2749                                                strna(t),
2750                                                yes_no(info.ignore),
2751                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2752                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2753                                                (unsigned) info. pid,
2754                                                sigchld_code_to_string(info.code),
2755                                                info.status,
2756                                                info.code == CLD_EXITED ? "" : "/",
2757                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2758
2759                                         free(t);
2760                                 }
2761
2762                                 free(info.path);
2763                                 strv_free(info.argv);
2764
2765                                 dbus_message_iter_next(&sub);
2766                         }
2767
2768                         return 0;
2769                 }
2770
2771                 break;
2772         }
2773
2774         if (generic_print_property(name, iter, arg_all) > 0)
2775                 return 0;
2776
2777         if (arg_all)
2778                 printf("%s=[unprintable]\n", name);
2779
2780         return 0;
2781 }
2782
2783 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2784         DBusMessage *reply = NULL;
2785         const char *interface = "";
2786         int r;
2787         DBusMessageIter iter, sub, sub2, sub3;
2788         UnitStatusInfo info;
2789         ExecStatusInfo *p;
2790
2791         assert(path);
2792         assert(new_line);
2793
2794         zero(info);
2795
2796         r = bus_method_call_with_reply (
2797                         bus,
2798                         "org.freedesktop.systemd1",
2799                         path,
2800                         "org.freedesktop.DBus.Properties",
2801                         "GetAll",
2802                         &reply,
2803                         NULL,
2804                         DBUS_TYPE_STRING, &interface,
2805                         DBUS_TYPE_INVALID);
2806         if (r)
2807                 goto finish;
2808
2809         if (!dbus_message_iter_init(reply, &iter) ||
2810             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2811             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2812                 log_error("Failed to parse reply.");
2813                 r = -EIO;
2814                 goto finish;
2815         }
2816
2817         dbus_message_iter_recurse(&iter, &sub);
2818
2819         if (*new_line)
2820                 printf("\n");
2821
2822         *new_line = true;
2823
2824         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2825                 const char *name;
2826
2827                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2828                         log_error("Failed to parse reply.");
2829                         r = -EIO;
2830                         goto finish;
2831                 }
2832
2833                 dbus_message_iter_recurse(&sub, &sub2);
2834
2835                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2836                         log_error("Failed to parse reply.");
2837                         r = -EIO;
2838                         goto finish;
2839                 }
2840
2841                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2842                         log_error("Failed to parse reply.");
2843                         r = -EIO;
2844                         goto finish;
2845                 }
2846
2847                 dbus_message_iter_recurse(&sub2, &sub3);
2848
2849                 if (show_properties)
2850                         r = print_property(name, &sub3);
2851                 else
2852                         r = status_property(name, &sub3, &info);
2853
2854                 if (r < 0) {
2855                         log_error("Failed to parse reply.");
2856                         r = -EIO;
2857                         goto finish;
2858                 }
2859
2860                 dbus_message_iter_next(&sub);
2861         }
2862
2863         r = 0;
2864
2865         if (!show_properties) {
2866                 if (streq(verb, "help"))
2867                         show_unit_help(&info);
2868                 else
2869                         print_status_info(&info);
2870         }
2871
2872         strv_free(info.documentation);
2873
2874         if (!streq_ptr(info.active_state, "active") &&
2875             !streq_ptr(info.active_state, "reloading") &&
2876             streq(verb, "status"))
2877                 /* According to LSB: "program not running" */
2878                 r = 3;
2879
2880         while ((p = info.exec)) {
2881                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2882                 exec_status_info_free(p);
2883         }
2884
2885 finish:
2886         if (reply)
2887                 dbus_message_unref(reply);
2888
2889         return r;
2890 }
2891
2892 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
2893         DBusMessage *reply = NULL;
2894         const char *path = NULL;
2895         DBusError error;
2896         int r;
2897
2898         dbus_error_init(&error);
2899
2900         r = bus_method_call_with_reply (
2901                         bus,
2902                         "org.freedesktop.systemd1",
2903                         "/org/freedesktop/systemd1",
2904                         "org.freedesktop.systemd1.Manager",
2905                         "GetUnitByPID",
2906                         &reply,
2907                         NULL,
2908                         DBUS_TYPE_UINT32, &pid,
2909                         DBUS_TYPE_INVALID);
2910         if (r)
2911                 goto finish;
2912
2913         if (!dbus_message_get_args(reply, &error,
2914                                    DBUS_TYPE_OBJECT_PATH, &path,
2915                                    DBUS_TYPE_INVALID)) {
2916                 log_error("Failed to parse reply: %s", bus_error_message(&error));
2917                 r = -EIO;
2918                 goto finish;
2919         }
2920
2921         r = show_one(verb, bus, path, false, new_line);
2922
2923 finish:
2924         if (reply)
2925                 dbus_message_unref(reply);
2926
2927         dbus_error_free(&error);
2928
2929         return r;
2930 }
2931
2932 static int show(DBusConnection *bus, char **args) {
2933         int r, ret = 0;
2934         bool show_properties, new_line = false;
2935         char **name;
2936
2937         assert(bus);
2938         assert(args);
2939
2940         show_properties = streq(args[0], "show");
2941
2942         if (show_properties)
2943                 pager_open_if_enabled();
2944
2945         if (show_properties && strv_length(args) <= 1) {
2946                 /* If not argument is specified inspect the manager
2947                  * itself */
2948
2949                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2950         }
2951
2952         STRV_FOREACH(name, args+1) {
2953                 uint32_t id;
2954
2955                 if (safe_atou32(*name, &id) < 0) {
2956                         char *p, *n;
2957                         /* Interpret as unit name */
2958
2959                         n = unit_name_mangle(*name);
2960                         p = unit_dbus_path_from_name(n ? n : *name);
2961                         free(n);
2962                         if (!p)
2963                                 return log_oom();
2964
2965                         r = show_one(args[0], bus, p, show_properties, &new_line);
2966                         free(p);
2967
2968                         if (r != 0)
2969                                 ret = r;
2970
2971                 } else if (show_properties) {
2972
2973                         /* Interpret as job id */
2974
2975                         char *p;
2976                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
2977                                 return log_oom();
2978
2979                         r = show_one(args[0], bus, p, show_properties, &new_line);
2980                         free(p);
2981
2982                         if (r != 0)
2983                                 ret = r;
2984
2985                 } else {
2986
2987                         /* Interpret as PID */
2988
2989                         r = show_one_by_pid(args[0], bus, id, &new_line);
2990                         if (r != 0)
2991                                 ret = r;
2992                 }
2993         }
2994
2995         return ret;
2996 }
2997
2998 static int dump(DBusConnection *bus, char **args) {
2999         DBusMessage *reply = NULL;
3000         DBusError error;
3001         int r;
3002         const char *text;
3003
3004         dbus_error_init(&error);
3005
3006         pager_open_if_enabled();
3007
3008         r = bus_method_call_with_reply (
3009                         bus,
3010                         "org.freedesktop.systemd1",
3011                         "/org/freedesktop/systemd1",
3012                         "org.freedesktop.systemd1.Manager",
3013                         "Dump",
3014                         &reply,
3015                         NULL,
3016                         DBUS_TYPE_INVALID);
3017         if (r)
3018                 goto finish;
3019
3020         if (!dbus_message_get_args(reply, &error,
3021                                    DBUS_TYPE_STRING, &text,
3022                                    DBUS_TYPE_INVALID)) {
3023                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3024                 r = -EIO;
3025                 goto finish;
3026         }
3027
3028         fputs(text, stdout);
3029
3030 finish:
3031         if (reply)
3032                 dbus_message_unref(reply);
3033
3034         dbus_error_free(&error);
3035
3036         return r;
3037 }
3038
3039 static int snapshot(DBusConnection *bus, char **args) {
3040         DBusMessage *reply = NULL;
3041         DBusError error;
3042         int r;
3043         dbus_bool_t cleanup = FALSE;
3044         DBusMessageIter iter, sub;
3045         const char
3046                 *name = "", *path, *id,
3047                 *interface = "org.freedesktop.systemd1.Unit",
3048                 *property = "Id";
3049         char *n;
3050
3051         dbus_error_init(&error);
3052
3053         if (strv_length(args) > 1)
3054                 name = args[1];
3055
3056         n = unit_name_mangle(name);
3057         r = bus_method_call_with_reply (
3058                         bus,
3059                         "org.freedesktop.systemd1",
3060                         "/org/freedesktop/systemd1",
3061                         "org.freedesktop.systemd1.Manager",
3062                         "CreateSnapshot",
3063                         &reply,
3064                         NULL,
3065                         DBUS_TYPE_STRING, n ? (const char**) &n : &name,
3066                         DBUS_TYPE_BOOLEAN, &cleanup,
3067                         DBUS_TYPE_INVALID);
3068         free(n);
3069         if (r)
3070                 goto finish;
3071
3072         if (!dbus_message_get_args(reply, &error,
3073                                    DBUS_TYPE_OBJECT_PATH, &path,
3074                                    DBUS_TYPE_INVALID)) {
3075                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3076                 r = -EIO;
3077                 goto finish;
3078         }
3079
3080         dbus_message_unref(reply);
3081         r = bus_method_call_with_reply (
3082                         bus,
3083                         "org.freedesktop.systemd1",
3084                         path,
3085                         "org.freedesktop.DBus.Properties",
3086                         "Get",
3087                         &reply,
3088                         NULL,
3089                         DBUS_TYPE_STRING, &interface,
3090                         DBUS_TYPE_STRING, &property,
3091                         DBUS_TYPE_INVALID);
3092         if (r)
3093                 goto finish;
3094
3095         if (!dbus_message_iter_init(reply, &iter) ||
3096             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3097                 log_error("Failed to parse reply.");
3098                 r = -EIO;
3099                 goto finish;
3100         }
3101
3102         dbus_message_iter_recurse(&iter, &sub);
3103
3104         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3105                 log_error("Failed to parse reply.");
3106                 r = -EIO;
3107                 goto finish;
3108         }
3109
3110         dbus_message_iter_get_basic(&sub, &id);
3111
3112         if (!arg_quiet)
3113                 puts(id);
3114
3115 finish:
3116         if (reply)
3117                 dbus_message_unref(reply);
3118
3119         dbus_error_free(&error);
3120
3121         return r;
3122 }
3123
3124 static int delete_snapshot(DBusConnection *bus, char **args) {
3125         DBusMessage *reply = NULL;
3126         int r = 0;
3127         DBusError error;
3128         char **name;
3129
3130         assert(args);
3131
3132         dbus_error_init(&error);
3133
3134         STRV_FOREACH(name, args+1) {
3135                 const char *path = NULL;
3136                 char *n;
3137
3138                 n = unit_name_mangle(*name);
3139                 r = bus_method_call_with_reply (
3140                                 bus,
3141                                 "org.freedesktop.systemd1",
3142                                 "/org/freedesktop/systemd1",
3143                                 "org.freedesktop.systemd1.Manager",
3144                                 "GetUnit",
3145                                 &reply,
3146                                 NULL,
3147                                 DBUS_TYPE_STRING, n ? &n : name,
3148                                 DBUS_TYPE_INVALID);
3149                 free(n);
3150                 if (r)
3151                         goto finish;
3152
3153                 if (!dbus_message_get_args(reply, &error,
3154                                            DBUS_TYPE_OBJECT_PATH, &path,
3155                                            DBUS_TYPE_INVALID)) {
3156                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3157                         r = -EIO;
3158                         dbus_message_unref(reply);
3159                         dbus_error_free(&error);
3160                         goto finish;
3161                 }
3162                 dbus_message_unref(reply);
3163
3164                 r = bus_method_call_with_reply (
3165                                 bus,
3166                                 "org.freedesktop.systemd1",
3167                                 path,
3168                                 "org.freedesktop.systemd1.Snapshot",
3169                                 "Remove",
3170                                 NULL,
3171                                 NULL,
3172                                 DBUS_TYPE_INVALID);
3173                 if (r)
3174                         goto finish;
3175         }
3176
3177 finish:
3178         return r;
3179 }
3180
3181 static int daemon_reload(DBusConnection *bus, char **args) {
3182         int r;
3183         const char *method;
3184         DBusError error;
3185
3186         if (arg_action == ACTION_RELOAD)
3187                 method = "Reload";
3188         else if (arg_action == ACTION_REEXEC)
3189                 method = "Reexecute";
3190         else {
3191                 assert(arg_action == ACTION_SYSTEMCTL);
3192
3193                 method =
3194                         streq(args[0], "clear-jobs")    ||
3195                         streq(args[0], "cancel")        ? "ClearJobs" :
3196                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3197                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3198                         streq(args[0], "halt")          ? "Halt" :
3199                         streq(args[0], "poweroff")      ? "PowerOff" :
3200                         streq(args[0], "reboot")        ? "Reboot" :
3201                         streq(args[0], "kexec")         ? "KExec" :
3202                         streq(args[0], "exit")          ? "Exit" :
3203                                     /* "daemon-reload" */ "Reload";
3204         }
3205
3206         r = bus_method_call_with_reply (
3207                         bus,
3208                         "org.freedesktop.systemd1",
3209                         "/org/freedesktop/systemd1",
3210                         "org.freedesktop.systemd1.Manager",
3211                         method,
3212                         NULL,
3213                         &error,
3214                         DBUS_TYPE_INVALID);
3215
3216         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3217                 /* There's always a fallback possible for
3218                  * legacy actions. */
3219                 r = -EADDRNOTAVAIL;
3220         else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3221                 /* On reexecution, we expect a disconnect, not
3222                  * a reply */
3223                 r = 0;
3224         else if (r)
3225                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3226         dbus_error_free(&error);
3227
3228         return r;
3229 }
3230
3231 static int reset_failed(DBusConnection *bus, char **args) {
3232         int r = 0;
3233         char **name, *n;
3234
3235         if (strv_length(args) <= 1)
3236                 return daemon_reload(bus, args);
3237
3238         STRV_FOREACH(name, args+1) {
3239                 n = unit_name_mangle(*name);
3240                 r = bus_method_call_with_reply (
3241                                 bus,
3242                                 "org.freedesktop.systemd1",
3243                                 "/org/freedesktop/systemd1",
3244                                 "org.freedesktop.systemd1.Manager",
3245                                 "ResetFailedUnit",
3246                                 NULL,
3247                                 NULL,
3248                                 DBUS_TYPE_STRING, n ? &n : name,
3249                                 DBUS_TYPE_INVALID);
3250                 free(n);
3251                 if (r)
3252                         goto finish;
3253         }
3254
3255 finish:
3256         return r;
3257 }
3258
3259 static int show_enviroment(DBusConnection *bus, char **args) {
3260         DBusMessage *reply = NULL;
3261         DBusMessageIter iter, sub, sub2;
3262         int r;
3263         const char
3264                 *interface = "org.freedesktop.systemd1.Manager",
3265                 *property = "Environment";
3266
3267         pager_open_if_enabled();
3268
3269         r = bus_method_call_with_reply (
3270                         bus,
3271                         "org.freedesktop.systemd1",
3272                         "/org/freedesktop/systemd1",
3273                         "org.freedesktop.DBus.Properties",
3274                         "Get",
3275                         &reply,
3276                         NULL,
3277                         DBUS_TYPE_STRING, &interface,
3278                         DBUS_TYPE_STRING, &property,
3279                         DBUS_TYPE_INVALID);
3280         if (r)
3281                 goto finish;
3282
3283         if (!dbus_message_iter_init(reply, &iter) ||
3284             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3285                 log_error("Failed to parse reply.");
3286                 r = -EIO;
3287                 goto finish;
3288         }
3289
3290         dbus_message_iter_recurse(&iter, &sub);
3291
3292         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3293             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3294                 log_error("Failed to parse reply.");
3295                 r = -EIO;
3296                 goto finish;
3297         }
3298
3299         dbus_message_iter_recurse(&sub, &sub2);
3300
3301         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3302                 const char *text;
3303
3304                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3305                         log_error("Failed to parse reply.");
3306                         r = -EIO;
3307                         goto finish;
3308                 }
3309
3310                 dbus_message_iter_get_basic(&sub2, &text);
3311                 printf("%s\n", text);
3312
3313                 dbus_message_iter_next(&sub2);
3314         }
3315
3316         r = 0;
3317
3318 finish:
3319         if (reply)
3320                 dbus_message_unref(reply);
3321
3322         return r;
3323 }
3324
3325 static int switch_root(DBusConnection *bus, char **args) {
3326         unsigned l;
3327         const char *root, *init;
3328
3329         l = strv_length(args);
3330         if (l < 2 || l > 3) {
3331                 log_error("Wrong number of arguments.");
3332                 return -EINVAL;
3333         }
3334
3335         root = args[1];
3336         init = l >= 3 ? args[2] : "";
3337
3338         return bus_method_call_with_reply (
3339                         bus,
3340                         "org.freedesktop.systemd1",
3341                         "/org/freedesktop/systemd1",
3342                         "org.freedesktop.systemd1.Manager",
3343                         "SwitchRoot",
3344                         NULL,
3345                         NULL,
3346                         DBUS_TYPE_STRING, &root,
3347                         DBUS_TYPE_STRING, &init,
3348                         DBUS_TYPE_INVALID);
3349 }
3350
3351 static int set_environment(DBusConnection *bus, char **args) {
3352         DBusMessage *m = NULL, *reply = NULL;
3353         DBusError error;
3354         int r;
3355         const char *method;
3356         DBusMessageIter iter, sub;
3357         char **name;
3358
3359         dbus_error_init(&error);
3360
3361         method = streq(args[0], "set-environment")
3362                 ? "SetEnvironment"
3363                 : "UnsetEnvironment";
3364
3365         if (!(m = dbus_message_new_method_call(
3366                               "org.freedesktop.systemd1",
3367                               "/org/freedesktop/systemd1",
3368                               "org.freedesktop.systemd1.Manager",
3369                               method))) {
3370
3371                 log_error("Could not allocate message.");
3372                 return -ENOMEM;
3373         }
3374
3375         dbus_message_iter_init_append(m, &iter);
3376
3377         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3378                 log_error("Could not append arguments to message.");
3379                 r = -ENOMEM;
3380                 goto finish;
3381         }
3382
3383         STRV_FOREACH(name, args+1)
3384                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3385                         log_error("Could not append arguments to message.");
3386                         r = -ENOMEM;
3387                         goto finish;
3388                 }
3389
3390         if (!dbus_message_iter_close_container(&iter, &sub)) {
3391                 log_error("Could not append arguments to message.");
3392                 r = -ENOMEM;
3393                 goto finish;
3394         }
3395
3396         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3397                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3398                 r = -EIO;
3399                 goto finish;
3400         }
3401
3402         r = 0;
3403
3404 finish:
3405         if (m)
3406                 dbus_message_unref(m);
3407
3408         if (reply)
3409                 dbus_message_unref(reply);
3410
3411         dbus_error_free(&error);
3412
3413         return r;
3414 }
3415
3416 static int enable_sysv_units(char **args) {
3417         int r = 0;
3418
3419 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3420         const char *verb = args[0];
3421         unsigned f = 1, t = 1;
3422         LookupPaths paths;
3423
3424         if (arg_scope != UNIT_FILE_SYSTEM)
3425                 return 0;
3426
3427         if (!streq(verb, "enable") &&
3428             !streq(verb, "disable") &&
3429             !streq(verb, "is-enabled"))
3430                 return 0;
3431
3432         /* Processes all SysV units, and reshuffles the array so that
3433          * afterwards only the native units remain */
3434
3435         zero(paths);
3436         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
3437         if (r < 0)
3438                 return r;
3439
3440         r = 0;
3441         for (f = 1; args[f]; f++) {
3442                 const char *name;
3443                 char *p;
3444                 bool found_native = false, found_sysv;
3445                 unsigned c = 1;
3446                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3447                 char **k, *l, *q = NULL;
3448                 int j;
3449                 pid_t pid;
3450                 siginfo_t status;
3451
3452                 name = args[f];
3453
3454                 if (!endswith(name, ".service"))
3455                         continue;
3456
3457                 if (path_is_absolute(name))
3458                         continue;
3459
3460                 STRV_FOREACH(k, paths.unit_path) {
3461                         p = NULL;
3462
3463                         if (!isempty(arg_root))
3464                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3465                         else
3466                                 asprintf(&p, "%s/%s", *k, name);
3467
3468                         if (!p) {
3469                                 r = log_oom();
3470                                 goto finish;
3471                         }
3472
3473                         found_native = access(p, F_OK) >= 0;
3474                         free(p);
3475
3476                         if (found_native)
3477                                 break;
3478                 }
3479
3480                 if (found_native)
3481                         continue;
3482
3483                 p = NULL;
3484                 if (!isempty(arg_root))
3485                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3486                 else
3487                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3488                 if (!p) {
3489                         r = log_oom();
3490                         goto finish;
3491                 }
3492
3493                 p[strlen(p) - sizeof(".service") + 1] = 0;
3494                 found_sysv = access(p, F_OK) >= 0;
3495
3496                 if (!found_sysv) {
3497                         free(p);
3498                         continue;
3499                 }
3500
3501                 /* Mark this entry, so that we don't try enabling it as native unit */
3502                 args[f] = (char*) "";
3503
3504                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3505
3506                 if (!isempty(arg_root))
3507                         argv[c++] = q = strappend("--root=", arg_root);
3508
3509                 argv[c++] = path_get_file_name(p);
3510                 argv[c++] =
3511                         streq(verb, "enable") ? "on" :
3512                         streq(verb, "disable") ? "off" : "--level=5";
3513                 argv[c] = NULL;
3514
3515                 l = strv_join((char**)argv, " ");
3516                 if (!l) {
3517                         free(q);
3518                         free(p);
3519                         r = log_oom();
3520                         goto finish;
3521                 }
3522
3523                 log_info("Executing %s", l);
3524                 free(l);
3525
3526                 pid = fork();
3527                 if (pid < 0) {
3528                         log_error("Failed to fork: %m");
3529                         free(p);
3530                         free(q);
3531                         r = -errno;
3532                         goto finish;
3533                 } else if (pid == 0) {
3534                         /* Child */
3535
3536                         execv(argv[0], (char**) argv);
3537                         _exit(EXIT_FAILURE);
3538                 }
3539
3540                 free(p);
3541                 free(q);
3542
3543                 j = wait_for_terminate(pid, &status);
3544                 if (j < 0) {
3545                         log_error("Failed to wait for child: %s", strerror(-r));
3546                         r = j;
3547                         goto finish;
3548                 }
3549
3550                 if (status.si_code == CLD_EXITED) {
3551                         if (streq(verb, "is-enabled")) {
3552                                 if (status.si_status == 0) {
3553                                         if (!arg_quiet)
3554                                                 puts("enabled");
3555                                         r = 1;
3556                                 } else {
3557                                         if (!arg_quiet)
3558                                                 puts("disabled");
3559                                 }
3560
3561                         } else if (status.si_status != 0) {
3562                                 r = -EINVAL;
3563                                 goto finish;
3564                         }
3565                 } else {
3566                         r = -EPROTO;
3567                         goto finish;
3568                 }
3569         }
3570
3571 finish:
3572         lookup_paths_free(&paths);
3573
3574         /* Drop all SysV units */
3575         for (f = 1, t = 1; args[f]; f++) {
3576
3577                 if (isempty(args[f]))
3578                         continue;
3579
3580                 args[t++] = args[f];
3581         }
3582
3583         args[t] = NULL;
3584
3585 #endif
3586         return r;
3587 }
3588
3589 static int mangle_names(char **original_names, char ***mangled_names) {
3590         char **i, **l, **name;
3591
3592         l = new(char*, strv_length(original_names) + 1);
3593         if (!l)
3594                 return log_oom();
3595
3596         i = l;
3597         STRV_FOREACH(name, original_names) {
3598
3599                 /* When enabling units qualified path names are OK,
3600                  * too, hence allow them explicitly. */
3601
3602                 if (is_path(*name))
3603                         *i = strdup(*name);
3604                 else
3605                         *i = unit_name_mangle(*name);
3606
3607                 if (!*i) {
3608                         strv_free(l);
3609                         return log_oom();
3610                 }
3611
3612                 i++;
3613         }
3614
3615         *i = NULL;
3616         *mangled_names = l;
3617
3618         return 0;
3619 }
3620
3621 static int enable_unit(DBusConnection *bus, char **args) {
3622         const char *verb = args[0];
3623         UnitFileChange *changes = NULL;
3624         unsigned n_changes = 0, i;
3625         int carries_install_info = -1;
3626         DBusMessage *m = NULL, *reply = NULL;
3627         int r;
3628         DBusError error;
3629         char **mangled_names = NULL;
3630
3631         r = enable_sysv_units(args);
3632         if (r < 0)
3633                 return r;
3634
3635         if (!args[1])
3636                 return 0;
3637
3638         dbus_error_init(&error);
3639
3640         if (!bus || avoid_bus()) {
3641                 if (streq(verb, "enable")) {
3642                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3643                         carries_install_info = r;
3644                 } else if (streq(verb, "disable"))
3645                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3646                 else if (streq(verb, "reenable")) {
3647                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3648                         carries_install_info = r;
3649                 } else if (streq(verb, "link"))
3650                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3651                 else if (streq(verb, "preset")) {
3652                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3653                         carries_install_info = r;
3654                 } else if (streq(verb, "mask"))
3655                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3656                 else if (streq(verb, "unmask"))
3657                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3658                 else
3659                         assert_not_reached("Unknown verb");
3660
3661                 if (r < 0) {
3662                         log_error("Operation failed: %s", strerror(-r));
3663                         goto finish;
3664                 }
3665
3666                 if (!arg_quiet) {
3667                         for (i = 0; i < n_changes; i++) {
3668                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3669                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3670                                 else
3671                                         log_info("rm '%s'", changes[i].path);
3672                         }
3673                 }
3674
3675         } else {
3676                 const char *method;
3677                 bool send_force = true, expect_carries_install_info = false;
3678                 dbus_bool_t a, b;
3679                 DBusMessageIter iter, sub, sub2;
3680
3681                 if (streq(verb, "enable")) {
3682                         method = "EnableUnitFiles";
3683                         expect_carries_install_info = true;
3684                 } else if (streq(verb, "disable")) {
3685                         method = "DisableUnitFiles";
3686                         send_force = false;
3687                 } else if (streq(verb, "reenable")) {
3688                         method = "ReenableUnitFiles";
3689                         expect_carries_install_info = true;
3690                 } else if (streq(verb, "link"))
3691                         method = "LinkUnitFiles";
3692                 else if (streq(verb, "preset")) {
3693                         method = "PresetUnitFiles";
3694                         expect_carries_install_info = true;
3695                 } else if (streq(verb, "mask"))
3696                         method = "MaskUnitFiles";
3697                 else if (streq(verb, "unmask")) {
3698                         method = "UnmaskUnitFiles";
3699                         send_force = false;
3700                 } else
3701                         assert_not_reached("Unknown verb");
3702
3703                 m = dbus_message_new_method_call(
3704                                 "org.freedesktop.systemd1",
3705                                 "/org/freedesktop/systemd1",
3706                                 "org.freedesktop.systemd1.Manager",
3707                                 method);
3708                 if (!m) {
3709                         r = log_oom();
3710                         goto finish;
3711                 }
3712
3713                 dbus_message_iter_init_append(m, &iter);
3714
3715                 r = mangle_names(args+1, &mangled_names);
3716                 if(r < 0)
3717                         goto finish;
3718
3719                 r = bus_append_strv_iter(&iter, mangled_names);
3720                 if (r < 0) {
3721                         log_error("Failed to append unit files.");
3722                         goto finish;
3723                 }
3724
3725                 a = arg_runtime;
3726                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3727                         log_error("Failed to append runtime boolean.");
3728                         r = -ENOMEM;
3729                         goto finish;
3730                 }
3731
3732                 if (send_force) {
3733                         b = arg_force;
3734
3735                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3736                                 log_error("Failed to append force boolean.");
3737                                 r = -ENOMEM;
3738                                 goto finish;
3739                         }
3740                 }
3741
3742                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3743                 if (!reply) {
3744                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3745                         r = -EIO;
3746                         goto finish;
3747                 }
3748
3749                 if (!dbus_message_iter_init(reply, &iter)) {
3750                         log_error("Failed to initialize iterator.");
3751                         goto finish;
3752                 }
3753
3754                 if (expect_carries_install_info) {
3755                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3756                         if (r < 0) {
3757                                 log_error("Failed to parse reply.");
3758                                 goto finish;
3759                         }
3760
3761                         carries_install_info = b;
3762                 }
3763
3764                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3765                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3766                         log_error("Failed to parse reply.");
3767                         r = -EIO;
3768                         goto finish;
3769                 }
3770
3771                 dbus_message_iter_recurse(&iter, &sub);
3772                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3773                         const char *type, *path, *source;
3774
3775                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3776                                 log_error("Failed to parse reply.");
3777                                 r = -EIO;
3778                                 goto finish;
3779                         }
3780
3781                         dbus_message_iter_recurse(&sub, &sub2);
3782
3783                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3784                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3785                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3786                                 log_error("Failed to parse reply.");
3787                                 r = -EIO;
3788                                 goto finish;
3789                         }
3790
3791                         if (!arg_quiet) {
3792                                 if (streq(type, "symlink"))
3793                                         log_info("ln -s '%s' '%s'", source, path);
3794                                 else
3795                                         log_info("rm '%s'", path);
3796                         }
3797
3798                         dbus_message_iter_next(&sub);
3799                 }
3800
3801                 /* Try to reload if enabeld */
3802                 if (!arg_no_reload)
3803                         r = daemon_reload(bus, args);
3804         }
3805
3806         if (carries_install_info == 0)
3807                 log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
3808
3809 finish:
3810         if (m)
3811                 dbus_message_unref(m);
3812
3813         if (reply)
3814                 dbus_message_unref(reply);
3815
3816         unit_file_changes_free(changes, n_changes);
3817
3818         dbus_error_free(&error);
3819
3820         strv_free(mangled_names);
3821
3822         return r;
3823 }
3824
3825 static int unit_is_enabled(DBusConnection *bus, char **args) {
3826         DBusError error;
3827         int r;
3828         DBusMessage *reply = NULL;
3829         bool enabled;
3830         char **name;
3831
3832         dbus_error_init(&error);
3833
3834         r = enable_sysv_units(args);
3835         if (r < 0)
3836                 return r;
3837
3838         enabled = r > 0;
3839
3840         if (!bus || avoid_bus()) {
3841
3842                 STRV_FOREACH(name, args+1) {
3843                         UnitFileState state;
3844
3845                         state = unit_file_get_state(arg_scope, arg_root, *name);
3846                         if (state < 0) {
3847                                 r = state;
3848                                 goto finish;
3849                         }
3850
3851                         if (state == UNIT_FILE_ENABLED ||
3852                             state == UNIT_FILE_ENABLED_RUNTIME ||
3853                             state == UNIT_FILE_STATIC)
3854                                 enabled = true;
3855
3856                         if (!arg_quiet)
3857                                 puts(unit_file_state_to_string(state));
3858                 }
3859
3860         } else {
3861                 STRV_FOREACH(name, args+1) {
3862                         const char *s;
3863
3864                         r = bus_method_call_with_reply (
3865                                         bus,
3866                                         "org.freedesktop.systemd1",
3867                                         "/org/freedesktop/systemd1",
3868                                         "org.freedesktop.systemd1.Manager",
3869                                         "GetUnitFileState",
3870                                         &reply,
3871                                         NULL,
3872                                         DBUS_TYPE_STRING, name,
3873                                         DBUS_TYPE_INVALID);
3874                         if (r)
3875                                 goto finish;
3876
3877                         if (!dbus_message_get_args(reply, &error,
3878                                                    DBUS_TYPE_STRING, &s,
3879                                                    DBUS_TYPE_INVALID)) {
3880                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3881                                 r = -EIO;
3882                                 goto finish;
3883                         }
3884
3885                         dbus_message_unref(reply);
3886                         reply = NULL;
3887
3888                         if (streq(s, "enabled") ||
3889                             streq(s, "enabled-runtime") ||
3890                             streq(s, "static"))
3891                                 enabled = true;
3892
3893                         if (!arg_quiet)
3894                                 puts(s);
3895                 }
3896         }
3897
3898         r = enabled ? 0 : 1;
3899
3900 finish:
3901         if (reply)
3902                 dbus_message_unref(reply);
3903
3904         dbus_error_free(&error);
3905         return r;
3906 }
3907
3908 static int systemctl_help(void) {
3909
3910         pager_open_if_enabled();
3911
3912         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3913                "Query or send control commands to the systemd manager.\n\n"
3914                "  -h --help           Show this help\n"
3915                "     --version        Show package version\n"
3916                "  -t --type=TYPE      List only units of a particular type\n"
3917                "  -p --property=NAME  Show only properties by this name\n"
3918                "  -a --all            Show all units/properties, including dead/empty ones\n"
3919                "     --failed         Show only failed units\n"
3920                "     --full           Don't ellipsize unit names on output\n"
3921                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
3922                "                      pending\n"
3923                "     --ignore-dependencies\n"
3924                "                      When queueing a new job, ignore all its dependencies\n"
3925                "     --kill-who=WHO   Who to send signal to\n"
3926                "  -s --signal=SIGNAL  Which signal to send\n"
3927                "  -H --host=[USER@]HOST\n"
3928                "                      Show information for remote host\n"
3929                "  -P --privileged     Acquire privileges before execution\n"
3930                "  -q --quiet          Suppress output\n"
3931                "     --no-block       Do not wait until operation finished\n"
3932                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
3933                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
3934                "                      configuration\n"
3935                "     --no-legend      Do not print a legend (column headers and hints)\n"
3936                "     --no-pager       Do not pipe output into a pager\n"
3937                "     --no-ask-password\n"
3938                "                      Do not ask for system passwords\n"
3939                "     --order          When generating graph for dot, show only order\n"
3940                "     --require        When generating graph for dot, show only requirement\n"
3941                "     --system         Connect to system manager\n"
3942                "     --user           Connect to user service manager\n"
3943                "     --global         Enable/disable unit files globally\n"
3944                "  -f --force          When enabling unit files, override existing symlinks\n"
3945                "                      When shutting down, execute action immediately\n"
3946                "     --root=PATH      Enable unit files in the specified root directory\n"
3947                "     --runtime        Enable unit files only temporarily until next reboot\n"
3948                "  -n --lines=INTEGER  Journal entries to show\n"
3949                "     --follow         Follow journal\n"
3950                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
3951                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
3952                "Unit Commands:\n"
3953                "  list-units                      List loaded units\n"
3954                "  start [NAME...]                 Start (activate) one or more units\n"
3955                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
3956                "  reload [NAME...]                Reload one or more units\n"
3957                "  restart [NAME...]               Start or restart one or more units\n"
3958                "  try-restart [NAME...]           Restart one or more units if active\n"
3959                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
3960                "                                  otherwise start or restart\n"
3961                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
3962                "                                  otherwise restart if active\n"
3963                "  isolate [NAME]                  Start one unit and stop all others\n"
3964                "  kill [NAME...]                  Send signal to processes of a unit\n"
3965                "  is-active [NAME...]             Check whether units are active\n"
3966                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
3967                "  show [NAME...|JOB...]           Show properties of one or more\n"
3968                "                                  units/jobs or the manager\n"
3969                "  help [NAME...|PID...]            Show manual for one or more units\n"
3970                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
3971                "                                  units\n"
3972                "  load [NAME...]                  Load one or more units\n\n"
3973                "Unit File Commands:\n"
3974                "  list-unit-files                 List installed unit files\n"
3975                "  enable [NAME...]                Enable one or more unit files\n"
3976                "  disable [NAME...]               Disable one or more unit files\n"
3977                "  reenable [NAME...]              Reenable one or more unit files\n"
3978                "  preset [NAME...]                Enable/disable one or more unit files\n"
3979                "                                  based on preset configuration\n"
3980                "  mask [NAME...]                  Mask one or more units\n"
3981                "  unmask [NAME...]                Unmask one or more units\n"
3982                "  link [PATH...]                  Link one or more units files into\n"
3983                "                                  the search path\n"
3984                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
3985                "Job Commands:\n"
3986                "  list-jobs                       List jobs\n"
3987                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
3988                "Status Commands:\n"
3989                "  dump                            Dump server status\n"
3990                "  dot                             Dump dependency graph for dot(1)\n\n"
3991                "Snapshot Commands:\n"
3992                "  snapshot [NAME]                 Create a snapshot\n"
3993                "  delete [NAME...]                Remove one or more snapshots\n\n"
3994                "Environment Commands:\n"
3995                "  show-environment                Dump environment\n"
3996                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
3997                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
3998                "Manager Lifecycle Commands:\n"
3999                "  daemon-reload                   Reload systemd manager configuration\n"
4000                "  daemon-reexec                   Reexecute systemd manager\n\n"
4001                "System Commands:\n"
4002                "  default                         Enter system default mode\n"
4003                "  rescue                          Enter system rescue mode\n"
4004                "  emergency                       Enter system emergency mode\n"
4005                "  halt                            Shut down and halt the system\n"
4006                "  poweroff                        Shut down and power-off the system\n"
4007                "  reboot                          Shut down and reboot the system\n"
4008                "  kexec                           Shut down and reboot the system with kexec\n"
4009                "  exit                            Request user instance exit\n"
4010                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4011                "  suspend                         Suspend the system\n"
4012                "  hibernate                       Hibernate the system\n",
4013                program_invocation_short_name);
4014
4015         return 0;
4016 }
4017
4018 static int halt_help(void) {
4019
4020         printf("%s [OPTIONS...]\n\n"
4021                "%s the system.\n\n"
4022                "     --help      Show this help\n"
4023                "     --halt      Halt the machine\n"
4024                "  -p --poweroff  Switch off the machine\n"
4025                "     --reboot    Reboot the machine\n"
4026                "  -f --force     Force immediate halt/power-off/reboot\n"
4027                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4028                "  -d --no-wtmp   Don't write wtmp record\n"
4029                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4030                program_invocation_short_name,
4031                arg_action == ACTION_REBOOT   ? "Reboot" :
4032                arg_action == ACTION_POWEROFF ? "Power off" :
4033                                                "Halt");
4034
4035         return 0;
4036 }
4037
4038 static int shutdown_help(void) {
4039
4040         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4041                "Shut down the system.\n\n"
4042                "     --help      Show this help\n"
4043                "  -H --halt      Halt the machine\n"
4044                "  -P --poweroff  Power-off the machine\n"
4045                "  -r --reboot    Reboot the machine\n"
4046                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4047                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4048                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4049                "  -c             Cancel a pending shutdown\n",
4050                program_invocation_short_name);
4051
4052         return 0;
4053 }
4054
4055 static int telinit_help(void) {
4056
4057         printf("%s [OPTIONS...] {COMMAND}\n\n"
4058                "Send control commands to the init daemon.\n\n"
4059                "     --help      Show this help\n"
4060                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4061                "Commands:\n"
4062                "  0              Power-off the machine\n"
4063                "  6              Reboot the machine\n"
4064                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4065                "  1, s, S        Enter rescue mode\n"
4066                "  q, Q           Reload init daemon configuration\n"
4067                "  u, U           Reexecute init daemon\n",
4068                program_invocation_short_name);
4069
4070         return 0;
4071 }
4072
4073 static int runlevel_help(void) {
4074
4075         printf("%s [OPTIONS...]\n\n"
4076                "Prints the previous and current runlevel of the init system.\n\n"
4077                "     --help      Show this help\n",
4078                program_invocation_short_name);
4079
4080         return 0;
4081 }
4082
4083 static int systemctl_parse_argv(int argc, char *argv[]) {
4084
4085         enum {
4086                 ARG_FAIL = 0x100,
4087                 ARG_IGNORE_DEPENDENCIES,
4088                 ARG_VERSION,
4089                 ARG_USER,
4090                 ARG_SYSTEM,
4091                 ARG_GLOBAL,
4092                 ARG_NO_BLOCK,
4093                 ARG_NO_LEGEND,
4094                 ARG_NO_PAGER,
4095                 ARG_NO_WALL,
4096                 ARG_ORDER,
4097                 ARG_REQUIRE,
4098                 ARG_ROOT,
4099                 ARG_FULL,
4100                 ARG_NO_RELOAD,
4101                 ARG_KILL_WHO,
4102                 ARG_NO_ASK_PASSWORD,
4103                 ARG_FAILED,
4104                 ARG_RUNTIME,
4105                 ARG_FOLLOW,
4106                 ARG_FORCE
4107         };
4108
4109         static const struct option options[] = {
4110                 { "help",      no_argument,       NULL, 'h'           },
4111                 { "version",   no_argument,       NULL, ARG_VERSION   },
4112                 { "type",      required_argument, NULL, 't'           },
4113                 { "property",  required_argument, NULL, 'p'           },
4114                 { "all",       no_argument,       NULL, 'a'           },
4115                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4116                 { "full",      no_argument,       NULL, ARG_FULL      },
4117                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4118                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4119                 { "user",      no_argument,       NULL, ARG_USER      },
4120                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4121                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4122                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4123                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4124                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4125                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4126                 { "quiet",     no_argument,       NULL, 'q'           },
4127                 { "order",     no_argument,       NULL, ARG_ORDER     },
4128                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4129                 { "root",      required_argument, NULL, ARG_ROOT      },
4130                 { "force",     no_argument,       NULL, ARG_FORCE     },
4131                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4132                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4133                 { "signal",    required_argument, NULL, 's'           },
4134                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4135                 { "host",      required_argument, NULL, 'H'           },
4136                 { "privileged",no_argument,       NULL, 'P'           },
4137                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4138                 { "lines",     required_argument, NULL, 'n'           },
4139                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4140                 { "output",    required_argument, NULL, 'o'           },
4141                 { NULL,        0,                 NULL, 0             }
4142         };
4143
4144         int c;
4145
4146         assert(argc >= 0);
4147         assert(argv);
4148
4149         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4150
4151                 switch (c) {
4152
4153                 case 'h':
4154                         systemctl_help();
4155                         return 0;
4156
4157                 case ARG_VERSION:
4158                         puts(PACKAGE_STRING);
4159                         puts(DISTRIBUTION);
4160                         puts(SYSTEMD_FEATURES);
4161                         return 0;
4162
4163                 case 't':
4164                         if (unit_type_from_string(optarg) >= 0) {
4165                                 arg_type = optarg;
4166                                 break;
4167                         }
4168                         if (unit_load_state_from_string(optarg) >= 0) {
4169                                 arg_load_state = optarg;
4170                                 break;
4171                         }
4172                         log_error("Unkown unit type or load state '%s'.",
4173                                   optarg);
4174                         return -EINVAL;
4175                 case 'p': {
4176                         char **l;
4177
4178                         if (!(l = strv_append(arg_property, optarg)))
4179                                 return -ENOMEM;
4180
4181                         strv_free(arg_property);
4182                         arg_property = l;
4183
4184                         /* If the user asked for a particular
4185                          * property, show it to him, even if it is
4186                          * empty. */
4187                         arg_all = true;
4188                         break;
4189                 }
4190
4191                 case 'a':
4192                         arg_all = true;
4193                         break;
4194
4195                 case ARG_FAIL:
4196                         arg_job_mode = "fail";
4197                         break;
4198
4199                 case ARG_IGNORE_DEPENDENCIES:
4200                         arg_job_mode = "ignore-dependencies";
4201                         break;
4202
4203                 case ARG_USER:
4204                         arg_scope = UNIT_FILE_USER;
4205                         break;
4206
4207                 case ARG_SYSTEM:
4208                         arg_scope = UNIT_FILE_SYSTEM;
4209                         break;
4210
4211                 case ARG_GLOBAL:
4212                         arg_scope = UNIT_FILE_GLOBAL;
4213                         break;
4214
4215                 case ARG_NO_BLOCK:
4216                         arg_no_block = true;
4217                         break;
4218
4219                 case ARG_NO_LEGEND:
4220                         arg_no_legend = true;
4221                         break;
4222
4223                 case ARG_NO_PAGER:
4224                         arg_no_pager = true;
4225                         break;
4226
4227                 case ARG_NO_WALL:
4228                         arg_no_wall = true;
4229                         break;
4230
4231                 case ARG_ORDER:
4232                         arg_dot = DOT_ORDER;
4233                         break;
4234
4235                 case ARG_REQUIRE:
4236                         arg_dot = DOT_REQUIRE;
4237                         break;
4238
4239                 case ARG_ROOT:
4240                         arg_root = optarg;
4241                         break;
4242
4243                 case ARG_FULL:
4244                         arg_full = true;
4245                         break;
4246
4247                 case ARG_FAILED:
4248                         arg_failed = true;
4249                         break;
4250
4251                 case 'q':
4252                         arg_quiet = true;
4253                         break;
4254
4255                 case ARG_FORCE:
4256                         arg_force ++;
4257                         break;
4258
4259                 case ARG_FOLLOW:
4260                         arg_follow = true;
4261                         break;
4262
4263                 case 'f':
4264                         /* -f is short for both --follow and --force! */
4265                         arg_force ++;
4266                         arg_follow = true;
4267                         break;
4268
4269                 case ARG_NO_RELOAD:
4270                         arg_no_reload = true;
4271                         break;
4272
4273                 case ARG_KILL_WHO:
4274                         arg_kill_who = optarg;
4275                         break;
4276
4277                 case 's':
4278                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4279                                 log_error("Failed to parse signal string %s.", optarg);
4280                                 return -EINVAL;
4281                         }
4282                         break;
4283
4284                 case ARG_NO_ASK_PASSWORD:
4285                         arg_ask_password = false;
4286                         break;
4287
4288                 case 'P':
4289                         arg_transport = TRANSPORT_POLKIT;
4290                         break;
4291
4292                 case 'H':
4293                         arg_transport = TRANSPORT_SSH;
4294                         arg_host = optarg;
4295                         break;
4296
4297                 case ARG_RUNTIME:
4298                         arg_runtime = true;
4299                         break;
4300
4301                 case 'n':
4302                         if (safe_atou(optarg, &arg_lines) < 0) {
4303                                 log_error("Failed to parse lines '%s'", optarg);
4304                                 return -EINVAL;
4305                         }
4306                         break;
4307
4308                 case 'o':
4309                         arg_output = output_mode_from_string(optarg);
4310                         if (arg_output < 0) {
4311                                 log_error("Unknown output '%s'.", optarg);
4312                                 return -EINVAL;
4313                         }
4314                         break;
4315
4316                 case '?':
4317                         return -EINVAL;
4318
4319                 default:
4320                         log_error("Unknown option code '%c'.", c);
4321                         return -EINVAL;
4322                 }
4323         }
4324
4325         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4326                 log_error("Cannot access user instance remotely.");
4327                 return -EINVAL;
4328         }
4329
4330         return 1;
4331 }
4332
4333 static int halt_parse_argv(int argc, char *argv[]) {
4334
4335         enum {
4336                 ARG_HELP = 0x100,
4337                 ARG_HALT,
4338                 ARG_REBOOT,
4339                 ARG_NO_WALL
4340         };
4341
4342         static const struct option options[] = {
4343                 { "help",      no_argument,       NULL, ARG_HELP    },
4344                 { "halt",      no_argument,       NULL, ARG_HALT    },
4345                 { "poweroff",  no_argument,       NULL, 'p'         },
4346                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4347                 { "force",     no_argument,       NULL, 'f'         },
4348                 { "wtmp-only", no_argument,       NULL, 'w'         },
4349                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4350                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4351                 { NULL,        0,                 NULL, 0           }
4352         };
4353
4354         int c, runlevel;
4355
4356         assert(argc >= 0);
4357         assert(argv);
4358
4359         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4360                 if (runlevel == '0' || runlevel == '6')
4361                         arg_force = 2;
4362
4363         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4364                 switch (c) {
4365
4366                 case ARG_HELP:
4367                         halt_help();
4368                         return 0;
4369
4370                 case ARG_HALT:
4371                         arg_action = ACTION_HALT;
4372                         break;
4373
4374                 case 'p':
4375                         if (arg_action != ACTION_REBOOT)
4376                                 arg_action = ACTION_POWEROFF;
4377                         break;
4378
4379                 case ARG_REBOOT:
4380                         arg_action = ACTION_REBOOT;
4381                         break;
4382
4383                 case 'f':
4384                         arg_force = 2;
4385                         break;
4386
4387                 case 'w':
4388                         arg_dry = true;
4389                         break;
4390
4391                 case 'd':
4392                         arg_no_wtmp = true;
4393                         break;
4394
4395                 case ARG_NO_WALL:
4396                         arg_no_wall = true;
4397                         break;
4398
4399                 case 'i':
4400                 case 'h':
4401                 case 'n':
4402                         /* Compatibility nops */
4403                         break;
4404
4405                 case '?':
4406                         return -EINVAL;
4407
4408                 default:
4409                         log_error("Unknown option code '%c'.", c);
4410                         return -EINVAL;
4411                 }
4412         }
4413
4414         if (optind < argc) {
4415                 log_error("Too many arguments.");
4416                 return -EINVAL;
4417         }
4418
4419         return 1;
4420 }
4421
4422 static int parse_time_spec(const char *t, usec_t *_u) {
4423         assert(t);
4424         assert(_u);
4425
4426         if (streq(t, "now"))
4427                 *_u = 0;
4428         else if (!strchr(t, ':')) {
4429                 uint64_t u;
4430
4431                 if (safe_atou64(t, &u) < 0)
4432                         return -EINVAL;
4433
4434                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4435         } else {
4436                 char *e = NULL;
4437                 long hour, minute;
4438                 struct tm tm;
4439                 time_t s;
4440                 usec_t n;
4441
4442                 errno = 0;
4443                 hour = strtol(t, &e, 10);
4444                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4445                         return -EINVAL;
4446
4447                 minute = strtol(e+1, &e, 10);
4448                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4449                         return -EINVAL;
4450
4451                 n = now(CLOCK_REALTIME);
4452                 s = (time_t) (n / USEC_PER_SEC);
4453
4454                 zero(tm);
4455                 assert_se(localtime_r(&s, &tm));
4456
4457                 tm.tm_hour = (int) hour;
4458                 tm.tm_min = (int) minute;
4459                 tm.tm_sec = 0;
4460
4461                 assert_se(s = mktime(&tm));
4462
4463                 *_u = (usec_t) s * USEC_PER_SEC;
4464
4465                 while (*_u <= n)
4466                         *_u += USEC_PER_DAY;
4467         }
4468
4469         return 0;
4470 }
4471
4472 static int shutdown_parse_argv(int argc, char *argv[]) {
4473
4474         enum {
4475                 ARG_HELP = 0x100,
4476                 ARG_NO_WALL
4477         };
4478
4479         static const struct option options[] = {
4480                 { "help",      no_argument,       NULL, ARG_HELP    },
4481                 { "halt",      no_argument,       NULL, 'H'         },
4482                 { "poweroff",  no_argument,       NULL, 'P'         },
4483                 { "reboot",    no_argument,       NULL, 'r'         },
4484                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4485                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4486                 { NULL,        0,                 NULL, 0           }
4487         };
4488
4489         int c, r;
4490
4491         assert(argc >= 0);
4492         assert(argv);
4493
4494         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4495                 switch (c) {
4496
4497                 case ARG_HELP:
4498                         shutdown_help();
4499                         return 0;
4500
4501                 case 'H':
4502                         arg_action = ACTION_HALT;
4503                         break;
4504
4505                 case 'P':
4506                         arg_action = ACTION_POWEROFF;
4507                         break;
4508
4509                 case 'r':
4510                         if (kexec_loaded())
4511                                 arg_action = ACTION_KEXEC;
4512                         else
4513                                 arg_action = ACTION_REBOOT;
4514                         break;
4515
4516                 case 'K':
4517                         arg_action = ACTION_KEXEC;
4518                         break;
4519
4520                 case 'h':
4521                         if (arg_action != ACTION_HALT)
4522                                 arg_action = ACTION_POWEROFF;
4523                         break;
4524
4525                 case 'k':
4526                         arg_dry = true;
4527                         break;
4528
4529                 case ARG_NO_WALL:
4530                         arg_no_wall = true;
4531                         break;
4532
4533                 case 't':
4534                 case 'a':
4535                         /* Compatibility nops */
4536                         break;
4537
4538                 case 'c':
4539                         arg_action = ACTION_CANCEL_SHUTDOWN;
4540                         break;
4541
4542                 case '?':
4543                         return -EINVAL;
4544
4545                 default:
4546                         log_error("Unknown option code '%c'.", c);
4547                         return -EINVAL;
4548                 }
4549         }
4550
4551         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4552                 r = parse_time_spec(argv[optind], &arg_when);
4553                 if (r < 0) {
4554                         log_error("Failed to parse time specification: %s", argv[optind]);
4555                         return r;
4556                 }
4557         } else
4558                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4559
4560         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4561                 /* No time argument for shutdown cancel */
4562                 arg_wall = argv + optind;
4563         else if (argc > optind + 1)
4564                 /* We skip the time argument */
4565                 arg_wall = argv + optind + 1;
4566
4567         optind = argc;
4568
4569         return 1;
4570 }
4571
4572 static int telinit_parse_argv(int argc, char *argv[]) {
4573
4574         enum {
4575                 ARG_HELP = 0x100,
4576                 ARG_NO_WALL
4577         };
4578
4579         static const struct option options[] = {
4580                 { "help",      no_argument,       NULL, ARG_HELP    },
4581                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4582                 { NULL,        0,                 NULL, 0           }
4583         };
4584
4585         static const struct {
4586                 char from;
4587                 enum action to;
4588         } table[] = {
4589                 { '0', ACTION_POWEROFF },
4590                 { '6', ACTION_REBOOT },
4591                 { '1', ACTION_RESCUE },
4592                 { '2', ACTION_RUNLEVEL2 },
4593                 { '3', ACTION_RUNLEVEL3 },
4594                 { '4', ACTION_RUNLEVEL4 },
4595                 { '5', ACTION_RUNLEVEL5 },
4596                 { 's', ACTION_RESCUE },
4597                 { 'S', ACTION_RESCUE },
4598                 { 'q', ACTION_RELOAD },
4599                 { 'Q', ACTION_RELOAD },
4600                 { 'u', ACTION_REEXEC },
4601                 { 'U', ACTION_REEXEC }
4602         };
4603
4604         unsigned i;
4605         int c;
4606
4607         assert(argc >= 0);
4608         assert(argv);
4609
4610         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4611                 switch (c) {
4612
4613                 case ARG_HELP:
4614                         telinit_help();
4615                         return 0;
4616
4617                 case ARG_NO_WALL:
4618                         arg_no_wall = true;
4619                         break;
4620
4621                 case '?':
4622                         return -EINVAL;
4623
4624                 default:
4625                         log_error("Unknown option code '%c'.", c);
4626                         return -EINVAL;
4627                 }
4628         }
4629
4630         if (optind >= argc) {
4631                 telinit_help();
4632                 return -EINVAL;
4633         }
4634
4635         if (optind + 1 < argc) {
4636                 log_error("Too many arguments.");
4637                 return -EINVAL;
4638         }
4639
4640         if (strlen(argv[optind]) != 1) {
4641                 log_error("Expected single character argument.");
4642                 return -EINVAL;
4643         }
4644
4645         for (i = 0; i < ELEMENTSOF(table); i++)
4646                 if (table[i].from == argv[optind][0])
4647                         break;
4648
4649         if (i >= ELEMENTSOF(table)) {
4650                 log_error("Unknown command '%s'.", argv[optind]);
4651                 return -EINVAL;
4652         }
4653
4654         arg_action = table[i].to;
4655
4656         optind ++;
4657
4658         return 1;
4659 }
4660
4661 static int runlevel_parse_argv(int argc, char *argv[]) {
4662
4663         enum {
4664                 ARG_HELP = 0x100,
4665         };
4666
4667         static const struct option options[] = {
4668                 { "help",      no_argument,       NULL, ARG_HELP    },
4669                 { NULL,        0,                 NULL, 0           }
4670         };
4671
4672         int c;
4673
4674         assert(argc >= 0);
4675         assert(argv);
4676
4677         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4678                 switch (c) {
4679
4680                 case ARG_HELP:
4681                         runlevel_help();
4682                         return 0;
4683
4684                 case '?':
4685                         return -EINVAL;
4686
4687                 default:
4688                         log_error("Unknown option code '%c'.", c);
4689                         return -EINVAL;
4690                 }
4691         }
4692
4693         if (optind < argc) {
4694                 log_error("Too many arguments.");
4695                 return -EINVAL;
4696         }
4697
4698         return 1;
4699 }
4700
4701 static int parse_argv(int argc, char *argv[]) {
4702         assert(argc >= 0);
4703         assert(argv);
4704
4705         if (program_invocation_short_name) {
4706
4707                 if (strstr(program_invocation_short_name, "halt")) {
4708                         arg_action = ACTION_HALT;
4709                         return halt_parse_argv(argc, argv);
4710                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4711                         arg_action = ACTION_POWEROFF;
4712                         return halt_parse_argv(argc, argv);
4713                 } else if (strstr(program_invocation_short_name, "reboot")) {
4714                         if (kexec_loaded())
4715                                 arg_action = ACTION_KEXEC;
4716                         else
4717                                 arg_action = ACTION_REBOOT;
4718                         return halt_parse_argv(argc, argv);
4719                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4720                         arg_action = ACTION_POWEROFF;
4721                         return shutdown_parse_argv(argc, argv);
4722                 } else if (strstr(program_invocation_short_name, "init")) {
4723
4724                         if (sd_booted() > 0) {
4725                                 arg_action = ACTION_INVALID;
4726                                 return telinit_parse_argv(argc, argv);
4727                         } else {
4728                                 /* Hmm, so some other init system is
4729                                  * running, we need to forward this
4730                                  * request to it. For now we simply
4731                                  * guess that it is Upstart. */
4732
4733                                 execv("/lib/upstart/telinit", argv);
4734
4735                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4736                                 return -EIO;
4737                         }
4738
4739                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4740                         arg_action = ACTION_RUNLEVEL;
4741                         return runlevel_parse_argv(argc, argv);
4742                 }
4743         }
4744
4745         arg_action = ACTION_SYSTEMCTL;
4746         return systemctl_parse_argv(argc, argv);
4747 }
4748
4749 static int action_to_runlevel(void) {
4750
4751         static const char table[_ACTION_MAX] = {
4752                 [ACTION_HALT] =      '0',
4753                 [ACTION_POWEROFF] =  '0',
4754                 [ACTION_REBOOT] =    '6',
4755                 [ACTION_RUNLEVEL2] = '2',
4756                 [ACTION_RUNLEVEL3] = '3',
4757                 [ACTION_RUNLEVEL4] = '4',
4758                 [ACTION_RUNLEVEL5] = '5',
4759                 [ACTION_RESCUE] =    '1'
4760         };
4761
4762         assert(arg_action < _ACTION_MAX);
4763
4764         return table[arg_action];
4765 }
4766
4767 static int talk_upstart(void) {
4768         DBusMessage *m = NULL, *reply = NULL;
4769         DBusError error;
4770         int previous, rl, r;
4771         char
4772                 env1_buf[] = "RUNLEVEL=X",
4773                 env2_buf[] = "PREVLEVEL=X";
4774         char *env1 = env1_buf, *env2 = env2_buf;
4775         const char *emit = "runlevel";
4776         dbus_bool_t b_false = FALSE;
4777         DBusMessageIter iter, sub;
4778         DBusConnection *bus;
4779
4780         dbus_error_init(&error);
4781
4782         if (!(rl = action_to_runlevel()))
4783                 return 0;
4784
4785         if (utmp_get_runlevel(&previous, NULL) < 0)
4786                 previous = 'N';
4787
4788         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4789                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4790                         r = 0;
4791                         goto finish;
4792                 }
4793
4794                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4795                 r = -EIO;
4796                 goto finish;
4797         }
4798
4799         if ((r = bus_check_peercred(bus)) < 0) {
4800                 log_error("Failed to verify owner of bus.");
4801                 goto finish;
4802         }
4803
4804         if (!(m = dbus_message_new_method_call(
4805                               "com.ubuntu.Upstart",
4806                               "/com/ubuntu/Upstart",
4807                               "com.ubuntu.Upstart0_6",
4808                               "EmitEvent"))) {
4809
4810                 log_error("Could not allocate message.");
4811                 r = -ENOMEM;
4812                 goto finish;
4813         }
4814
4815         dbus_message_iter_init_append(m, &iter);
4816
4817         env1_buf[sizeof(env1_buf)-2] = rl;
4818         env2_buf[sizeof(env2_buf)-2] = previous;
4819
4820         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4821             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4822             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4823             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4824             !dbus_message_iter_close_container(&iter, &sub) ||
4825             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4826                 log_error("Could not append arguments to message.");
4827                 r = -ENOMEM;
4828                 goto finish;
4829         }
4830
4831         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4832
4833                 if (bus_error_is_no_service(&error)) {
4834                         r = -EADDRNOTAVAIL;
4835                         goto finish;
4836                 }
4837
4838                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4839                 r = -EIO;
4840                 goto finish;
4841         }
4842
4843         r = 1;
4844
4845 finish:
4846         if (m)
4847                 dbus_message_unref(m);
4848
4849         if (reply)
4850                 dbus_message_unref(reply);
4851
4852         if (bus) {
4853                 dbus_connection_flush(bus);
4854                 dbus_connection_close(bus);
4855                 dbus_connection_unref(bus);
4856         }
4857
4858         dbus_error_free(&error);
4859
4860         return r;
4861 }
4862
4863 static int talk_initctl(void) {
4864         struct init_request request;
4865         int r, fd;
4866         char rl;
4867
4868         if (!(rl = action_to_runlevel()))
4869                 return 0;
4870
4871         zero(request);
4872         request.magic = INIT_MAGIC;
4873         request.sleeptime = 0;
4874         request.cmd = INIT_CMD_RUNLVL;
4875         request.runlevel = rl;
4876
4877         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4878
4879                 if (errno == ENOENT)
4880                         return 0;
4881
4882                 log_error("Failed to open "INIT_FIFO": %m");
4883                 return -errno;
4884         }
4885
4886         errno = 0;
4887         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4888         close_nointr_nofail(fd);
4889
4890         if (r < 0) {
4891                 log_error("Failed to write to "INIT_FIFO": %m");
4892                 return errno ? -errno : -EIO;
4893         }
4894
4895         return 1;
4896 }
4897
4898 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4899
4900         static const struct {
4901                 const char* verb;
4902                 const enum {
4903                         MORE,
4904                         LESS,
4905                         EQUAL
4906                 } argc_cmp;
4907                 const int argc;
4908                 int (* const dispatch)(DBusConnection *bus, char **args);
4909         } verbs[] = {
4910                 { "list-units",            LESS,  1, list_units        },
4911                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
4912                 { "list-jobs",             EQUAL, 1, list_jobs         },
4913                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
4914                 { "load",                  MORE,  2, load_unit         },
4915                 { "cancel",                MORE,  2, cancel_job        },
4916                 { "start",                 MORE,  2, start_unit        },
4917                 { "stop",                  MORE,  2, start_unit        },
4918                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4919                 { "reload",                MORE,  2, start_unit        },
4920                 { "restart",               MORE,  2, start_unit        },
4921                 { "try-restart",           MORE,  2, start_unit        },
4922                 { "reload-or-restart",     MORE,  2, start_unit        },
4923                 { "reload-or-try-restart", MORE,  2, start_unit        },
4924                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
4925                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4926                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
4927                 { "isolate",               EQUAL, 2, start_unit        },
4928                 { "kill",                  MORE,  2, kill_unit         },
4929                 { "is-active",             MORE,  2, check_unit        },
4930                 { "check",                 MORE,  2, check_unit        },
4931                 { "show",                  MORE,  1, show              },
4932                 { "status",                MORE,  2, show              },
4933                 { "help",                  MORE,  2, show              },
4934                 { "dump",                  EQUAL, 1, dump              },
4935                 { "dot",                   EQUAL, 1, dot               },
4936                 { "snapshot",              LESS,  2, snapshot          },
4937                 { "delete",                MORE,  2, delete_snapshot   },
4938                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
4939                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
4940                 { "show-environment",      EQUAL, 1, show_enviroment   },
4941                 { "set-environment",       MORE,  2, set_environment   },
4942                 { "unset-environment",     MORE,  2, set_environment   },
4943                 { "halt",                  EQUAL, 1, start_special     },
4944                 { "poweroff",              EQUAL, 1, start_special     },
4945                 { "reboot",                EQUAL, 1, start_special     },
4946                 { "kexec",                 EQUAL, 1, start_special     },
4947                 { "suspend",               EQUAL, 1, start_special     },
4948                 { "hibernate",             EQUAL, 1, start_special     },
4949                 { "default",               EQUAL, 1, start_special     },
4950                 { "rescue",                EQUAL, 1, start_special     },
4951                 { "emergency",             EQUAL, 1, start_special     },
4952                 { "exit",                  EQUAL, 1, start_special     },
4953                 { "reset-failed",          MORE,  1, reset_failed      },
4954                 { "enable",                MORE,  2, enable_unit       },
4955                 { "disable",               MORE,  2, enable_unit       },
4956                 { "is-enabled",            MORE,  2, unit_is_enabled   },
4957                 { "reenable",              MORE,  2, enable_unit       },
4958                 { "preset",                MORE,  2, enable_unit       },
4959                 { "mask",                  MORE,  2, enable_unit       },
4960                 { "unmask",                MORE,  2, enable_unit       },
4961                 { "link",                  MORE,  2, enable_unit       },
4962                 { "switch-root",           MORE,  2, switch_root       },
4963         };
4964
4965         int left;
4966         unsigned i;
4967
4968         assert(argc >= 0);
4969         assert(argv);
4970         assert(error);
4971
4972         left = argc - optind;
4973
4974         if (left <= 0)
4975                 /* Special rule: no arguments means "list-units" */
4976                 i = 0;
4977         else {
4978                 if (streq(argv[optind], "help") && !argv[optind+1]) {
4979                         log_error("This command expects one or more "
4980                                   "unit names. Did you mean --help?");
4981                         return -EINVAL;
4982                 }
4983
4984                 for (i = 0; i < ELEMENTSOF(verbs); i++)
4985                         if (streq(argv[optind], verbs[i].verb))
4986                                 break;
4987
4988                 if (i >= ELEMENTSOF(verbs)) {
4989                         log_error("Unknown operation '%s'.", argv[optind]);
4990                         return -EINVAL;
4991                 }
4992         }
4993
4994         switch (verbs[i].argc_cmp) {
4995
4996         case EQUAL:
4997                 if (left != verbs[i].argc) {
4998                         log_error("Invalid number of arguments.");
4999                         return -EINVAL;
5000                 }
5001
5002                 break;
5003
5004         case MORE:
5005                 if (left < verbs[i].argc) {
5006                         log_error("Too few arguments.");
5007                         return -EINVAL;
5008                 }
5009
5010                 break;
5011
5012         case LESS:
5013                 if (left > verbs[i].argc) {
5014                         log_error("Too many arguments.");
5015                         return -EINVAL;
5016                 }
5017
5018                 break;
5019
5020         default:
5021                 assert_not_reached("Unknown comparison operator.");
5022         }
5023
5024         /* Require a bus connection for all operations but
5025          * enable/disable */
5026         if (!streq(verbs[i].verb, "enable") &&
5027             !streq(verbs[i].verb, "disable") &&
5028             !streq(verbs[i].verb, "is-enabled") &&
5029             !streq(verbs[i].verb, "list-unit-files") &&
5030             !streq(verbs[i].verb, "reenable") &&
5031             !streq(verbs[i].verb, "preset") &&
5032             !streq(verbs[i].verb, "mask") &&
5033             !streq(verbs[i].verb, "unmask") &&
5034             !streq(verbs[i].verb, "link")) {
5035
5036                 if (running_in_chroot() > 0) {
5037                         log_info("Running in chroot, ignoring request.");
5038                         return 0;
5039                 }
5040
5041                 if (((!streq(verbs[i].verb, "reboot") &&
5042                       !streq(verbs[i].verb, "halt") &&
5043                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5044                         log_error("Failed to get D-Bus connection: %s",
5045                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5046                         return -EIO;
5047                 }
5048
5049         } else {
5050
5051                 if (!bus && !avoid_bus()) {
5052                         log_error("Failed to get D-Bus connection: %s",
5053                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5054                         return -EIO;
5055                 }
5056         }
5057
5058         return verbs[i].dispatch(bus, argv + optind);
5059 }
5060
5061 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5062         int fd;
5063         struct msghdr msghdr;
5064         struct iovec iovec[2];
5065         union sockaddr_union sockaddr;
5066         struct sd_shutdown_command c;
5067
5068         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5069         if (fd < 0)
5070                 return -errno;
5071
5072         zero(c);
5073         c.usec = t;
5074         c.mode = mode;
5075         c.dry_run = dry_run;
5076         c.warn_wall = warn;
5077
5078         zero(sockaddr);
5079         sockaddr.sa.sa_family = AF_UNIX;
5080         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5081
5082         zero(msghdr);
5083         msghdr.msg_name = &sockaddr;
5084         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5085
5086         zero(iovec);
5087         iovec[0].iov_base = (char*) &c;
5088         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5089
5090         if (isempty(message))
5091                 msghdr.msg_iovlen = 1;
5092         else {
5093                 iovec[1].iov_base = (char*) message;
5094                 iovec[1].iov_len = strlen(message);
5095                 msghdr.msg_iovlen = 2;
5096         }
5097         msghdr.msg_iov = iovec;
5098
5099         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5100                 close_nointr_nofail(fd);
5101                 return -errno;
5102         }
5103
5104         close_nointr_nofail(fd);
5105         return 0;
5106 }
5107
5108 static int reload_with_fallback(DBusConnection *bus) {
5109
5110         if (bus) {
5111                 /* First, try systemd via D-Bus. */
5112                 if (daemon_reload(bus, NULL) >= 0)
5113                         return 0;
5114         }
5115
5116         /* Nothing else worked, so let's try signals */
5117         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5118
5119         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5120                 log_error("kill() failed: %m");
5121                 return -errno;
5122         }
5123
5124         return 0;
5125 }
5126
5127 static int start_with_fallback(DBusConnection *bus) {
5128
5129         if (bus) {
5130                 /* First, try systemd via D-Bus. */
5131                 if (start_unit(bus, NULL) >= 0)
5132                         goto done;
5133         }
5134
5135         /* Hmm, talking to systemd via D-Bus didn't work. Then
5136          * let's try to talk to Upstart via D-Bus. */
5137         if (talk_upstart() > 0)
5138                 goto done;
5139
5140         /* Nothing else worked, so let's try
5141          * /dev/initctl */
5142         if (talk_initctl() > 0)
5143                 goto done;
5144
5145         log_error("Failed to talk to init daemon.");
5146         return -EIO;
5147
5148 done:
5149         warn_wall(arg_action);
5150         return 0;
5151 }
5152
5153 static _noreturn_ void halt_now(enum action a) {
5154
5155        /* Make sure C-A-D is handled by the kernel from this
5156          * point on... */
5157         reboot(RB_ENABLE_CAD);
5158
5159         switch (a) {
5160
5161         case ACTION_HALT:
5162                 log_info("Halting.");
5163                 reboot(RB_HALT_SYSTEM);
5164                 break;
5165
5166         case ACTION_POWEROFF:
5167                 log_info("Powering off.");
5168                 reboot(RB_POWER_OFF);
5169                 break;
5170
5171         case ACTION_REBOOT:
5172                 log_info("Rebooting.");
5173                 reboot(RB_AUTOBOOT);
5174                 break;
5175
5176         default:
5177                 assert_not_reached("Unknown halt action.");
5178         }
5179
5180         assert_not_reached("Uh? This shouldn't happen.");
5181 }
5182
5183 static int halt_main(DBusConnection *bus) {
5184         int r;
5185
5186         if (geteuid() != 0) {
5187                 /* Try logind if we are a normal user and no special
5188                  * mode applies. Maybe PolicyKit allows us to shutdown
5189                  * the machine. */
5190
5191                 if (arg_when <= 0 &&
5192                     !arg_dry &&
5193                     !arg_force &&
5194                     (arg_action == ACTION_POWEROFF ||
5195                      arg_action == ACTION_REBOOT)) {
5196                         r = reboot_with_logind(bus, arg_action);
5197                         if (r >= 0)
5198                                 return r;
5199                 }
5200
5201                 log_error("Must be root.");
5202                 return -EPERM;
5203         }
5204
5205         if (arg_when > 0) {
5206                 char *m;
5207
5208                 m = strv_join(arg_wall, " ");
5209                 r = send_shutdownd(arg_when,
5210                                    arg_action == ACTION_HALT     ? 'H' :
5211                                    arg_action == ACTION_POWEROFF ? 'P' :
5212                                    arg_action == ACTION_KEXEC    ? 'K' :
5213                                                                    'r',
5214                                    arg_dry,
5215                                    !arg_no_wall,
5216                                    m);
5217                 free(m);
5218
5219                 if (r < 0)
5220                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5221                 else {
5222                         char date[FORMAT_TIMESTAMP_MAX];
5223
5224                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5225                                  format_timestamp(date, sizeof(date), arg_when));
5226                         return 0;
5227                 }
5228         }
5229
5230         if (!arg_dry && !arg_force)
5231                 return start_with_fallback(bus);
5232
5233         if (!arg_no_wtmp) {
5234                 if (sd_booted() > 0)
5235                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5236                 else {
5237                         r = utmp_put_shutdown();
5238                         if (r < 0)
5239                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5240                 }
5241         }
5242
5243         if (arg_dry)
5244                 return 0;
5245
5246         halt_now(arg_action);
5247         /* We should never reach this. */
5248         return -ENOSYS;
5249 }
5250
5251 static int runlevel_main(void) {
5252         int r, runlevel, previous;
5253
5254         r = utmp_get_runlevel(&runlevel, &previous);
5255         if (r < 0) {
5256                 puts("unknown");
5257                 return r;
5258         }
5259
5260         printf("%c %c\n",
5261                previous <= 0 ? 'N' : previous,
5262                runlevel <= 0 ? 'N' : runlevel);
5263
5264         return 0;
5265 }
5266
5267 int main(int argc, char*argv[]) {
5268         int r, retval = EXIT_FAILURE;
5269         DBusConnection *bus = NULL;
5270         DBusError error;
5271
5272         dbus_error_init(&error);
5273
5274         log_parse_environment();
5275         log_open();
5276
5277         r = parse_argv(argc, argv);
5278         if (r < 0)
5279                 goto finish;
5280         else if (r == 0) {
5281                 retval = EXIT_SUCCESS;
5282                 goto finish;
5283         }
5284
5285         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5286          * let's shortcut this */
5287         if (arg_action == ACTION_RUNLEVEL) {
5288                 r = runlevel_main();
5289                 retval = r < 0 ? EXIT_FAILURE : r;
5290                 goto finish;
5291         }
5292
5293         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5294                 log_info("Running in chroot, ignoring request.");
5295                 retval = 0;
5296                 goto finish;
5297         }
5298
5299         if (!avoid_bus()) {
5300                 if (arg_transport == TRANSPORT_NORMAL)
5301                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5302                 else if (arg_transport == TRANSPORT_POLKIT) {
5303                         bus_connect_system_polkit(&bus, &error);
5304                         private_bus = false;
5305                 } else if (arg_transport == TRANSPORT_SSH) {
5306                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5307                         private_bus = false;
5308                 } else
5309                         assert_not_reached("Uh, invalid transport...");
5310         }
5311
5312         switch (arg_action) {
5313
5314         case ACTION_SYSTEMCTL:
5315                 r = systemctl_main(bus, argc, argv, &error);
5316                 break;
5317
5318         case ACTION_HALT:
5319         case ACTION_POWEROFF:
5320         case ACTION_REBOOT:
5321         case ACTION_KEXEC:
5322                 r = halt_main(bus);
5323                 break;
5324
5325         case ACTION_RUNLEVEL2:
5326         case ACTION_RUNLEVEL3:
5327         case ACTION_RUNLEVEL4:
5328         case ACTION_RUNLEVEL5:
5329         case ACTION_RESCUE:
5330         case ACTION_EMERGENCY:
5331         case ACTION_DEFAULT:
5332                 r = start_with_fallback(bus);
5333                 break;
5334
5335         case ACTION_RELOAD:
5336         case ACTION_REEXEC:
5337                 r = reload_with_fallback(bus);
5338                 break;
5339
5340         case ACTION_CANCEL_SHUTDOWN: {
5341                 char *m = NULL;
5342
5343                 if (arg_wall) {
5344                         m = strv_join(arg_wall, " ");
5345                         if (!m) {
5346                                 retval = EXIT_FAILURE;
5347                                 goto finish;
5348                         }
5349                 }
5350                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5351                 if (r < 0)
5352                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5353                 free(m);
5354                 break;
5355         }
5356
5357         case ACTION_INVALID:
5358         case ACTION_RUNLEVEL:
5359         default:
5360                 assert_not_reached("Unknown action");
5361         }
5362
5363         retval = r < 0 ? EXIT_FAILURE : r;
5364
5365 finish:
5366         if (bus) {
5367                 dbus_connection_flush(bus);
5368                 dbus_connection_close(bus);
5369                 dbus_connection_unref(bus);
5370         }
5371
5372         dbus_error_free(&error);
5373
5374         dbus_shutdown();
5375
5376         strv_free(arg_property);
5377
5378         pager_close();
5379         ask_password_agent_close();
5380         polkit_agent_close();
5381
5382         return retval;
5383 }