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