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