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