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