chiark / gitweb /
install: append .service when enable/disable... is called
[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 **names_it = NULL;
3556         char **name = NULL;
3557
3558         (*mangled_names) = new(char*, strv_length(original_names)+1);
3559         if(!(*mangled_names))
3560                 return log_oom();
3561
3562         names_it = *mangled_names;
3563
3564         STRV_FOREACH(name, original_names) {
3565                 char *n = unit_name_mangle(*name);
3566                 (*names_it) = n ? n : strdup(*name);
3567                 if(!(*names_it))
3568                         return log_oom();
3569                 names_it++;
3570         }
3571         *names_it = NULL;
3572
3573         return 0;
3574 }
3575
3576 static int enable_unit(DBusConnection *bus, char **args) {
3577         const char *verb = args[0];
3578         UnitFileChange *changes = NULL;
3579         unsigned n_changes = 0, i;
3580         int carries_install_info = -1;
3581         DBusMessage *m = NULL, *reply = NULL;
3582         int r;
3583         DBusError error;
3584         char **mangled_names = NULL;
3585
3586         r = enable_sysv_units(args);
3587         if (r < 0)
3588                 return r;
3589
3590         if (!args[1])
3591                 return 0;
3592
3593         dbus_error_init(&error);
3594
3595         if (!bus || avoid_bus()) {
3596                 if (streq(verb, "enable")) {
3597                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3598                         carries_install_info = r;
3599                 } else if (streq(verb, "disable"))
3600                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3601                 else if (streq(verb, "reenable")) {
3602                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3603                         carries_install_info = r;
3604                 } else if (streq(verb, "link"))
3605                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3606                 else if (streq(verb, "preset")) {
3607                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3608                         carries_install_info = r;
3609                 } else if (streq(verb, "mask"))
3610                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3611                 else if (streq(verb, "unmask"))
3612                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3613                 else
3614                         assert_not_reached("Unknown verb");
3615
3616                 if (r < 0) {
3617                         log_error("Operation failed: %s", strerror(-r));
3618                         goto finish;
3619                 }
3620
3621                 if (!arg_quiet) {
3622                         for (i = 0; i < n_changes; i++) {
3623                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3624                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3625                                 else
3626                                         log_info("rm '%s'", changes[i].path);
3627                         }
3628                 }
3629
3630         } else {
3631                 const char *method;
3632                 bool send_force = true, expect_carries_install_info = false;
3633                 dbus_bool_t a, b;
3634                 DBusMessageIter iter, sub, sub2;
3635
3636                 if (streq(verb, "enable")) {
3637                         method = "EnableUnitFiles";
3638                         expect_carries_install_info = true;
3639                 } else if (streq(verb, "disable")) {
3640                         method = "DisableUnitFiles";
3641                         send_force = false;
3642                 } else if (streq(verb, "reenable")) {
3643                         method = "ReenableUnitFiles";
3644                         expect_carries_install_info = true;
3645                 } else if (streq(verb, "link"))
3646                         method = "LinkUnitFiles";
3647                 else if (streq(verb, "preset")) {
3648                         method = "PresetUnitFiles";
3649                         expect_carries_install_info = true;
3650                 } else if (streq(verb, "mask"))
3651                         method = "MaskUnitFiles";
3652                 else if (streq(verb, "unmask")) {
3653                         method = "UnmaskUnitFiles";
3654                         send_force = false;
3655                 } else
3656                         assert_not_reached("Unknown verb");
3657
3658                 m = dbus_message_new_method_call(
3659                                 "org.freedesktop.systemd1",
3660                                 "/org/freedesktop/systemd1",
3661                                 "org.freedesktop.systemd1.Manager",
3662                                 method);
3663                 if (!m) {
3664                         r = log_oom();
3665                         goto finish;
3666                 }
3667
3668                 dbus_message_iter_init_append(m, &iter);
3669
3670                 r = mangle_names(args+1, &mangled_names);
3671                 if(r < 0)
3672                         goto finish;
3673
3674                 r = bus_append_strv_iter(&iter, mangled_names);
3675                 if (r < 0) {
3676                         log_error("Failed to append unit files.");
3677                         goto finish;
3678                 }
3679
3680                 a = arg_runtime;
3681                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3682                         log_error("Failed to append runtime boolean.");
3683                         r = -ENOMEM;
3684                         goto finish;
3685                 }
3686
3687                 if (send_force) {
3688                         b = arg_force;
3689
3690                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3691                                 log_error("Failed to append force boolean.");
3692                                 r = -ENOMEM;
3693                                 goto finish;
3694                         }
3695                 }
3696
3697                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3698                 if (!reply) {
3699                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3700                         r = -EIO;
3701                         goto finish;
3702                 }
3703
3704                 if (!dbus_message_iter_init(reply, &iter)) {
3705                         log_error("Failed to initialize iterator.");
3706                         goto finish;
3707                 }
3708
3709                 if (expect_carries_install_info) {
3710                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3711                         if (r < 0) {
3712                                 log_error("Failed to parse reply.");
3713                                 goto finish;
3714                         }
3715
3716                         carries_install_info = b;
3717                 }
3718
3719                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3720                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3721                         log_error("Failed to parse reply.");
3722                         r = -EIO;
3723                         goto finish;
3724                 }
3725
3726                 dbus_message_iter_recurse(&iter, &sub);
3727                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3728                         const char *type, *path, *source;
3729
3730                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3731                                 log_error("Failed to parse reply.");
3732                                 r = -EIO;
3733                                 goto finish;
3734                         }
3735
3736                         dbus_message_iter_recurse(&sub, &sub2);
3737
3738                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3739                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3740                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3741                                 log_error("Failed to parse reply.");
3742                                 r = -EIO;
3743                                 goto finish;
3744                         }
3745
3746                         if (!arg_quiet) {
3747                                 if (streq(type, "symlink"))
3748                                         log_info("ln -s '%s' '%s'", source, path);
3749                                 else
3750                                         log_info("rm '%s'", path);
3751                         }
3752
3753                         dbus_message_iter_next(&sub);
3754                 }
3755
3756                 /* Try to reload if enabeld */
3757                 if (!arg_no_reload)
3758                         r = daemon_reload(bus, args);
3759         }
3760
3761         if (carries_install_info == 0)
3762                 log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
3763
3764 finish:
3765         if (m)
3766                 dbus_message_unref(m);
3767
3768         if (reply)
3769                 dbus_message_unref(reply);
3770
3771         unit_file_changes_free(changes, n_changes);
3772
3773         dbus_error_free(&error);
3774
3775         strv_free(mangled_names);
3776
3777         return r;
3778 }
3779
3780 static int unit_is_enabled(DBusConnection *bus, char **args) {
3781         DBusError error;
3782         int r;
3783         DBusMessage *reply = NULL;
3784         bool enabled;
3785         char **name;
3786
3787         dbus_error_init(&error);
3788
3789         r = enable_sysv_units(args);
3790         if (r < 0)
3791                 return r;
3792
3793         enabled = r > 0;
3794
3795         if (!bus || avoid_bus()) {
3796
3797                 STRV_FOREACH(name, args+1) {
3798                         UnitFileState state;
3799
3800                         state = unit_file_get_state(arg_scope, arg_root, *name);
3801                         if (state < 0) {
3802                                 r = state;
3803                                 goto finish;
3804                         }
3805
3806                         if (state == UNIT_FILE_ENABLED ||
3807                             state == UNIT_FILE_ENABLED_RUNTIME ||
3808                             state == UNIT_FILE_STATIC)
3809                                 enabled = true;
3810
3811                         if (!arg_quiet)
3812                                 puts(unit_file_state_to_string(state));
3813                 }
3814
3815         } else {
3816                 STRV_FOREACH(name, args+1) {
3817                         const char *s;
3818
3819                         r = bus_method_call_with_reply (
3820                                         bus,
3821                                         "org.freedesktop.systemd1",
3822                                         "/org/freedesktop/systemd1",
3823                                         "org.freedesktop.systemd1.Manager",
3824                                         "GetUnitFileState",
3825                                         &reply,
3826                                         NULL,
3827                                         DBUS_TYPE_STRING, name,
3828                                         DBUS_TYPE_INVALID);
3829                         if (r)
3830                                 goto finish;
3831
3832                         if (!dbus_message_get_args(reply, &error,
3833                                                    DBUS_TYPE_STRING, &s,
3834                                                    DBUS_TYPE_INVALID)) {
3835                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3836                                 r = -EIO;
3837                                 goto finish;
3838                         }
3839
3840                         dbus_message_unref(reply);
3841                         reply = NULL;
3842
3843                         if (streq(s, "enabled") ||
3844                             streq(s, "enabled-runtime") ||
3845                             streq(s, "static"))
3846                                 enabled = true;
3847
3848                         if (!arg_quiet)
3849                                 puts(s);
3850                 }
3851         }
3852
3853         r = enabled ? 0 : 1;
3854
3855 finish:
3856         if (reply)
3857                 dbus_message_unref(reply);
3858
3859         dbus_error_free(&error);
3860         return r;
3861 }
3862
3863 static int systemctl_help(void) {
3864
3865         pager_open_if_enabled();
3866
3867         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3868                "Query or send control commands to the systemd manager.\n\n"
3869                "  -h --help           Show this help\n"
3870                "     --version        Show package version\n"
3871                "  -t --type=TYPE      List only units of a particular type\n"
3872                "  -p --property=NAME  Show only properties by this name\n"
3873                "  -a --all            Show all units/properties, including dead/empty ones\n"
3874                "     --failed         Show only failed units\n"
3875                "     --full           Don't ellipsize unit names on output\n"
3876                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
3877                "                      pending\n"
3878                "     --ignore-dependencies\n"
3879                "                      When queueing a new job, ignore all its dependencies\n"
3880                "     --kill-who=WHO   Who to send signal to\n"
3881                "  -s --signal=SIGNAL  Which signal to send\n"
3882                "  -H --host=[USER@]HOST\n"
3883                "                      Show information for remote host\n"
3884                "  -P --privileged     Acquire privileges before execution\n"
3885                "  -q --quiet          Suppress output\n"
3886                "     --no-block       Do not wait until operation finished\n"
3887                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
3888                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
3889                "                      configuration\n"
3890                "     --no-legend      Do not print a legend (column headers and hints)\n"
3891                "     --no-pager       Do not pipe output into a pager\n"
3892                "     --no-ask-password\n"
3893                "                      Do not ask for system passwords\n"
3894                "     --order          When generating graph for dot, show only order\n"
3895                "     --require        When generating graph for dot, show only requirement\n"
3896                "     --system         Connect to system manager\n"
3897                "     --user           Connect to user service manager\n"
3898                "     --global         Enable/disable unit files globally\n"
3899                "  -f --force          When enabling unit files, override existing symlinks\n"
3900                "                      When shutting down, execute action immediately\n"
3901                "     --root=PATH      Enable unit files in the specified root directory\n"
3902                "     --runtime        Enable unit files only temporarily until next reboot\n"
3903                "  -n --lines=INTEGER  Journal entries to show\n"
3904                "     --follow         Follow journal\n"
3905                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
3906                "                      verbose, export, json, json-pretty, cat)\n\n"
3907                "Unit Commands:\n"
3908                "  list-units                      List loaded units\n"
3909                "  start [NAME...]                 Start (activate) one or more units\n"
3910                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
3911                "  reload [NAME...]                Reload one or more units\n"
3912                "  restart [NAME...]               Start or restart one or more units\n"
3913                "  try-restart [NAME...]           Restart one or more units if active\n"
3914                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
3915                "                                  otherwise start or restart\n"
3916                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
3917                "                                  otherwise restart if active\n"
3918                "  isolate [NAME]                  Start one unit and stop all others\n"
3919                "  kill [NAME...]                  Send signal to processes of a unit\n"
3920                "  is-active [NAME...]             Check whether units are active\n"
3921                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
3922                "  show [NAME...|JOB...]           Show properties of one or more\n"
3923                "                                  units/jobs or the manager\n"
3924                "  help [NAME...|PID...]            Show manual for one or more units\n"
3925                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
3926                "                                  units\n"
3927                "  load [NAME...]                  Load one or more units\n\n"
3928                "Unit File Commands:\n"
3929                "  list-unit-files                 List installed unit files\n"
3930                "  enable [NAME...]                Enable one or more unit files\n"
3931                "  disable [NAME...]               Disable one or more unit files\n"
3932                "  reenable [NAME...]              Reenable one or more unit files\n"
3933                "  preset [NAME...]                Enable/disable one or more unit files\n"
3934                "                                  based on preset configuration\n"
3935                "  mask [NAME...]                  Mask one or more units\n"
3936                "  unmask [NAME...]                Unmask one or more units\n"
3937                "  link [PATH...]                  Link one or more units files into\n"
3938                "                                  the search path\n"
3939                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
3940                "Job Commands:\n"
3941                "  list-jobs                       List jobs\n"
3942                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
3943                "Status Commands:\n"
3944                "  dump                            Dump server status\n"
3945                "  dot                             Dump dependency graph for dot(1)\n\n"
3946                "Snapshot Commands:\n"
3947                "  snapshot [NAME]                 Create a snapshot\n"
3948                "  delete [NAME...]                Remove one or more snapshots\n\n"
3949                "Environment Commands:\n"
3950                "  show-environment                Dump environment\n"
3951                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
3952                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
3953                "Manager Lifecycle Commands:\n"
3954                "  daemon-reload                   Reload systemd manager configuration\n"
3955                "  daemon-reexec                   Reexecute systemd manager\n\n"
3956                "System Commands:\n"
3957                "  default                         Enter system default mode\n"
3958                "  rescue                          Enter system rescue mode\n"
3959                "  emergency                       Enter system emergency mode\n"
3960                "  halt                            Shut down and halt the system\n"
3961                "  poweroff                        Shut down and power-off the system\n"
3962                "  reboot                          Shut down and reboot the system\n"
3963                "  kexec                           Shut down and reboot the system with kexec\n"
3964                "  exit                            Request user instance exit\n"
3965                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
3966                "  suspend                         Suspend the system\n"
3967                "  hibernate                       Hibernate the system\n",
3968                program_invocation_short_name);
3969
3970         return 0;
3971 }
3972
3973 static int halt_help(void) {
3974
3975         printf("%s [OPTIONS...]\n\n"
3976                "%s the system.\n\n"
3977                "     --help      Show this help\n"
3978                "     --halt      Halt the machine\n"
3979                "  -p --poweroff  Switch off the machine\n"
3980                "     --reboot    Reboot the machine\n"
3981                "  -f --force     Force immediate halt/power-off/reboot\n"
3982                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
3983                "  -d --no-wtmp   Don't write wtmp record\n"
3984                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
3985                program_invocation_short_name,
3986                arg_action == ACTION_REBOOT   ? "Reboot" :
3987                arg_action == ACTION_POWEROFF ? "Power off" :
3988                                                "Halt");
3989
3990         return 0;
3991 }
3992
3993 static int shutdown_help(void) {
3994
3995         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
3996                "Shut down the system.\n\n"
3997                "     --help      Show this help\n"
3998                "  -H --halt      Halt the machine\n"
3999                "  -P --poweroff  Power-off the machine\n"
4000                "  -r --reboot    Reboot the machine\n"
4001                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4002                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4003                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4004                "  -c             Cancel a pending shutdown\n",
4005                program_invocation_short_name);
4006
4007         return 0;
4008 }
4009
4010 static int telinit_help(void) {
4011
4012         printf("%s [OPTIONS...] {COMMAND}\n\n"
4013                "Send control commands to the init daemon.\n\n"
4014                "     --help      Show this help\n"
4015                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4016                "Commands:\n"
4017                "  0              Power-off the machine\n"
4018                "  6              Reboot the machine\n"
4019                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4020                "  1, s, S        Enter rescue mode\n"
4021                "  q, Q           Reload init daemon configuration\n"
4022                "  u, U           Reexecute init daemon\n",
4023                program_invocation_short_name);
4024
4025         return 0;
4026 }
4027
4028 static int runlevel_help(void) {
4029
4030         printf("%s [OPTIONS...]\n\n"
4031                "Prints the previous and current runlevel of the init system.\n\n"
4032                "     --help      Show this help\n",
4033                program_invocation_short_name);
4034
4035         return 0;
4036 }
4037
4038 static int systemctl_parse_argv(int argc, char *argv[]) {
4039
4040         enum {
4041                 ARG_FAIL = 0x100,
4042                 ARG_IGNORE_DEPENDENCIES,
4043                 ARG_VERSION,
4044                 ARG_USER,
4045                 ARG_SYSTEM,
4046                 ARG_GLOBAL,
4047                 ARG_NO_BLOCK,
4048                 ARG_NO_LEGEND,
4049                 ARG_NO_PAGER,
4050                 ARG_NO_WALL,
4051                 ARG_ORDER,
4052                 ARG_REQUIRE,
4053                 ARG_ROOT,
4054                 ARG_FULL,
4055                 ARG_NO_RELOAD,
4056                 ARG_KILL_WHO,
4057                 ARG_NO_ASK_PASSWORD,
4058                 ARG_FAILED,
4059                 ARG_RUNTIME,
4060                 ARG_FOLLOW,
4061                 ARG_FORCE
4062         };
4063
4064         static const struct option options[] = {
4065                 { "help",      no_argument,       NULL, 'h'           },
4066                 { "version",   no_argument,       NULL, ARG_VERSION   },
4067                 { "type",      required_argument, NULL, 't'           },
4068                 { "property",  required_argument, NULL, 'p'           },
4069                 { "all",       no_argument,       NULL, 'a'           },
4070                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4071                 { "full",      no_argument,       NULL, ARG_FULL      },
4072                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4073                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4074                 { "user",      no_argument,       NULL, ARG_USER      },
4075                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4076                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4077                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4078                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4079                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4080                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4081                 { "quiet",     no_argument,       NULL, 'q'           },
4082                 { "order",     no_argument,       NULL, ARG_ORDER     },
4083                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4084                 { "root",      required_argument, NULL, ARG_ROOT      },
4085                 { "force",     no_argument,       NULL, ARG_FORCE     },
4086                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4087                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4088                 { "signal",    required_argument, NULL, 's'           },
4089                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4090                 { "host",      required_argument, NULL, 'H'           },
4091                 { "privileged",no_argument,       NULL, 'P'           },
4092                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4093                 { "lines",     required_argument, NULL, 'n'           },
4094                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4095                 { "output",    required_argument, NULL, 'o'           },
4096                 { NULL,        0,                 NULL, 0             }
4097         };
4098
4099         int c;
4100
4101         assert(argc >= 0);
4102         assert(argv);
4103
4104         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4105
4106                 switch (c) {
4107
4108                 case 'h':
4109                         systemctl_help();
4110                         return 0;
4111
4112                 case ARG_VERSION:
4113                         puts(PACKAGE_STRING);
4114                         puts(DISTRIBUTION);
4115                         puts(SYSTEMD_FEATURES);
4116                         return 0;
4117
4118                 case 't':
4119                         if (unit_type_from_string(optarg) >= 0) {
4120                                 arg_type = optarg;
4121                                 break;
4122                         }
4123                         if (unit_load_state_from_string(optarg) >= 0) {
4124                                 arg_load_state = optarg;
4125                                 break;
4126                         }
4127                         log_error("Unkown unit type or load state '%s'.",
4128                                   optarg);
4129                         return -EINVAL;
4130                 case 'p': {
4131                         char **l;
4132
4133                         if (!(l = strv_append(arg_property, optarg)))
4134                                 return -ENOMEM;
4135
4136                         strv_free(arg_property);
4137                         arg_property = l;
4138
4139                         /* If the user asked for a particular
4140                          * property, show it to him, even if it is
4141                          * empty. */
4142                         arg_all = true;
4143                         break;
4144                 }
4145
4146                 case 'a':
4147                         arg_all = true;
4148                         break;
4149
4150                 case ARG_FAIL:
4151                         arg_job_mode = "fail";
4152                         break;
4153
4154                 case ARG_IGNORE_DEPENDENCIES:
4155                         arg_job_mode = "ignore-dependencies";
4156                         break;
4157
4158                 case ARG_USER:
4159                         arg_scope = UNIT_FILE_USER;
4160                         break;
4161
4162                 case ARG_SYSTEM:
4163                         arg_scope = UNIT_FILE_SYSTEM;
4164                         break;
4165
4166                 case ARG_GLOBAL:
4167                         arg_scope = UNIT_FILE_GLOBAL;
4168                         break;
4169
4170                 case ARG_NO_BLOCK:
4171                         arg_no_block = true;
4172                         break;
4173
4174                 case ARG_NO_LEGEND:
4175                         arg_no_legend = true;
4176                         break;
4177
4178                 case ARG_NO_PAGER:
4179                         arg_no_pager = true;
4180                         break;
4181
4182                 case ARG_NO_WALL:
4183                         arg_no_wall = true;
4184                         break;
4185
4186                 case ARG_ORDER:
4187                         arg_dot = DOT_ORDER;
4188                         break;
4189
4190                 case ARG_REQUIRE:
4191                         arg_dot = DOT_REQUIRE;
4192                         break;
4193
4194                 case ARG_ROOT:
4195                         arg_root = optarg;
4196                         break;
4197
4198                 case ARG_FULL:
4199                         arg_full = true;
4200                         break;
4201
4202                 case ARG_FAILED:
4203                         arg_failed = true;
4204                         break;
4205
4206                 case 'q':
4207                         arg_quiet = true;
4208                         break;
4209
4210                 case ARG_FORCE:
4211                         arg_force ++;
4212                         break;
4213
4214                 case ARG_FOLLOW:
4215                         arg_follow = true;
4216                         break;
4217
4218                 case 'f':
4219                         /* -f is short for both --follow and --force! */
4220                         arg_force ++;
4221                         arg_follow = true;
4222                         break;
4223
4224                 case ARG_NO_RELOAD:
4225                         arg_no_reload = true;
4226                         break;
4227
4228                 case ARG_KILL_WHO:
4229                         arg_kill_who = optarg;
4230                         break;
4231
4232                 case 's':
4233                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4234                                 log_error("Failed to parse signal string %s.", optarg);
4235                                 return -EINVAL;
4236                         }
4237                         break;
4238
4239                 case ARG_NO_ASK_PASSWORD:
4240                         arg_ask_password = false;
4241                         break;
4242
4243                 case 'P':
4244                         arg_transport = TRANSPORT_POLKIT;
4245                         break;
4246
4247                 case 'H':
4248                         arg_transport = TRANSPORT_SSH;
4249                         arg_host = optarg;
4250                         break;
4251
4252                 case ARG_RUNTIME:
4253                         arg_runtime = true;
4254                         break;
4255
4256                 case 'n':
4257                         if (safe_atou(optarg, &arg_lines) < 0) {
4258                                 log_error("Failed to parse lines '%s'", optarg);
4259                                 return -EINVAL;
4260                         }
4261                         break;
4262
4263                 case 'o':
4264                         arg_output = output_mode_from_string(optarg);
4265                         if (arg_output < 0) {
4266                                 log_error("Unknown output '%s'.", optarg);
4267                                 return -EINVAL;
4268                         }
4269                         break;
4270
4271                 case '?':
4272                         return -EINVAL;
4273
4274                 default:
4275                         log_error("Unknown option code '%c'.", c);
4276                         return -EINVAL;
4277                 }
4278         }
4279
4280         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4281                 log_error("Cannot access user instance remotely.");
4282                 return -EINVAL;
4283         }
4284
4285         return 1;
4286 }
4287
4288 static int halt_parse_argv(int argc, char *argv[]) {
4289
4290         enum {
4291                 ARG_HELP = 0x100,
4292                 ARG_HALT,
4293                 ARG_REBOOT,
4294                 ARG_NO_WALL
4295         };
4296
4297         static const struct option options[] = {
4298                 { "help",      no_argument,       NULL, ARG_HELP    },
4299                 { "halt",      no_argument,       NULL, ARG_HALT    },
4300                 { "poweroff",  no_argument,       NULL, 'p'         },
4301                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4302                 { "force",     no_argument,       NULL, 'f'         },
4303                 { "wtmp-only", no_argument,       NULL, 'w'         },
4304                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4305                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4306                 { NULL,        0,                 NULL, 0           }
4307         };
4308
4309         int c, runlevel;
4310
4311         assert(argc >= 0);
4312         assert(argv);
4313
4314         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4315                 if (runlevel == '0' || runlevel == '6')
4316                         arg_force = 2;
4317
4318         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4319                 switch (c) {
4320
4321                 case ARG_HELP:
4322                         halt_help();
4323                         return 0;
4324
4325                 case ARG_HALT:
4326                         arg_action = ACTION_HALT;
4327                         break;
4328
4329                 case 'p':
4330                         if (arg_action != ACTION_REBOOT)
4331                                 arg_action = ACTION_POWEROFF;
4332                         break;
4333
4334                 case ARG_REBOOT:
4335                         arg_action = ACTION_REBOOT;
4336                         break;
4337
4338                 case 'f':
4339                         arg_force = 2;
4340                         break;
4341
4342                 case 'w':
4343                         arg_dry = true;
4344                         break;
4345
4346                 case 'd':
4347                         arg_no_wtmp = true;
4348                         break;
4349
4350                 case ARG_NO_WALL:
4351                         arg_no_wall = true;
4352                         break;
4353
4354                 case 'i':
4355                 case 'h':
4356                 case 'n':
4357                         /* Compatibility nops */
4358                         break;
4359
4360                 case '?':
4361                         return -EINVAL;
4362
4363                 default:
4364                         log_error("Unknown option code '%c'.", c);
4365                         return -EINVAL;
4366                 }
4367         }
4368
4369         if (optind < argc) {
4370                 log_error("Too many arguments.");
4371                 return -EINVAL;
4372         }
4373
4374         return 1;
4375 }
4376
4377 static int parse_time_spec(const char *t, usec_t *_u) {
4378         assert(t);
4379         assert(_u);
4380
4381         if (streq(t, "now"))
4382                 *_u = 0;
4383         else if (!strchr(t, ':')) {
4384                 uint64_t u;
4385
4386                 if (safe_atou64(t, &u) < 0)
4387                         return -EINVAL;
4388
4389                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4390         } else {
4391                 char *e = NULL;
4392                 long hour, minute;
4393                 struct tm tm;
4394                 time_t s;
4395                 usec_t n;
4396
4397                 errno = 0;
4398                 hour = strtol(t, &e, 10);
4399                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4400                         return -EINVAL;
4401
4402                 minute = strtol(e+1, &e, 10);
4403                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4404                         return -EINVAL;
4405
4406                 n = now(CLOCK_REALTIME);
4407                 s = (time_t) (n / USEC_PER_SEC);
4408
4409                 zero(tm);
4410                 assert_se(localtime_r(&s, &tm));
4411
4412                 tm.tm_hour = (int) hour;
4413                 tm.tm_min = (int) minute;
4414                 tm.tm_sec = 0;
4415
4416                 assert_se(s = mktime(&tm));
4417
4418                 *_u = (usec_t) s * USEC_PER_SEC;
4419
4420                 while (*_u <= n)
4421                         *_u += USEC_PER_DAY;
4422         }
4423
4424         return 0;
4425 }
4426
4427 static int shutdown_parse_argv(int argc, char *argv[]) {
4428
4429         enum {
4430                 ARG_HELP = 0x100,
4431                 ARG_NO_WALL
4432         };
4433
4434         static const struct option options[] = {
4435                 { "help",      no_argument,       NULL, ARG_HELP    },
4436                 { "halt",      no_argument,       NULL, 'H'         },
4437                 { "poweroff",  no_argument,       NULL, 'P'         },
4438                 { "reboot",    no_argument,       NULL, 'r'         },
4439                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4440                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4441                 { NULL,        0,                 NULL, 0           }
4442         };
4443
4444         int c, r;
4445
4446         assert(argc >= 0);
4447         assert(argv);
4448
4449         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4450                 switch (c) {
4451
4452                 case ARG_HELP:
4453                         shutdown_help();
4454                         return 0;
4455
4456                 case 'H':
4457                         arg_action = ACTION_HALT;
4458                         break;
4459
4460                 case 'P':
4461                         arg_action = ACTION_POWEROFF;
4462                         break;
4463
4464                 case 'r':
4465                         if (kexec_loaded())
4466                                 arg_action = ACTION_KEXEC;
4467                         else
4468                                 arg_action = ACTION_REBOOT;
4469                         break;
4470
4471                 case 'K':
4472                         arg_action = ACTION_KEXEC;
4473                         break;
4474
4475                 case 'h':
4476                         if (arg_action != ACTION_HALT)
4477                                 arg_action = ACTION_POWEROFF;
4478                         break;
4479
4480                 case 'k':
4481                         arg_dry = true;
4482                         break;
4483
4484                 case ARG_NO_WALL:
4485                         arg_no_wall = true;
4486                         break;
4487
4488                 case 't':
4489                 case 'a':
4490                         /* Compatibility nops */
4491                         break;
4492
4493                 case 'c':
4494                         arg_action = ACTION_CANCEL_SHUTDOWN;
4495                         break;
4496
4497                 case '?':
4498                         return -EINVAL;
4499
4500                 default:
4501                         log_error("Unknown option code '%c'.", c);
4502                         return -EINVAL;
4503                 }
4504         }
4505
4506         if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4507                 r = parse_time_spec(argv[optind], &arg_when);
4508                 if (r < 0) {
4509                         log_error("Failed to parse time specification: %s", argv[optind]);
4510                         return r;
4511                 }
4512         } else
4513                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4514
4515         if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4516                 /* No time argument for shutdown cancel */
4517                 arg_wall = argv + optind;
4518         else if (argc > optind + 1)
4519                 /* We skip the time argument */
4520                 arg_wall = argv + optind + 1;
4521
4522         optind = argc;
4523
4524         return 1;
4525 }
4526
4527 static int telinit_parse_argv(int argc, char *argv[]) {
4528
4529         enum {
4530                 ARG_HELP = 0x100,
4531                 ARG_NO_WALL
4532         };
4533
4534         static const struct option options[] = {
4535                 { "help",      no_argument,       NULL, ARG_HELP    },
4536                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4537                 { NULL,        0,                 NULL, 0           }
4538         };
4539
4540         static const struct {
4541                 char from;
4542                 enum action to;
4543         } table[] = {
4544                 { '0', ACTION_POWEROFF },
4545                 { '6', ACTION_REBOOT },
4546                 { '1', ACTION_RESCUE },
4547                 { '2', ACTION_RUNLEVEL2 },
4548                 { '3', ACTION_RUNLEVEL3 },
4549                 { '4', ACTION_RUNLEVEL4 },
4550                 { '5', ACTION_RUNLEVEL5 },
4551                 { 's', ACTION_RESCUE },
4552                 { 'S', ACTION_RESCUE },
4553                 { 'q', ACTION_RELOAD },
4554                 { 'Q', ACTION_RELOAD },
4555                 { 'u', ACTION_REEXEC },
4556                 { 'U', ACTION_REEXEC }
4557         };
4558
4559         unsigned i;
4560         int c;
4561
4562         assert(argc >= 0);
4563         assert(argv);
4564
4565         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4566                 switch (c) {
4567
4568                 case ARG_HELP:
4569                         telinit_help();
4570                         return 0;
4571
4572                 case ARG_NO_WALL:
4573                         arg_no_wall = true;
4574                         break;
4575
4576                 case '?':
4577                         return -EINVAL;
4578
4579                 default:
4580                         log_error("Unknown option code '%c'.", c);
4581                         return -EINVAL;
4582                 }
4583         }
4584
4585         if (optind >= argc) {
4586                 telinit_help();
4587                 return -EINVAL;
4588         }
4589
4590         if (optind + 1 < argc) {
4591                 log_error("Too many arguments.");
4592                 return -EINVAL;
4593         }
4594
4595         if (strlen(argv[optind]) != 1) {
4596                 log_error("Expected single character argument.");
4597                 return -EINVAL;
4598         }
4599
4600         for (i = 0; i < ELEMENTSOF(table); i++)
4601                 if (table[i].from == argv[optind][0])
4602                         break;
4603
4604         if (i >= ELEMENTSOF(table)) {
4605                 log_error("Unknown command '%s'.", argv[optind]);
4606                 return -EINVAL;
4607         }
4608
4609         arg_action = table[i].to;
4610
4611         optind ++;
4612
4613         return 1;
4614 }
4615
4616 static int runlevel_parse_argv(int argc, char *argv[]) {
4617
4618         enum {
4619                 ARG_HELP = 0x100,
4620         };
4621
4622         static const struct option options[] = {
4623                 { "help",      no_argument,       NULL, ARG_HELP    },
4624                 { NULL,        0,                 NULL, 0           }
4625         };
4626
4627         int c;
4628
4629         assert(argc >= 0);
4630         assert(argv);
4631
4632         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4633                 switch (c) {
4634
4635                 case ARG_HELP:
4636                         runlevel_help();
4637                         return 0;
4638
4639                 case '?':
4640                         return -EINVAL;
4641
4642                 default:
4643                         log_error("Unknown option code '%c'.", c);
4644                         return -EINVAL;
4645                 }
4646         }
4647
4648         if (optind < argc) {
4649                 log_error("Too many arguments.");
4650                 return -EINVAL;
4651         }
4652
4653         return 1;
4654 }
4655
4656 static int parse_argv(int argc, char *argv[]) {
4657         assert(argc >= 0);
4658         assert(argv);
4659
4660         if (program_invocation_short_name) {
4661
4662                 if (strstr(program_invocation_short_name, "halt")) {
4663                         arg_action = ACTION_HALT;
4664                         return halt_parse_argv(argc, argv);
4665                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4666                         arg_action = ACTION_POWEROFF;
4667                         return halt_parse_argv(argc, argv);
4668                 } else if (strstr(program_invocation_short_name, "reboot")) {
4669                         if (kexec_loaded())
4670                                 arg_action = ACTION_KEXEC;
4671                         else
4672                                 arg_action = ACTION_REBOOT;
4673                         return halt_parse_argv(argc, argv);
4674                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4675                         arg_action = ACTION_POWEROFF;
4676                         return shutdown_parse_argv(argc, argv);
4677                 } else if (strstr(program_invocation_short_name, "init")) {
4678
4679                         if (sd_booted() > 0) {
4680                                 arg_action = ACTION_INVALID;
4681                                 return telinit_parse_argv(argc, argv);
4682                         } else {
4683                                 /* Hmm, so some other init system is
4684                                  * running, we need to forward this
4685                                  * request to it. For now we simply
4686                                  * guess that it is Upstart. */
4687
4688                                 execv("/lib/upstart/telinit", argv);
4689
4690                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4691                                 return -EIO;
4692                         }
4693
4694                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4695                         arg_action = ACTION_RUNLEVEL;
4696                         return runlevel_parse_argv(argc, argv);
4697                 }
4698         }
4699
4700         arg_action = ACTION_SYSTEMCTL;
4701         return systemctl_parse_argv(argc, argv);
4702 }
4703
4704 static int action_to_runlevel(void) {
4705
4706         static const char table[_ACTION_MAX] = {
4707                 [ACTION_HALT] =      '0',
4708                 [ACTION_POWEROFF] =  '0',
4709                 [ACTION_REBOOT] =    '6',
4710                 [ACTION_RUNLEVEL2] = '2',
4711                 [ACTION_RUNLEVEL3] = '3',
4712                 [ACTION_RUNLEVEL4] = '4',
4713                 [ACTION_RUNLEVEL5] = '5',
4714                 [ACTION_RESCUE] =    '1'
4715         };
4716
4717         assert(arg_action < _ACTION_MAX);
4718
4719         return table[arg_action];
4720 }
4721
4722 static int talk_upstart(void) {
4723         DBusMessage *m = NULL, *reply = NULL;
4724         DBusError error;
4725         int previous, rl, r;
4726         char
4727                 env1_buf[] = "RUNLEVEL=X",
4728                 env2_buf[] = "PREVLEVEL=X";
4729         char *env1 = env1_buf, *env2 = env2_buf;
4730         const char *emit = "runlevel";
4731         dbus_bool_t b_false = FALSE;
4732         DBusMessageIter iter, sub;
4733         DBusConnection *bus;
4734
4735         dbus_error_init(&error);
4736
4737         if (!(rl = action_to_runlevel()))
4738                 return 0;
4739
4740         if (utmp_get_runlevel(&previous, NULL) < 0)
4741                 previous = 'N';
4742
4743         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4744                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4745                         r = 0;
4746                         goto finish;
4747                 }
4748
4749                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4750                 r = -EIO;
4751                 goto finish;
4752         }
4753
4754         if ((r = bus_check_peercred(bus)) < 0) {
4755                 log_error("Failed to verify owner of bus.");
4756                 goto finish;
4757         }
4758
4759         if (!(m = dbus_message_new_method_call(
4760                               "com.ubuntu.Upstart",
4761                               "/com/ubuntu/Upstart",
4762                               "com.ubuntu.Upstart0_6",
4763                               "EmitEvent"))) {
4764
4765                 log_error("Could not allocate message.");
4766                 r = -ENOMEM;
4767                 goto finish;
4768         }
4769
4770         dbus_message_iter_init_append(m, &iter);
4771
4772         env1_buf[sizeof(env1_buf)-2] = rl;
4773         env2_buf[sizeof(env2_buf)-2] = previous;
4774
4775         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4776             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4777             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4778             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4779             !dbus_message_iter_close_container(&iter, &sub) ||
4780             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4781                 log_error("Could not append arguments to message.");
4782                 r = -ENOMEM;
4783                 goto finish;
4784         }
4785
4786         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4787
4788                 if (bus_error_is_no_service(&error)) {
4789                         r = -EADDRNOTAVAIL;
4790                         goto finish;
4791                 }
4792
4793                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4794                 r = -EIO;
4795                 goto finish;
4796         }
4797
4798         r = 1;
4799
4800 finish:
4801         if (m)
4802                 dbus_message_unref(m);
4803
4804         if (reply)
4805                 dbus_message_unref(reply);
4806
4807         if (bus) {
4808                 dbus_connection_flush(bus);
4809                 dbus_connection_close(bus);
4810                 dbus_connection_unref(bus);
4811         }
4812
4813         dbus_error_free(&error);
4814
4815         return r;
4816 }
4817
4818 static int talk_initctl(void) {
4819         struct init_request request;
4820         int r, fd;
4821         char rl;
4822
4823         if (!(rl = action_to_runlevel()))
4824                 return 0;
4825
4826         zero(request);
4827         request.magic = INIT_MAGIC;
4828         request.sleeptime = 0;
4829         request.cmd = INIT_CMD_RUNLVL;
4830         request.runlevel = rl;
4831
4832         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4833
4834                 if (errno == ENOENT)
4835                         return 0;
4836
4837                 log_error("Failed to open "INIT_FIFO": %m");
4838                 return -errno;
4839         }
4840
4841         errno = 0;
4842         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4843         close_nointr_nofail(fd);
4844
4845         if (r < 0) {
4846                 log_error("Failed to write to "INIT_FIFO": %m");
4847                 return errno ? -errno : -EIO;
4848         }
4849
4850         return 1;
4851 }
4852
4853 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4854
4855         static const struct {
4856                 const char* verb;
4857                 const enum {
4858                         MORE,
4859                         LESS,
4860                         EQUAL
4861                 } argc_cmp;
4862                 const int argc;
4863                 int (* const dispatch)(DBusConnection *bus, char **args);
4864         } verbs[] = {
4865                 { "list-units",            LESS,  1, list_units        },
4866                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
4867                 { "list-jobs",             EQUAL, 1, list_jobs         },
4868                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
4869                 { "load",                  MORE,  2, load_unit         },
4870                 { "cancel",                MORE,  2, cancel_job        },
4871                 { "start",                 MORE,  2, start_unit        },
4872                 { "stop",                  MORE,  2, start_unit        },
4873                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4874                 { "reload",                MORE,  2, start_unit        },
4875                 { "restart",               MORE,  2, start_unit        },
4876                 { "try-restart",           MORE,  2, start_unit        },
4877                 { "reload-or-restart",     MORE,  2, start_unit        },
4878                 { "reload-or-try-restart", MORE,  2, start_unit        },
4879                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
4880                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4881                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
4882                 { "isolate",               EQUAL, 2, start_unit        },
4883                 { "kill",                  MORE,  2, kill_unit         },
4884                 { "is-active",             MORE,  2, check_unit        },
4885                 { "check",                 MORE,  2, check_unit        },
4886                 { "show",                  MORE,  1, show              },
4887                 { "status",                MORE,  2, show              },
4888                 { "help",                  MORE,  2, show              },
4889                 { "dump",                  EQUAL, 1, dump              },
4890                 { "dot",                   EQUAL, 1, dot               },
4891                 { "snapshot",              LESS,  2, snapshot          },
4892                 { "delete",                MORE,  2, delete_snapshot   },
4893                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
4894                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
4895                 { "show-environment",      EQUAL, 1, show_enviroment   },
4896                 { "set-environment",       MORE,  2, set_environment   },
4897                 { "unset-environment",     MORE,  2, set_environment   },
4898                 { "halt",                  EQUAL, 1, start_special     },
4899                 { "poweroff",              EQUAL, 1, start_special     },
4900                 { "reboot",                EQUAL, 1, start_special     },
4901                 { "kexec",                 EQUAL, 1, start_special     },
4902                 { "suspend",               EQUAL, 1, start_special     },
4903                 { "hibernate",             EQUAL, 1, start_special     },
4904                 { "default",               EQUAL, 1, start_special     },
4905                 { "rescue",                EQUAL, 1, start_special     },
4906                 { "emergency",             EQUAL, 1, start_special     },
4907                 { "exit",                  EQUAL, 1, start_special     },
4908                 { "reset-failed",          MORE,  1, reset_failed      },
4909                 { "enable",                MORE,  2, enable_unit       },
4910                 { "disable",               MORE,  2, enable_unit       },
4911                 { "is-enabled",            MORE,  2, unit_is_enabled   },
4912                 { "reenable",              MORE,  2, enable_unit       },
4913                 { "preset",                MORE,  2, enable_unit       },
4914                 { "mask",                  MORE,  2, enable_unit       },
4915                 { "unmask",                MORE,  2, enable_unit       },
4916                 { "link",                  MORE,  2, enable_unit       },
4917                 { "switch-root",           MORE,  2, switch_root       },
4918         };
4919
4920         int left;
4921         unsigned i;
4922
4923         assert(argc >= 0);
4924         assert(argv);
4925         assert(error);
4926
4927         left = argc - optind;
4928
4929         if (left <= 0)
4930                 /* Special rule: no arguments means "list-units" */
4931                 i = 0;
4932         else {
4933                 if (streq(argv[optind], "help") && !argv[optind+1]) {
4934                         log_error("This command expects one or more "
4935                                   "unit names. Did you mean --help?");
4936                         return -EINVAL;
4937                 }
4938
4939                 for (i = 0; i < ELEMENTSOF(verbs); i++)
4940                         if (streq(argv[optind], verbs[i].verb))
4941                                 break;
4942
4943                 if (i >= ELEMENTSOF(verbs)) {
4944                         log_error("Unknown operation '%s'.", argv[optind]);
4945                         return -EINVAL;
4946                 }
4947         }
4948
4949         switch (verbs[i].argc_cmp) {
4950
4951         case EQUAL:
4952                 if (left != verbs[i].argc) {
4953                         log_error("Invalid number of arguments.");
4954                         return -EINVAL;
4955                 }
4956
4957                 break;
4958
4959         case MORE:
4960                 if (left < verbs[i].argc) {
4961                         log_error("Too few arguments.");
4962                         return -EINVAL;
4963                 }
4964
4965                 break;
4966
4967         case LESS:
4968                 if (left > verbs[i].argc) {
4969                         log_error("Too many arguments.");
4970                         return -EINVAL;
4971                 }
4972
4973                 break;
4974
4975         default:
4976                 assert_not_reached("Unknown comparison operator.");
4977         }
4978
4979         /* Require a bus connection for all operations but
4980          * enable/disable */
4981         if (!streq(verbs[i].verb, "enable") &&
4982             !streq(verbs[i].verb, "disable") &&
4983             !streq(verbs[i].verb, "is-enabled") &&
4984             !streq(verbs[i].verb, "list-unit-files") &&
4985             !streq(verbs[i].verb, "reenable") &&
4986             !streq(verbs[i].verb, "preset") &&
4987             !streq(verbs[i].verb, "mask") &&
4988             !streq(verbs[i].verb, "unmask") &&
4989             !streq(verbs[i].verb, "link")) {
4990
4991                 if (running_in_chroot() > 0) {
4992                         log_info("Running in chroot, ignoring request.");
4993                         return 0;
4994                 }
4995
4996                 if (((!streq(verbs[i].verb, "reboot") &&
4997                       !streq(verbs[i].verb, "halt") &&
4998                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
4999                         log_error("Failed to get D-Bus connection: %s",
5000                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5001                         return -EIO;
5002                 }
5003
5004         } else {
5005
5006                 if (!bus && !avoid_bus()) {
5007                         log_error("Failed to get D-Bus connection: %s",
5008                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5009                         return -EIO;
5010                 }
5011         }
5012
5013         return verbs[i].dispatch(bus, argv + optind);
5014 }
5015
5016 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5017         int fd;
5018         struct msghdr msghdr;
5019         struct iovec iovec[2];
5020         union sockaddr_union sockaddr;
5021         struct sd_shutdown_command c;
5022
5023         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5024         if (fd < 0)
5025                 return -errno;
5026
5027         zero(c);
5028         c.usec = t;
5029         c.mode = mode;
5030         c.dry_run = dry_run;
5031         c.warn_wall = warn;
5032
5033         zero(sockaddr);
5034         sockaddr.sa.sa_family = AF_UNIX;
5035         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5036
5037         zero(msghdr);
5038         msghdr.msg_name = &sockaddr;
5039         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5040
5041         zero(iovec);
5042         iovec[0].iov_base = (char*) &c;
5043         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5044
5045         if (isempty(message))
5046                 msghdr.msg_iovlen = 1;
5047         else {
5048                 iovec[1].iov_base = (char*) message;
5049                 iovec[1].iov_len = strlen(message);
5050                 msghdr.msg_iovlen = 2;
5051         }
5052         msghdr.msg_iov = iovec;
5053
5054         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5055                 close_nointr_nofail(fd);
5056                 return -errno;
5057         }
5058
5059         close_nointr_nofail(fd);
5060         return 0;
5061 }
5062
5063 static int reload_with_fallback(DBusConnection *bus) {
5064
5065         if (bus) {
5066                 /* First, try systemd via D-Bus. */
5067                 if (daemon_reload(bus, NULL) >= 0)
5068                         return 0;
5069         }
5070
5071         /* Nothing else worked, so let's try signals */
5072         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5073
5074         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5075                 log_error("kill() failed: %m");
5076                 return -errno;
5077         }
5078
5079         return 0;
5080 }
5081
5082 static int start_with_fallback(DBusConnection *bus) {
5083
5084         if (bus) {
5085                 /* First, try systemd via D-Bus. */
5086                 if (start_unit(bus, NULL) >= 0)
5087                         goto done;
5088         }
5089
5090         /* Hmm, talking to systemd via D-Bus didn't work. Then
5091          * let's try to talk to Upstart via D-Bus. */
5092         if (talk_upstart() > 0)
5093                 goto done;
5094
5095         /* Nothing else worked, so let's try
5096          * /dev/initctl */
5097         if (talk_initctl() > 0)
5098                 goto done;
5099
5100         log_error("Failed to talk to init daemon.");
5101         return -EIO;
5102
5103 done:
5104         warn_wall(arg_action);
5105         return 0;
5106 }
5107
5108 static _noreturn_ void halt_now(enum action a) {
5109
5110        /* Make sure C-A-D is handled by the kernel from this
5111          * point on... */
5112         reboot(RB_ENABLE_CAD);
5113
5114         switch (a) {
5115
5116         case ACTION_HALT:
5117                 log_info("Halting.");
5118                 reboot(RB_HALT_SYSTEM);
5119                 break;
5120
5121         case ACTION_POWEROFF:
5122                 log_info("Powering off.");
5123                 reboot(RB_POWER_OFF);
5124                 break;
5125
5126         case ACTION_REBOOT:
5127                 log_info("Rebooting.");
5128                 reboot(RB_AUTOBOOT);
5129                 break;
5130
5131         default:
5132                 assert_not_reached("Unknown halt action.");
5133         }
5134
5135         assert_not_reached("Uh? This shouldn't happen.");
5136 }
5137
5138 static int halt_main(DBusConnection *bus) {
5139         int r;
5140
5141         if (geteuid() != 0) {
5142                 /* Try logind if we are a normal user and no special
5143                  * mode applies. Maybe PolicyKit allows us to shutdown
5144                  * the machine. */
5145
5146                 if (arg_when <= 0 &&
5147                     !arg_dry &&
5148                     !arg_force &&
5149                     (arg_action == ACTION_POWEROFF ||
5150                      arg_action == ACTION_REBOOT)) {
5151                         r = reboot_with_logind(bus, arg_action);
5152                         if (r >= 0)
5153                                 return r;
5154                 }
5155
5156                 log_error("Must be root.");
5157                 return -EPERM;
5158         }
5159
5160         if (arg_when > 0) {
5161                 char *m;
5162
5163                 m = strv_join(arg_wall, " ");
5164                 r = send_shutdownd(arg_when,
5165                                    arg_action == ACTION_HALT     ? 'H' :
5166                                    arg_action == ACTION_POWEROFF ? 'P' :
5167                                    arg_action == ACTION_KEXEC    ? 'K' :
5168                                                                    'r',
5169                                    arg_dry,
5170                                    !arg_no_wall,
5171                                    m);
5172                 free(m);
5173
5174                 if (r < 0)
5175                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5176                 else {
5177                         char date[FORMAT_TIMESTAMP_MAX];
5178
5179                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5180                                  format_timestamp(date, sizeof(date), arg_when));
5181                         return 0;
5182                 }
5183         }
5184
5185         if (!arg_dry && !arg_force)
5186                 return start_with_fallback(bus);
5187
5188         if (!arg_no_wtmp) {
5189                 if (sd_booted() > 0)
5190                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5191                 else {
5192                         r = utmp_put_shutdown();
5193                         if (r < 0)
5194                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5195                 }
5196         }
5197
5198         if (arg_dry)
5199                 return 0;
5200
5201         halt_now(arg_action);
5202         /* We should never reach this. */
5203         return -ENOSYS;
5204 }
5205
5206 static int runlevel_main(void) {
5207         int r, runlevel, previous;
5208
5209         r = utmp_get_runlevel(&runlevel, &previous);
5210         if (r < 0) {
5211                 puts("unknown");
5212                 return r;
5213         }
5214
5215         printf("%c %c\n",
5216                previous <= 0 ? 'N' : previous,
5217                runlevel <= 0 ? 'N' : runlevel);
5218
5219         return 0;
5220 }
5221
5222 int main(int argc, char*argv[]) {
5223         int r, retval = EXIT_FAILURE;
5224         DBusConnection *bus = NULL;
5225         DBusError error;
5226
5227         dbus_error_init(&error);
5228
5229         log_parse_environment();
5230         log_open();
5231
5232         r = parse_argv(argc, argv);
5233         if (r < 0)
5234                 goto finish;
5235         else if (r == 0) {
5236                 retval = EXIT_SUCCESS;
5237                 goto finish;
5238         }
5239
5240         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5241          * let's shortcut this */
5242         if (arg_action == ACTION_RUNLEVEL) {
5243                 r = runlevel_main();
5244                 retval = r < 0 ? EXIT_FAILURE : r;
5245                 goto finish;
5246         }
5247
5248         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5249                 log_info("Running in chroot, ignoring request.");
5250                 retval = 0;
5251                 goto finish;
5252         }
5253
5254         if (!avoid_bus()) {
5255                 if (arg_transport == TRANSPORT_NORMAL)
5256                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5257                 else if (arg_transport == TRANSPORT_POLKIT) {
5258                         bus_connect_system_polkit(&bus, &error);
5259                         private_bus = false;
5260                 } else if (arg_transport == TRANSPORT_SSH) {
5261                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5262                         private_bus = false;
5263                 } else
5264                         assert_not_reached("Uh, invalid transport...");
5265         }
5266
5267         switch (arg_action) {
5268
5269         case ACTION_SYSTEMCTL:
5270                 r = systemctl_main(bus, argc, argv, &error);
5271                 break;
5272
5273         case ACTION_HALT:
5274         case ACTION_POWEROFF:
5275         case ACTION_REBOOT:
5276         case ACTION_KEXEC:
5277                 r = halt_main(bus);
5278                 break;
5279
5280         case ACTION_RUNLEVEL2:
5281         case ACTION_RUNLEVEL3:
5282         case ACTION_RUNLEVEL4:
5283         case ACTION_RUNLEVEL5:
5284         case ACTION_RESCUE:
5285         case ACTION_EMERGENCY:
5286         case ACTION_DEFAULT:
5287                 r = start_with_fallback(bus);
5288                 break;
5289
5290         case ACTION_RELOAD:
5291         case ACTION_REEXEC:
5292                 r = reload_with_fallback(bus);
5293                 break;
5294
5295         case ACTION_CANCEL_SHUTDOWN: {
5296                 char *m = NULL;
5297
5298                 if (arg_wall) {
5299                         m = strv_join(arg_wall, " ");
5300                         if (!m) {
5301                                 retval = EXIT_FAILURE;
5302                                 goto finish;
5303                         }
5304                 }
5305                 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5306                 if (r < 0)
5307                         log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5308                 free(m);
5309                 break;
5310         }
5311
5312         case ACTION_INVALID:
5313         case ACTION_RUNLEVEL:
5314         default:
5315                 assert_not_reached("Unknown action");
5316         }
5317
5318         retval = r < 0 ? EXIT_FAILURE : r;
5319
5320 finish:
5321         if (bus) {
5322                 dbus_connection_flush(bus);
5323                 dbus_connection_close(bus);
5324                 dbus_connection_unref(bus);
5325         }
5326
5327         dbus_error_free(&error);
5328
5329         dbus_shutdown();
5330
5331         strv_free(arg_property);
5332
5333         pager_close();
5334         ask_password_agent_close();
5335         polkit_agent_close();
5336
5337         return retval;
5338 }