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