chiark / gitweb /
core: add bus API and systemctl commands for altering cgroup parameters during runtime
[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 <locale.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/ioctl.h>
30 #include <termios.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/socket.h>
34 #include <sys/stat.h>
35 #include <stddef.h>
36 #include <sys/prctl.h>
37 #include <dbus/dbus.h>
38
39 #include <systemd/sd-daemon.h>
40 #include <systemd/sd-shutdown.h>
41
42 #include "log.h"
43 #include "util.h"
44 #include "macro.h"
45 #include "set.h"
46 #include "utmp-wtmp.h"
47 #include "special.h"
48 #include "initreq.h"
49 #include "path-util.h"
50 #include "strv.h"
51 #include "dbus-common.h"
52 #include "cgroup-show.h"
53 #include "cgroup-util.h"
54 #include "list.h"
55 #include "path-lookup.h"
56 #include "conf-parser.h"
57 #include "exit-status.h"
58 #include "bus-errors.h"
59 #include "build.h"
60 #include "unit-name.h"
61 #include "pager.h"
62 #include "spawn-ask-password-agent.h"
63 #include "spawn-polkit-agent.h"
64 #include "install.h"
65 #include "logs-show.h"
66 #include "path-util.h"
67 #include "socket-util.h"
68
69 static const char *arg_type = NULL;
70 static const char *arg_load_state = NULL;
71 static char **arg_property = NULL;
72 static bool arg_all = false;
73 static const char *arg_job_mode = "replace";
74 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
75 static bool arg_no_block = false;
76 static bool arg_no_legend = false;
77 static bool arg_no_pager = false;
78 static bool arg_no_wtmp = false;
79 static bool arg_no_wall = false;
80 static bool arg_no_reload = false;
81 static bool arg_ignore_inhibitors = false;
82 static bool arg_dry = false;
83 static bool arg_quiet = false;
84 static bool arg_full = false;
85 static int arg_force = 0;
86 static bool arg_ask_password = true;
87 static bool arg_failed = false;
88 static bool arg_runtime = false;
89 static char **arg_wall = NULL;
90 static const char *arg_kill_who = NULL;
91 static int arg_signal = SIGTERM;
92 static const char *arg_root = NULL;
93 static usec_t arg_when = 0;
94 static enum action {
95         ACTION_INVALID,
96         ACTION_SYSTEMCTL,
97         ACTION_HALT,
98         ACTION_POWEROFF,
99         ACTION_REBOOT,
100         ACTION_KEXEC,
101         ACTION_EXIT,
102         ACTION_SUSPEND,
103         ACTION_HIBERNATE,
104         ACTION_HYBRID_SLEEP,
105         ACTION_RUNLEVEL2,
106         ACTION_RUNLEVEL3,
107         ACTION_RUNLEVEL4,
108         ACTION_RUNLEVEL5,
109         ACTION_RESCUE,
110         ACTION_EMERGENCY,
111         ACTION_DEFAULT,
112         ACTION_RELOAD,
113         ACTION_REEXEC,
114         ACTION_RUNLEVEL,
115         ACTION_CANCEL_SHUTDOWN,
116         _ACTION_MAX
117 } arg_action = ACTION_SYSTEMCTL;
118 static enum dot {
119         DOT_ALL,
120         DOT_ORDER,
121         DOT_REQUIRE
122 } arg_dot = DOT_ALL;
123 static enum transport {
124         TRANSPORT_NORMAL,
125         TRANSPORT_SSH,
126         TRANSPORT_POLKIT
127 } arg_transport = TRANSPORT_NORMAL;
128 static const char *arg_host = NULL;
129 static unsigned arg_lines = 10;
130 static OutputMode arg_output = OUTPUT_SHORT;
131
132 static bool private_bus = false;
133
134 static int daemon_reload(DBusConnection *bus, char **args);
135 static void halt_now(enum action a);
136
137 static void pager_open_if_enabled(void) {
138
139         if (arg_no_pager)
140                 return;
141
142         pager_open();
143 }
144
145 static void ask_password_agent_open_if_enabled(void) {
146
147         /* Open the password agent as a child process if necessary */
148
149         if (!arg_ask_password)
150                 return;
151
152         if (arg_scope != UNIT_FILE_SYSTEM)
153                 return;
154
155         ask_password_agent_open();
156 }
157
158 #ifdef HAVE_LOGIND
159 static void polkit_agent_open_if_enabled(void) {
160
161         /* Open the polkit agent as a child process if necessary */
162
163         if (!arg_ask_password)
164                 return;
165
166         if (arg_scope != UNIT_FILE_SYSTEM)
167                 return;
168
169         polkit_agent_open();
170 }
171 #endif
172
173 static const char *ansi_highlight(bool b) {
174
175         if (!on_tty())
176                 return "";
177
178         return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
179 }
180
181 static const char *ansi_highlight_red(bool b) {
182
183         if (!on_tty())
184                 return "";
185
186         return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
187 }
188
189 static const char *ansi_highlight_green(bool b) {
190
191         if (!on_tty())
192                 return "";
193
194         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
195 }
196
197 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
198         assert(error);
199
200         if (!dbus_error_is_set(error))
201                 return r;
202
203         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
204             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
205             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
206             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
207                 return EXIT_NOPERMISSION;
208
209         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
210                 return EXIT_NOTINSTALLED;
211
212         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
213             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
214                 return EXIT_NOTIMPLEMENTED;
215
216         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
217                 return EXIT_NOTCONFIGURED;
218
219         if (r != 0)
220                 return r;
221
222         return EXIT_FAILURE;
223 }
224
225 static void warn_wall(enum action a) {
226         static const char *table[_ACTION_MAX] = {
227                 [ACTION_HALT]            = "The system is going down for system halt NOW!",
228                 [ACTION_REBOOT]          = "The system is going down for reboot NOW!",
229                 [ACTION_POWEROFF]        = "The system is going down for power-off NOW!",
230                 [ACTION_KEXEC]           = "The system is going down for kexec reboot NOW!",
231                 [ACTION_RESCUE]          = "The system is going down to rescue mode NOW!",
232                 [ACTION_EMERGENCY]       = "The system is going down to emergency mode NOW!",
233                 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
234         };
235
236         if (arg_no_wall)
237                 return;
238
239         if (arg_wall) {
240                 char *p;
241
242                 p = strv_join(arg_wall, " ");
243                 if (!p) {
244                         log_error("Failed to join strings.");
245                         return;
246                 }
247
248                 if (*p) {
249                         utmp_wall(p, NULL);
250                         free(p);
251                         return;
252                 }
253
254                 free(p);
255         }
256
257         if (!table[a])
258                 return;
259
260         utmp_wall(table[a], NULL);
261 }
262
263 static bool avoid_bus(void) {
264
265         if (running_in_chroot() > 0)
266                 return true;
267
268         if (sd_booted() <= 0)
269                 return true;
270
271         if (!isempty(arg_root))
272                 return true;
273
274         if (arg_scope == UNIT_FILE_GLOBAL)
275                 return true;
276
277         return false;
278 }
279
280 struct unit_info {
281         const char *id;
282         const char *description;
283         const char *load_state;
284         const char *active_state;
285         const char *sub_state;
286         const char *following;
287         const char *unit_path;
288         uint32_t job_id;
289         const char *job_type;
290         const char *job_path;
291 };
292
293 static int compare_unit_info(const void *a, const void *b) {
294         const char *d1, *d2;
295         const struct unit_info *u = a, *v = b;
296
297         d1 = strrchr(u->id, '.');
298         d2 = strrchr(v->id, '.');
299
300         if (d1 && d2) {
301                 int r;
302
303                 if ((r = strcasecmp(d1, d2)) != 0)
304                         return r;
305         }
306
307         return strcasecmp(u->id, v->id);
308 }
309
310 static bool output_show_unit(const struct unit_info *u) {
311         const char *dot;
312
313         if (arg_failed)
314                 return streq(u->active_state, "failed");
315
316         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
317                               streq(dot+1, arg_type))) &&
318                 (!arg_load_state || streq(u->load_state, arg_load_state)) &&
319                 (arg_all || !(streq(u->active_state, "inactive")
320                               || u->following[0]) || u->job_id > 0);
321 }
322
323 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
324         unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
325         const struct unit_info *u;
326         int job_count = 0;
327
328         max_id_len = sizeof("UNIT")-1;
329         active_len = sizeof("ACTIVE")-1;
330         sub_len = sizeof("SUB")-1;
331         job_len = sizeof("JOB")-1;
332         desc_len = 0;
333
334         for (u = unit_infos; u < unit_infos + c; u++) {
335                 if (!output_show_unit(u))
336                         continue;
337
338                 max_id_len = MAX(max_id_len, strlen(u->id));
339                 active_len = MAX(active_len, strlen(u->active_state));
340                 sub_len = MAX(sub_len, strlen(u->sub_state));
341                 if (u->job_id != 0) {
342                         job_len = MAX(job_len, strlen(u->job_type));
343                         job_count++;
344                 }
345         }
346
347         if (!arg_full) {
348                 unsigned basic_len;
349                 id_len = MIN(max_id_len, 25);
350                 basic_len = 5 + id_len + 5 + active_len + sub_len;
351                 if (job_count)
352                         basic_len += job_len + 1;
353                 if (basic_len < (unsigned) columns()) {
354                         unsigned extra_len, incr;
355                         extra_len = columns() - basic_len;
356                         /* Either UNIT already got 25, or is fully satisfied.
357                          * Grant up to 25 to DESC now. */
358                         incr = MIN(extra_len, 25);
359                         desc_len += incr;
360                         extra_len -= incr;
361                         /* split the remaining space between UNIT and DESC,
362                          * but do not give UNIT more than it needs. */
363                         if (extra_len > 0) {
364                                 incr = MIN(extra_len / 2, max_id_len - id_len);
365                                 id_len += incr;
366                                 desc_len += extra_len - incr;
367                         }
368                 }
369         } else
370                 id_len = max_id_len;
371
372         for (u = unit_infos; u < unit_infos + c; u++) {
373                 char *e;
374                 const char *on_loaded, *off_loaded;
375                 const char *on_active, *off_active;
376
377                 if (!output_show_unit(u))
378                         continue;
379
380                 if (!n_shown && !arg_no_legend) {
381                         printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
382                                active_len, "ACTIVE", sub_len, "SUB");
383                         if (job_count)
384                                 printf("%-*s ", job_len, "JOB");
385                         if (!arg_full && arg_no_pager)
386                                 printf("%.*s\n", desc_len, "DESCRIPTION");
387                         else
388                                 printf("%s\n", "DESCRIPTION");
389                 }
390
391                 n_shown++;
392
393                 if (streq(u->load_state, "error")) {
394                         on_loaded = ansi_highlight_red(true);
395                         off_loaded = ansi_highlight_red(false);
396                 } else
397                         on_loaded = off_loaded = "";
398
399                 if (streq(u->active_state, "failed")) {
400                         on_active = ansi_highlight_red(true);
401                         off_active = ansi_highlight_red(false);
402                 } else
403                         on_active = off_active = "";
404
405                 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
406
407                 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s",
408                        id_len, e ? e : u->id,
409                        on_loaded, u->load_state, off_loaded,
410                        on_active, active_len, u->active_state,
411                        sub_len, u->sub_state, off_active,
412                        job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
413                 if (!arg_full && arg_no_pager)
414                         printf("%.*s\n", desc_len, u->description);
415                 else
416                         printf("%s\n", u->description);
417
418                 free(e);
419         }
420
421         if (!arg_no_legend) {
422                 const char *on, *off;
423
424                 if (n_shown) {
425                         printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
426                                "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
427                                "SUB    = The low-level unit activation state, values depend on unit type.\n");
428                         if (job_count)
429                                 printf("JOB    = Pending job for the unit.\n");
430                         puts("");
431                         on = ansi_highlight(true);
432                         off = ansi_highlight(false);
433                 } else {
434                         on = ansi_highlight_red(true);
435                         off = ansi_highlight_red(false);
436                 }
437
438                 if (arg_all)
439                         printf("%s%u loaded units listed.%s\n"
440                                "To show all installed unit files use 'systemctl list-unit-files'.\n",
441                                on, n_shown, off);
442                 else
443                         printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
444                                "To show all installed unit files use 'systemctl list-unit-files'.\n",
445                                on, n_shown, off);
446         }
447 }
448
449 static int list_units(DBusConnection *bus, char **args) {
450         DBusMessage *reply = NULL;
451         int r;
452         DBusMessageIter iter, sub, sub2;
453         unsigned c = 0, n_units = 0;
454         struct unit_info *unit_infos = NULL;
455
456         pager_open_if_enabled();
457
458         r = bus_method_call_with_reply (
459                         bus,
460                         "org.freedesktop.systemd1",
461                         "/org/freedesktop/systemd1",
462                         "org.freedesktop.systemd1.Manager",
463                         "ListUnits",
464                         &reply,
465                         NULL,
466                         DBUS_TYPE_INVALID);
467         if (r)
468                 goto finish;
469
470         if (!dbus_message_iter_init(reply, &iter) ||
471             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
472             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
473                 log_error("Failed to parse reply.");
474                 r = -EIO;
475                 goto finish;
476         }
477
478         dbus_message_iter_recurse(&iter, &sub);
479
480         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
481                 struct unit_info *u;
482
483                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
484                         log_error("Failed to parse reply.");
485                         r = -EIO;
486                         goto finish;
487                 }
488
489                 if (c >= n_units) {
490                         struct unit_info *w;
491
492                         n_units = MAX(2*c, 16);
493                         w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
494
495                         if (!w) {
496                                 log_error("Failed to allocate unit array.");
497                                 r = -ENOMEM;
498                                 goto finish;
499                         }
500
501                         unit_infos = w;
502                 }
503
504                 u = unit_infos+c;
505
506                 dbus_message_iter_recurse(&sub, &sub2);
507
508                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
509                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
510                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
511                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
512                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
513                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
514                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
515                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
516                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
517                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
518                         log_error("Failed to parse reply.");
519                         r = -EIO;
520                         goto finish;
521                 }
522
523                 dbus_message_iter_next(&sub);
524                 c++;
525         }
526
527         if (c > 0) {
528                 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
529                 output_units_list(unit_infos, c);
530         }
531
532 finish:
533         if (reply)
534                 dbus_message_unref(reply);
535
536         free(unit_infos);
537
538         return r;
539 }
540
541 static int compare_unit_file_list(const void *a, const void *b) {
542         const char *d1, *d2;
543         const UnitFileList *u = a, *v = b;
544
545         d1 = strrchr(u->path, '.');
546         d2 = strrchr(v->path, '.');
547
548         if (d1 && d2) {
549                 int r;
550
551                 r = strcasecmp(d1, d2);
552                 if (r != 0)
553                         return r;
554         }
555
556         return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
557 }
558
559 static bool output_show_unit_file(const UnitFileList *u) {
560         const char *dot;
561
562         return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
563 }
564
565 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
566         unsigned max_id_len, id_cols, state_cols, n_shown = 0;
567         const UnitFileList *u;
568
569         max_id_len = sizeof("UNIT FILE")-1;
570         state_cols = sizeof("STATE")-1;
571         for (u = units; u < units + c; u++) {
572                 if (!output_show_unit_file(u))
573                         continue;
574
575                 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
576                 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
577         }
578
579         if (!arg_full) {
580                 unsigned basic_cols;
581                 id_cols = MIN(max_id_len, 25);
582                 basic_cols = 1 + id_cols + state_cols;
583                 if (basic_cols < (unsigned) columns())
584                         id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
585         } else
586                 id_cols = max_id_len;
587
588         if (!arg_no_legend)
589                 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
590
591         for (u = units; u < units + c; u++) {
592                 char *e;
593                 const char *on, *off;
594                 const char *id;
595
596                 if (!output_show_unit_file(u))
597                         continue;
598
599                 n_shown++;
600
601                 if (u->state == UNIT_FILE_MASKED ||
602                     u->state == UNIT_FILE_MASKED_RUNTIME ||
603                     u->state == UNIT_FILE_DISABLED ||
604                     u->state == UNIT_FILE_INVALID) {
605                         on  = ansi_highlight_red(true);
606                         off = ansi_highlight_red(false);
607                 } else if (u->state == UNIT_FILE_ENABLED) {
608                         on  = ansi_highlight_green(true);
609                         off = ansi_highlight_green(false);
610                 } else
611                         on = off = "";
612
613                 id = path_get_file_name(u->path);
614
615                 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
616
617                 printf("%-*s %s%-*s%s\n",
618                        id_cols, e ? e : id,
619                        on, state_cols, unit_file_state_to_string(u->state), off);
620
621                 free(e);
622         }
623
624         if (!arg_no_legend)
625                 printf("\n%u unit files listed.\n", n_shown);
626 }
627
628 static int list_unit_files(DBusConnection *bus, char **args) {
629         DBusMessage *reply = NULL;
630         int r;
631         DBusMessageIter iter, sub, sub2;
632         unsigned c = 0, n_units = 0;
633         UnitFileList *units = NULL;
634
635         pager_open_if_enabled();
636
637         if (avoid_bus()) {
638                 Hashmap *h;
639                 UnitFileList *u;
640                 Iterator i;
641
642                 h = hashmap_new(string_hash_func, string_compare_func);
643                 if (!h)
644                         return log_oom();
645
646                 r = unit_file_get_list(arg_scope, arg_root, h);
647                 if (r < 0) {
648                         unit_file_list_free(h);
649                         log_error("Failed to get unit file list: %s", strerror(-r));
650                         return r;
651                 }
652
653                 n_units = hashmap_size(h);
654                 units = new(UnitFileList, n_units);
655                 if (!units) {
656                         unit_file_list_free(h);
657                         return log_oom();
658                 }
659
660                 HASHMAP_FOREACH(u, h, i) {
661                         memcpy(units + c++, u, sizeof(UnitFileList));
662                         free(u);
663                 }
664
665                 hashmap_free(h);
666         } else {
667                 r = bus_method_call_with_reply (
668                                 bus,
669                                 "org.freedesktop.systemd1",
670                                 "/org/freedesktop/systemd1",
671                                 "org.freedesktop.systemd1.Manager",
672                                 "ListUnitFiles",
673                                 &reply,
674                                 NULL,
675                                 DBUS_TYPE_INVALID);
676                 if (r)
677                         goto finish;
678
679                 if (!dbus_message_iter_init(reply, &iter) ||
680                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
681                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
682                         log_error("Failed to parse reply.");
683                         r = -EIO;
684                         goto finish;
685                 }
686
687                 dbus_message_iter_recurse(&iter, &sub);
688
689                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
690                         UnitFileList *u;
691                         const char *state;
692
693                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
694                                 log_error("Failed to parse reply.");
695                                 r = -EIO;
696                                 goto finish;
697                         }
698
699                         if (c >= n_units) {
700                                 UnitFileList *w;
701
702                                 n_units = MAX(2*c, 16);
703                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
704
705                                 if (!w) {
706                                         log_error("Failed to allocate unit array.");
707                                         r = -ENOMEM;
708                                         goto finish;
709                                 }
710
711                                 units = w;
712                         }
713
714                         u = units+c;
715
716                         dbus_message_iter_recurse(&sub, &sub2);
717
718                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
719                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
720                                 log_error("Failed to parse reply.");
721                                 r = -EIO;
722                                 goto finish;
723                         }
724
725                         u->state = unit_file_state_from_string(state);
726
727                         dbus_message_iter_next(&sub);
728                         c++;
729                 }
730         }
731
732         if (c > 0) {
733                 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
734                 output_unit_file_list(units, c);
735         }
736
737         r = 0;
738
739 finish:
740         if (reply)
741                 dbus_message_unref(reply);
742
743         free(units);
744
745         return r;
746 }
747
748 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
749         static const char * const colors[] = {
750                 "Requires",              "[color=\"black\"]",
751                 "RequiresOverridable",   "[color=\"black\"]",
752                 "Requisite",             "[color=\"darkblue\"]",
753                 "RequisiteOverridable",  "[color=\"darkblue\"]",
754                 "Wants",                 "[color=\"grey66\"]",
755                 "Conflicts",             "[color=\"red\"]",
756                 "ConflictedBy",          "[color=\"red\"]",
757                 "After",                 "[color=\"green\"]"
758         };
759
760         const char *c = NULL;
761         unsigned i;
762
763         assert(name);
764         assert(prop);
765         assert(iter);
766
767         for (i = 0; i < ELEMENTSOF(colors); i += 2)
768                 if (streq(colors[i], prop)) {
769                         c = colors[i+1];
770                         break;
771                 }
772
773         if (!c)
774                 return 0;
775
776         if (arg_dot != DOT_ALL)
777                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
778                         return 0;
779
780         switch (dbus_message_iter_get_arg_type(iter)) {
781
782         case DBUS_TYPE_ARRAY:
783
784                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
785                         DBusMessageIter sub;
786
787                         dbus_message_iter_recurse(iter, &sub);
788
789                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
790                                 const char *s;
791
792                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
793                                 dbus_message_iter_get_basic(&sub, &s);
794                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
795
796                                 dbus_message_iter_next(&sub);
797                         }
798
799                         return 0;
800                 }
801         }
802
803         return 0;
804 }
805
806 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
807         DBusMessage *reply = NULL;
808         const char *interface = "org.freedesktop.systemd1.Unit";
809         int r;
810         DBusMessageIter iter, sub, sub2, sub3;
811
812         assert(path);
813
814         r = bus_method_call_with_reply (
815                         bus,
816                         "org.freedesktop.systemd1",
817                         path,
818                         "org.freedesktop.DBus.Properties",
819                         "GetAll",
820                         &reply,
821                         NULL,
822                         DBUS_TYPE_STRING, &interface,
823                         DBUS_TYPE_INVALID);
824         if (r)
825                 goto finish;
826
827         if (!dbus_message_iter_init(reply, &iter) ||
828             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
829             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
830                 log_error("Failed to parse reply.");
831                 r = -EIO;
832                 goto finish;
833         }
834
835         dbus_message_iter_recurse(&iter, &sub);
836
837         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
838                 const char *prop;
839
840                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
841                         log_error("Failed to parse reply.");
842                         r = -EIO;
843                         goto finish;
844                 }
845
846                 dbus_message_iter_recurse(&sub, &sub2);
847
848                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
849                         log_error("Failed to parse reply.");
850                         r = -EIO;
851                         goto finish;
852                 }
853
854                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
855                         log_error("Failed to parse reply.");
856                         r = -EIO;
857                         goto finish;
858                 }
859
860                 dbus_message_iter_recurse(&sub2, &sub3);
861
862                 if (dot_one_property(name, prop, &sub3)) {
863                         log_error("Failed to parse reply.");
864                         r = -EIO;
865                         goto finish;
866                 }
867
868                 dbus_message_iter_next(&sub);
869         }
870
871 finish:
872         if (reply)
873                 dbus_message_unref(reply);
874
875         return r;
876 }
877
878 static int dot(DBusConnection *bus, char **args) {
879         DBusMessage *reply = NULL;
880         int r;
881         DBusMessageIter iter, sub, sub2;
882
883         r = bus_method_call_with_reply (
884                         bus,
885                         "org.freedesktop.systemd1",
886                         "/org/freedesktop/systemd1",
887                         "org.freedesktop.systemd1.Manager",
888                         "ListUnits",
889                         &reply,
890                         NULL,
891                         DBUS_TYPE_INVALID);
892         if (r)
893                 goto finish;
894
895         if (!dbus_message_iter_init(reply, &iter) ||
896             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
897             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
898                 log_error("Failed to parse reply.");
899                 r = -EIO;
900                 goto finish;
901         }
902
903         printf("digraph systemd {\n");
904
905         dbus_message_iter_recurse(&iter, &sub);
906         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
907                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
908
909                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
910                         log_error("Failed to parse reply.");
911                         r = -EIO;
912                         goto finish;
913                 }
914
915                 dbus_message_iter_recurse(&sub, &sub2);
916
917                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
918                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
919                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
920                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
921                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
922                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
923                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
924                         log_error("Failed to parse reply.");
925                         r = -EIO;
926                         goto finish;
927                 }
928
929                 if ((r = dot_one(bus, id, unit_path)) < 0)
930                         goto finish;
931
932                 /* printf("\t\"%s\";\n", id); */
933                 dbus_message_iter_next(&sub);
934         }
935
936         printf("}\n");
937
938         log_info("   Color legend: black     = Requires\n"
939                  "                 dark blue = Requisite\n"
940                  "                 dark grey = Wants\n"
941                  "                 red       = Conflicts\n"
942                  "                 green     = After\n");
943
944         if (on_tty())
945                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
946                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
947
948         r = 0;
949
950 finish:
951         if (reply)
952                 dbus_message_unref(reply);
953
954         return r;
955 }
956
957 static int list_jobs(DBusConnection *bus, char **args) {
958         DBusMessage *reply = NULL;
959         int r;
960         DBusMessageIter iter, sub, sub2;
961         unsigned k = 0;
962
963         pager_open_if_enabled();
964
965         r = bus_method_call_with_reply (
966                         bus,
967                         "org.freedesktop.systemd1",
968                         "/org/freedesktop/systemd1",
969                         "org.freedesktop.systemd1.Manager",
970                         "ListJobs",
971                         &reply,
972                         NULL,
973                         DBUS_TYPE_INVALID);
974         if (r)
975                 goto finish;
976
977         if (!dbus_message_iter_init(reply, &iter) ||
978             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
979             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
980                 log_error("Failed to parse reply.");
981                 r = -EIO;
982                 goto finish;
983         }
984
985         dbus_message_iter_recurse(&iter, &sub);
986
987         if (on_tty())
988                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
989
990         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
991                 const char *name, *type, *state, *job_path, *unit_path;
992                 uint32_t id;
993                 char *e;
994
995                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
996                         log_error("Failed to parse reply.");
997                         r = -EIO;
998                         goto finish;
999                 }
1000
1001                 dbus_message_iter_recurse(&sub, &sub2);
1002
1003                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1004                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1005                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1006                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1007                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1008                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1009                         log_error("Failed to parse reply.");
1010                         r = -EIO;
1011                         goto finish;
1012                 }
1013
1014                 e = arg_full ? NULL : ellipsize(name, 25, 33);
1015                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1016                 free(e);
1017
1018                 k++;
1019
1020                 dbus_message_iter_next(&sub);
1021         }
1022
1023         if (on_tty())
1024                 printf("\n%u jobs listed.\n", k);
1025
1026         r = 0;
1027
1028 finish:
1029         if (reply)
1030                 dbus_message_unref(reply);
1031
1032         return r;
1033 }
1034
1035 static int load_unit(DBusConnection *bus, char **args) {
1036         char **name;
1037
1038         assert(args);
1039
1040         STRV_FOREACH(name, args+1) {
1041                 _cleanup_free_ char *n = NULL;
1042                 int r;
1043
1044                 n = unit_name_mangle(*name);
1045                 r = bus_method_call_with_reply (
1046                                 bus,
1047                                 "org.freedesktop.systemd1",
1048                                 "/org/freedesktop/systemd1",
1049                                 "org.freedesktop.systemd1.Manager",
1050                                 "LoadUnit",
1051                                 NULL,
1052                                 NULL,
1053                                 DBUS_TYPE_STRING, n ? &n : name,
1054                                 DBUS_TYPE_INVALID);
1055                 if (r < 0)
1056                         return r;
1057         }
1058
1059         return 0;
1060 }
1061
1062 static int cancel_job(DBusConnection *bus, char **args) {
1063         char **name;
1064
1065         assert(args);
1066
1067         if (strv_length(args) <= 1)
1068                 return daemon_reload(bus, args);
1069
1070         STRV_FOREACH(name, args+1) {
1071                 uint32_t id;
1072                 int r;
1073
1074                 r = safe_atou32(*name, &id);
1075                 if (r < 0) {
1076                         log_error("Failed to parse job id: %s", strerror(-r));
1077                         return r;
1078                 }
1079
1080                 r = bus_method_call_with_reply(
1081                                 bus,
1082                                 "org.freedesktop.systemd1",
1083                                 "/org/freedesktop/systemd1",
1084                                 "org.freedesktop.systemd1.Manager",
1085                                 "CancelJob",
1086                                 NULL,
1087                                 NULL,
1088                                 DBUS_TYPE_UINT32, &id,
1089                                 DBUS_TYPE_INVALID);
1090                 if (r < 0)
1091                         return r;
1092         }
1093
1094         return 0;
1095 }
1096
1097 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1098         DBusMessage *reply = NULL;
1099         dbus_bool_t b = FALSE;
1100         DBusMessageIter iter, sub;
1101         const char
1102                 *interface = "org.freedesktop.systemd1.Unit",
1103                 *property = "NeedDaemonReload",
1104                 *path;
1105         char *n;
1106         int r;
1107
1108         /* We ignore all errors here, since this is used to show a warning only */
1109
1110         n = unit_name_mangle(unit);
1111         r = bus_method_call_with_reply (
1112                         bus,
1113                         "org.freedesktop.systemd1",
1114                         "/org/freedesktop/systemd1",
1115                         "org.freedesktop.systemd1.Manager",
1116                         "GetUnit",
1117                         &reply,
1118                         NULL,
1119                         DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
1120                         DBUS_TYPE_INVALID);
1121         free(n);
1122         if (r)
1123                 goto finish;
1124
1125         if (!dbus_message_get_args(reply, NULL,
1126                                    DBUS_TYPE_OBJECT_PATH, &path,
1127                                    DBUS_TYPE_INVALID))
1128                 goto finish;
1129
1130         dbus_message_unref(reply);
1131         r = bus_method_call_with_reply (
1132                         bus,
1133                         "org.freedesktop.systemd1",
1134                         path,
1135                         "org.freedesktop.DBus.Properties",
1136                         "Get",
1137                         &reply,
1138                         NULL,
1139                         DBUS_TYPE_STRING, &interface,
1140                         DBUS_TYPE_STRING, &property,
1141                         DBUS_TYPE_INVALID);
1142         if (r)
1143                 goto finish;
1144
1145         if (!dbus_message_iter_init(reply, &iter) ||
1146             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1147                 goto finish;
1148
1149         dbus_message_iter_recurse(&iter, &sub);
1150
1151         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1152                 goto finish;
1153
1154         dbus_message_iter_get_basic(&sub, &b);
1155
1156 finish:
1157         if (reply)
1158                 dbus_message_unref(reply);
1159
1160         return b;
1161 }
1162
1163 typedef struct WaitData {
1164         Set *set;
1165
1166         char *name;
1167         char *result;
1168 } WaitData;
1169
1170 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1171         DBusError error;
1172         WaitData *d = data;
1173
1174         assert(connection);
1175         assert(message);
1176         assert(d);
1177
1178         dbus_error_init(&error);
1179
1180         log_debug("Got D-Bus request: %s.%s() on %s",
1181                   dbus_message_get_interface(message),
1182                   dbus_message_get_member(message),
1183                   dbus_message_get_path(message));
1184
1185         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1186                 log_error("Warning! D-Bus connection terminated.");
1187                 dbus_connection_close(connection);
1188
1189         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1190                 uint32_t id;
1191                 const char *path, *result, *unit;
1192                 dbus_bool_t success = true;
1193
1194                 if (dbus_message_get_args(message, &error,
1195                                           DBUS_TYPE_UINT32, &id,
1196                                           DBUS_TYPE_OBJECT_PATH, &path,
1197                                           DBUS_TYPE_STRING, &unit,
1198                                           DBUS_TYPE_STRING, &result,
1199                                           DBUS_TYPE_INVALID)) {
1200                         char *p;
1201
1202                         p = set_remove(d->set, (char*) path);
1203                         free(p);
1204
1205                         if (!isempty(result))
1206                                 d->result = strdup(result);
1207
1208                         if (!isempty(unit))
1209                                 d->name = strdup(unit);
1210
1211                         goto finish;
1212                 }
1213 #ifndef LEGACY
1214                 dbus_error_free(&error);
1215                 if (dbus_message_get_args(message, &error,
1216                                           DBUS_TYPE_UINT32, &id,
1217                                           DBUS_TYPE_OBJECT_PATH, &path,
1218                                           DBUS_TYPE_STRING, &result,
1219                                           DBUS_TYPE_INVALID)) {
1220                         char *p;
1221
1222                         /* Compatibility with older systemd versions <
1223                          * 183 during upgrades. This should be dropped
1224                          * one day. */
1225                         p = set_remove(d->set, (char*) path);
1226                         free(p);
1227
1228                         if (*result)
1229                                 d->result = strdup(result);
1230
1231                         goto finish;
1232                 }
1233
1234                 dbus_error_free(&error);
1235                 if (dbus_message_get_args(message, &error,
1236                                           DBUS_TYPE_UINT32, &id,
1237                                           DBUS_TYPE_OBJECT_PATH, &path,
1238                                           DBUS_TYPE_BOOLEAN, &success,
1239                                           DBUS_TYPE_INVALID)) {
1240                         char *p;
1241
1242                         /* Compatibility with older systemd versions <
1243                          * 19 during upgrades. This should be dropped
1244                          * one day */
1245
1246                         p = set_remove(d->set, (char*) path);
1247                         free(p);
1248
1249                         if (!success)
1250                                 d->result = strdup("failed");
1251
1252                         goto finish;
1253                 }
1254 #endif
1255
1256                 log_error("Failed to parse message: %s", bus_error_message(&error));
1257         }
1258
1259 finish:
1260         dbus_error_free(&error);
1261         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1262 }
1263
1264 static int enable_wait_for_jobs(DBusConnection *bus) {
1265         DBusError error;
1266
1267         assert(bus);
1268
1269         if (private_bus)
1270                 return 0;
1271
1272         dbus_error_init(&error);
1273         dbus_bus_add_match(bus,
1274                            "type='signal',"
1275                            "sender='org.freedesktop.systemd1',"
1276                            "interface='org.freedesktop.systemd1.Manager',"
1277                            "member='JobRemoved',"
1278                            "path='/org/freedesktop/systemd1'",
1279                            &error);
1280
1281         if (dbus_error_is_set(&error)) {
1282                 log_error("Failed to add match: %s", bus_error_message(&error));
1283                 dbus_error_free(&error);
1284                 return -EIO;
1285         }
1286
1287         /* This is slightly dirty, since we don't undo the match registrations. */
1288         return 0;
1289 }
1290
1291 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1292         int r = 0;
1293         WaitData d;
1294
1295         assert(bus);
1296         assert(s);
1297
1298         zero(d);
1299         d.set = s;
1300
1301         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1302                 return log_oom();
1303
1304         while (!set_isempty(s)) {
1305
1306                 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1307                         log_error("Disconnected from bus.");
1308                         return -ECONNREFUSED;
1309                 }
1310
1311                 if (!d.result)
1312                         goto free_name;
1313
1314                 if (!arg_quiet) {
1315                         if (streq(d.result, "timeout"))
1316                                 log_error("Job for %s timed out.", strna(d.name));
1317                         else if (streq(d.result, "canceled"))
1318                                 log_error("Job for %s canceled.", strna(d.name));
1319                         else if (streq(d.result, "dependency"))
1320                                 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1321                         else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1322                                 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1323                 }
1324
1325                 if (streq_ptr(d.result, "timeout"))
1326                         r = -ETIME;
1327                 else if (streq_ptr(d.result, "canceled"))
1328                         r = -ECANCELED;
1329                 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1330                         r = -EIO;
1331
1332                 free(d.result);
1333                 d.result = NULL;
1334
1335         free_name:
1336                 free(d.name);
1337                 d.name = NULL;
1338         }
1339
1340         dbus_connection_remove_filter(bus, wait_filter, &d);
1341         return r;
1342 }
1343
1344 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1345         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1346         DBusMessageIter iter, sub;
1347         const char
1348                 *interface = "org.freedesktop.systemd1.Unit",
1349                 *property = "ActiveState";
1350         const char *state, *path;
1351         _cleanup_free_ char *n = NULL;
1352         DBusError error;
1353         int r;
1354
1355         assert(name);
1356
1357         dbus_error_init(&error);
1358
1359         n = unit_name_mangle(name);
1360         if (!n)
1361                 return log_oom();
1362
1363         r = bus_method_call_with_reply (
1364                         bus,
1365                         "org.freedesktop.systemd1",
1366                         "/org/freedesktop/systemd1",
1367                         "org.freedesktop.systemd1.Manager",
1368                         "GetUnit",
1369                         &reply,
1370                         &error,
1371                         DBUS_TYPE_STRING, &n,
1372                         DBUS_TYPE_INVALID);
1373         if (r < 0) {
1374                 dbus_error_free(&error);
1375
1376                 if (!quiet)
1377                         puts("unknown");
1378                 return 0;
1379         }
1380
1381         if (!dbus_message_get_args(reply, NULL,
1382                                    DBUS_TYPE_OBJECT_PATH, &path,
1383                                    DBUS_TYPE_INVALID)) {
1384                 log_error("Failed to parse reply.");
1385                 return -EIO;
1386         }
1387
1388         dbus_message_unref(reply);
1389         reply = NULL;
1390
1391         r = bus_method_call_with_reply(
1392                         bus,
1393                         "org.freedesktop.systemd1",
1394                         path,
1395                         "org.freedesktop.DBus.Properties",
1396                         "Get",
1397                         &reply,
1398                         NULL,
1399                         DBUS_TYPE_STRING, &interface,
1400                         DBUS_TYPE_STRING, &property,
1401                         DBUS_TYPE_INVALID);
1402         if (r < 0) {
1403                 if (!quiet)
1404                         puts("unknown");
1405                 return 0;
1406         }
1407
1408         if (!dbus_message_iter_init(reply, &iter) ||
1409             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1410                 log_error("Failed to parse reply.");
1411                 return r;
1412         }
1413
1414         dbus_message_iter_recurse(&iter, &sub);
1415
1416         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1417                 log_error("Failed to parse reply.");
1418                 return r;
1419         }
1420
1421         dbus_message_iter_get_basic(&sub, &state);
1422
1423         if (!quiet)
1424                 puts(state);
1425
1426         return strv_find(check_states, state) ? 1 : 0;
1427 }
1428
1429 static void check_triggering_units(
1430                 DBusConnection *bus,
1431                 const char *unit_name) {
1432
1433         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1434         DBusMessageIter iter, sub;
1435         const char *interface = "org.freedesktop.systemd1.Unit",
1436                    *triggered_by_property = "TriggeredBy";
1437
1438         char _cleanup_free_ *unit_path = NULL, *n = NULL;
1439         bool print_warning_label = true;
1440         int r;
1441
1442         n = unit_name_mangle(unit_name);
1443         if (!n) {
1444                 log_oom();
1445                 return;
1446         }
1447
1448         unit_path = unit_dbus_path_from_name(n);
1449         if (!unit_path) {
1450                 log_oom();
1451                 return;
1452         }
1453
1454         r = bus_method_call_with_reply(
1455                         bus,
1456                         "org.freedesktop.systemd1",
1457                         unit_path,
1458                         "org.freedesktop.DBus.Properties",
1459                         "Get",
1460                         &reply,
1461                         NULL,
1462                         DBUS_TYPE_STRING, &interface,
1463                         DBUS_TYPE_STRING, &triggered_by_property,
1464                         DBUS_TYPE_INVALID);
1465         if (r < 0)
1466                 return;
1467
1468         if (!dbus_message_iter_init(reply, &iter) ||
1469             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1470                 log_error("Failed to parse reply.");
1471                 return;
1472         }
1473
1474         dbus_message_iter_recurse(&iter, &sub);
1475         dbus_message_iter_recurse(&sub, &iter);
1476         sub = iter;
1477
1478         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1479                 const char * const check_states[] = {
1480                         "active",
1481                         "reloading",
1482                         NULL
1483                 };
1484                 const char *service_trigger;
1485
1486                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1487                         log_error("Failed to parse reply.");
1488                         return;
1489                 }
1490
1491                 dbus_message_iter_get_basic(&sub, &service_trigger);
1492
1493                 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1494                 if (r < 0)
1495                         return;
1496                 if (r > 0) {
1497                         if (print_warning_label) {
1498                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1499                                 print_warning_label = false;
1500                         }
1501
1502                         log_warning("  %s", service_trigger);
1503                 }
1504
1505                 dbus_message_iter_next(&sub);
1506         }
1507 }
1508
1509 static int start_unit_one(
1510                 DBusConnection *bus,
1511                 const char *method,
1512                 const char *name,
1513                 const char *mode,
1514                 DBusError *error,
1515                 Set *s) {
1516
1517         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1518         const char *path;
1519         int r;
1520         _cleanup_free_ char *n, *p = NULL;
1521
1522         assert(method);
1523         assert(name);
1524         assert(mode);
1525         assert(error);
1526
1527         n = unit_name_mangle(name);
1528         if (!n)
1529                 return log_oom();
1530
1531         r = bus_method_call_with_reply(
1532                         bus,
1533                         "org.freedesktop.systemd1",
1534                         "/org/freedesktop/systemd1",
1535                         "org.freedesktop.systemd1.Manager",
1536                         method,
1537                         &reply,
1538                         error,
1539                         DBUS_TYPE_STRING, &n,
1540                         DBUS_TYPE_STRING, &mode,
1541                         DBUS_TYPE_INVALID);
1542         if (r) {
1543                 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1544                         /* There's always a fallback possible for
1545                          * legacy actions. */
1546                         r = -EADDRNOTAVAIL;
1547                 else
1548                         log_error("Failed to issue method call: %s", bus_error_message(error));
1549
1550                 return r;
1551         }
1552
1553         if (!dbus_message_get_args(reply, error,
1554                                    DBUS_TYPE_OBJECT_PATH, &path,
1555                                    DBUS_TYPE_INVALID)) {
1556                 log_error("Failed to parse reply: %s", bus_error_message(error));
1557                 return -EIO;
1558         }
1559
1560         if (need_daemon_reload(bus, n))
1561                 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1562                             n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1563
1564         if (s) {
1565                 p = strdup(path);
1566                 if (!p)
1567                         return log_oom();
1568
1569                 r = set_put(s, p);
1570                 if (r < 0) {
1571                         log_error("Failed to add path to set.");
1572                         return r;
1573                 }
1574
1575                 p = NULL;
1576         }
1577
1578         return 0;
1579 }
1580
1581 static enum action verb_to_action(const char *verb) {
1582         if (streq(verb, "halt"))
1583                 return ACTION_HALT;
1584         else if (streq(verb, "poweroff"))
1585                 return ACTION_POWEROFF;
1586         else if (streq(verb, "reboot"))
1587                 return ACTION_REBOOT;
1588         else if (streq(verb, "kexec"))
1589                 return ACTION_KEXEC;
1590         else if (streq(verb, "rescue"))
1591                 return ACTION_RESCUE;
1592         else if (streq(verb, "emergency"))
1593                 return ACTION_EMERGENCY;
1594         else if (streq(verb, "default"))
1595                 return ACTION_DEFAULT;
1596         else if (streq(verb, "exit"))
1597                 return ACTION_EXIT;
1598         else if (streq(verb, "suspend"))
1599                 return ACTION_SUSPEND;
1600         else if (streq(verb, "hibernate"))
1601                 return ACTION_HIBERNATE;
1602         else if (streq(verb, "hybrid-sleep"))
1603                 return ACTION_HYBRID_SLEEP;
1604         else
1605                 return ACTION_INVALID;
1606 }
1607
1608 static int start_unit(DBusConnection *bus, char **args) {
1609
1610         static const char * const table[_ACTION_MAX] = {
1611                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1612                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1613                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1614                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1615                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1616                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1617                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1618                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1619                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1620                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1621                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1622                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1623                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1624                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
1625                 [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
1626         };
1627
1628         int r, ret = 0;
1629         const char *method, *mode, *one_name;
1630         Set *s = NULL;
1631         DBusError error;
1632         char **name;
1633
1634         dbus_error_init(&error);
1635
1636         assert(bus);
1637
1638         ask_password_agent_open_if_enabled();
1639
1640         if (arg_action == ACTION_SYSTEMCTL) {
1641                 method =
1642                         streq(args[0], "stop") ||
1643                         streq(args[0], "condstop")              ? "StopUnit" :
1644                         streq(args[0], "reload")                ? "ReloadUnit" :
1645                         streq(args[0], "restart")               ? "RestartUnit" :
1646
1647                         streq(args[0], "try-restart")           ||
1648                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1649
1650                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1651
1652                         streq(args[0], "reload-or-try-restart") ||
1653                         streq(args[0], "condreload") ||
1654
1655                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1656                                                                   "StartUnit";
1657
1658                 mode =
1659                         (streq(args[0], "isolate") ||
1660                          streq(args[0], "rescue")  ||
1661                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1662
1663                 one_name = table[verb_to_action(args[0])];
1664
1665         } else {
1666                 assert(arg_action < ELEMENTSOF(table));
1667                 assert(table[arg_action]);
1668
1669                 method = "StartUnit";
1670
1671                 mode = (arg_action == ACTION_EMERGENCY ||
1672                         arg_action == ACTION_RESCUE ||
1673                         arg_action == ACTION_RUNLEVEL2 ||
1674                         arg_action == ACTION_RUNLEVEL3 ||
1675                         arg_action == ACTION_RUNLEVEL4 ||
1676                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1677
1678                 one_name = table[arg_action];
1679         }
1680
1681         if (!arg_no_block) {
1682                 ret = enable_wait_for_jobs(bus);
1683                 if (ret < 0) {
1684                         log_error("Could not watch jobs: %s", strerror(-ret));
1685                         goto finish;
1686                 }
1687
1688                 s = set_new(string_hash_func, string_compare_func);
1689                 if (!s) {
1690                         ret = log_oom();
1691                         goto finish;
1692                 }
1693         }
1694
1695         if (one_name) {
1696                 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1697                 if (ret < 0)
1698                         ret = translate_bus_error_to_exit_status(ret, &error);
1699         } else {
1700                 STRV_FOREACH(name, args+1) {
1701                         r = start_unit_one(bus, method, *name, mode, &error, s);
1702                         if (r < 0) {
1703                                 ret = translate_bus_error_to_exit_status(r, &error);
1704                                 dbus_error_free(&error);
1705                         }
1706                 }
1707         }
1708
1709         if (!arg_no_block) {
1710                 r = wait_for_jobs(bus, s);
1711                 if (r < 0) {
1712                         ret = r;
1713                         goto finish;
1714                 }
1715
1716                 /* When stopping units, warn if they can still be triggered by
1717                  * another active unit (socket, path, timer) */
1718                 if (!arg_quiet && streq(method, "StopUnit")) {
1719                         if (one_name)
1720                                 check_triggering_units(bus, one_name);
1721                         else
1722                                 STRV_FOREACH(name, args+1)
1723                                         check_triggering_units(bus, *name);
1724                 }
1725         }
1726
1727 finish:
1728         set_free_free(s);
1729         dbus_error_free(&error);
1730
1731         return ret;
1732 }
1733
1734 /* Ask systemd-logind, which might grant access to unprivileged users
1735  * through PolicyKit */
1736 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1737 #ifdef HAVE_LOGIND
1738         const char *method;
1739         dbus_bool_t interactive = true;
1740
1741         if (!bus)
1742                 return -EIO;
1743
1744         polkit_agent_open_if_enabled();
1745
1746         switch (a) {
1747
1748         case ACTION_REBOOT:
1749                 method = "Reboot";
1750                 break;
1751
1752         case ACTION_POWEROFF:
1753                 method = "PowerOff";
1754                 break;
1755
1756         case ACTION_SUSPEND:
1757                 method = "Suspend";
1758                 break;
1759
1760         case ACTION_HIBERNATE:
1761                 method = "Hibernate";
1762                 break;
1763
1764         case ACTION_HYBRID_SLEEP:
1765                 method = "HybridSleep";
1766                 break;
1767
1768         default:
1769                 return -EINVAL;
1770         }
1771
1772         return bus_method_call_with_reply (
1773                         bus,
1774                         "org.freedesktop.login1",
1775                         "/org/freedesktop/login1",
1776                         "org.freedesktop.login1.Manager",
1777                         method,
1778                         NULL,
1779                         NULL,
1780                         DBUS_TYPE_BOOLEAN, &interactive,
1781                         DBUS_TYPE_INVALID);
1782 #else
1783         return -ENOSYS;
1784 #endif
1785 }
1786
1787 static int check_inhibitors(DBusConnection *bus, enum action a) {
1788 #ifdef HAVE_LOGIND
1789         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1790         DBusMessageIter iter, sub, sub2;
1791         int r;
1792         unsigned c = 0;
1793
1794         if (!bus)
1795                 return 0;
1796
1797         if (arg_ignore_inhibitors || arg_force > 0)
1798                 return 0;
1799
1800         if (arg_when > 0)
1801                 return 0;
1802
1803         if (geteuid() == 0)
1804                 return 0;
1805
1806         if (!on_tty())
1807                 return 0;
1808
1809         r = bus_method_call_with_reply(
1810                         bus,
1811                         "org.freedesktop.login1",
1812                         "/org/freedesktop/login1",
1813                         "org.freedesktop.login1.Manager",
1814                         "ListInhibitors",
1815                         &reply,
1816                         NULL,
1817                         DBUS_TYPE_INVALID);
1818         if (r < 0)
1819                 /* If logind is not around, then there are no inhibitors... */
1820                 return 0;
1821
1822         if (!dbus_message_iter_init(reply, &iter) ||
1823             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1824             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1825                 log_error("Failed to parse reply.");
1826                 return -EIO;
1827         }
1828
1829         dbus_message_iter_recurse(&iter, &sub);
1830         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1831                 const char *what, *who, *why, *mode;
1832                 uint32_t uid, pid;
1833                 _cleanup_strv_free_ char **sv = NULL;
1834                 _cleanup_free_ char *comm = NULL;
1835
1836                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1837                         log_error("Failed to parse reply.");
1838                         return -EIO;
1839                 }
1840
1841                 dbus_message_iter_recurse(&sub, &sub2);
1842
1843                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1844                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1845                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1846                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1847                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1848                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1849                         log_error("Failed to parse reply.");
1850                         return -EIO;
1851                 }
1852
1853                 if (!streq(mode, "block"))
1854                         goto next;
1855
1856                 sv = strv_split(what, ":");
1857                 if (!sv)
1858                         return log_oom();
1859
1860                 if (!strv_contains(sv,
1861                                   a == ACTION_HALT ||
1862                                   a == ACTION_POWEROFF ||
1863                                   a == ACTION_REBOOT ||
1864                                   a == ACTION_KEXEC ? "shutdown" : "sleep"))
1865                         goto next;
1866
1867                 get_process_comm(pid, &comm);
1868                 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", UID %lu), reason is \"%s\".", who, (unsigned long) pid, strna(comm), (unsigned long) uid, why);
1869                 c++;
1870
1871         next:
1872                 dbus_message_iter_next(&sub);
1873         }
1874
1875         dbus_message_iter_recurse(&iter, &sub);
1876
1877         if (c <= 0)
1878                 return 0;
1879
1880         log_error("Please try again after closing inhibitors or ignore them with 'systemctl %s -i'.",
1881                   a == ACTION_HALT ? "halt" :
1882                   a == ACTION_POWEROFF ? "poweroff" :
1883                   a == ACTION_REBOOT ? "reboot" :
1884                   a == ACTION_KEXEC ? "kexec" :
1885                   a == ACTION_SUSPEND ? "suspend" :
1886                   a == ACTION_HIBERNATE ? "hibernate" : "hybrid-sleep");
1887
1888         return -EPERM;
1889 #else
1890         return 0;
1891 #endif
1892 }
1893
1894 static int start_special(DBusConnection *bus, char **args) {
1895         enum action a;
1896         int r;
1897
1898         assert(args);
1899
1900         a = verb_to_action(args[0]);
1901
1902         r = check_inhibitors(bus, a);
1903         if (r < 0)
1904                 return r;
1905
1906         if (arg_force >= 2 && geteuid() != 0) {
1907                 log_error("Must be root.");
1908                 return -EPERM;
1909         }
1910
1911         if (arg_force >= 2 &&
1912             (a == ACTION_HALT ||
1913              a == ACTION_POWEROFF ||
1914              a == ACTION_REBOOT))
1915                 halt_now(a);
1916
1917         if (arg_force >= 1 &&
1918             (a == ACTION_HALT ||
1919              a == ACTION_POWEROFF ||
1920              a == ACTION_REBOOT ||
1921              a == ACTION_KEXEC ||
1922              a == ACTION_EXIT))
1923                 return daemon_reload(bus, args);
1924
1925         /* first try logind, to allow authentication with polkit */
1926         if (geteuid() != 0 &&
1927             (a == ACTION_POWEROFF ||
1928              a == ACTION_REBOOT ||
1929              a == ACTION_SUSPEND ||
1930              a == ACTION_HIBERNATE ||
1931              a == ACTION_HYBRID_SLEEP)) {
1932                 r = reboot_with_logind(bus, a);
1933                 if (r >= 0)
1934                         return r;
1935         }
1936
1937         r = start_unit(bus, args);
1938         if (r >= 0)
1939                 warn_wall(a);
1940
1941         return r;
1942 }
1943
1944 static int check_unit_active(DBusConnection *bus, char **args) {
1945         const char * const check_states[] = {
1946                 "active",
1947                 "reloading",
1948                 NULL
1949         };
1950
1951         char **name;
1952         int r = 3; /* According to LSB: "program is not running" */
1953
1954         assert(bus);
1955         assert(args);
1956
1957         STRV_FOREACH(name, args+1) {
1958                 int state;
1959
1960                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1961                 if (state < 0)
1962                         return state;
1963                 if (state > 0)
1964                         r = 0;
1965         }
1966
1967         return r;
1968 }
1969
1970 static int check_unit_failed(DBusConnection *bus, char **args) {
1971         const char * const check_states[] = {
1972                 "failed",
1973                 NULL
1974         };
1975
1976         char **name;
1977         int r = 1;
1978
1979         assert(bus);
1980         assert(args);
1981
1982         STRV_FOREACH(name, args+1) {
1983                 int state;
1984
1985                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1986                 if (state < 0)
1987                         return state;
1988                 if (state > 0)
1989                         r = 0;
1990         }
1991
1992         return r;
1993 }
1994
1995 static int kill_unit(DBusConnection *bus, char **args) {
1996         char **name;
1997         int r = 0;
1998
1999         assert(bus);
2000         assert(args);
2001
2002         if (!arg_kill_who)
2003                 arg_kill_who = "all";
2004
2005         STRV_FOREACH(name, args+1) {
2006                 _cleanup_free_ char *n = NULL;
2007
2008                 n = unit_name_mangle(*name);
2009
2010                 r = bus_method_call_with_reply(
2011                                 bus,
2012                                 "org.freedesktop.systemd1",
2013                                 "/org/freedesktop/systemd1",
2014                                 "org.freedesktop.systemd1.Manager",
2015                                 "KillUnit",
2016                                 NULL,
2017                                 NULL,
2018                                 DBUS_TYPE_STRING, n ? &n : name,
2019                                 DBUS_TYPE_STRING, &arg_kill_who,
2020                                 DBUS_TYPE_INT32, &arg_signal,
2021                                 DBUS_TYPE_INVALID);
2022                 if (r < 0)
2023                         return r;
2024         }
2025         return 0;
2026 }
2027
2028 static int set_cgroup(DBusConnection *bus, char **args) {
2029         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2030         DBusError error;
2031         const char *method;
2032         DBusMessageIter iter;
2033         int r;
2034         _cleanup_free_ char *n = NULL;
2035
2036         assert(bus);
2037         assert(args);
2038
2039         dbus_error_init(&error);
2040
2041         method =
2042                 streq(args[0], "set-cgroup")  ? "SetUnitControlGroups" :
2043                 streq(args[0], "unset-group") ? "UnsetUnitControlGroups"
2044                                               : "UnsetUnitControlGroupAttributes";
2045
2046         n = unit_name_mangle(args[1]);
2047         if (!n)
2048                 return log_oom();
2049
2050         m = dbus_message_new_method_call(
2051                         "org.freedesktop.systemd1",
2052                         "/org/freedesktop/systemd1",
2053                         "org.freedesktop.systemd1.Manager",
2054                         method);
2055         if (!m)
2056                 return log_oom();
2057
2058         dbus_message_iter_init_append(m, &iter);
2059         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2060                 return log_oom();
2061
2062         r = bus_append_strv_iter(&iter, args + 2);
2063         if (r < 0)
2064                 return log_oom();
2065
2066         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2067         if (!reply) {
2068                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2069                 dbus_error_free(&error);
2070                 return -EIO;
2071         }
2072
2073         return 0;
2074 }
2075
2076 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2077         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2078         DBusError error;
2079         DBusMessageIter iter, sub, sub2;
2080         int r;
2081         char **x, **y;
2082         _cleanup_free_ char *n = NULL;
2083
2084         assert(bus);
2085         assert(args);
2086
2087         dbus_error_init(&error);
2088
2089         if (strv_length(args) % 2 != 0) {
2090                 log_error("Expecting an uneven number of arguments!");
2091                 return -EINVAL;
2092         }
2093
2094         n = unit_name_mangle(args[1]);
2095         if (!n)
2096                 return log_oom();
2097
2098         m = dbus_message_new_method_call(
2099                         "org.freedesktop.systemd1",
2100                         "/org/freedesktop/systemd1",
2101                         "org.freedesktop.systemd1.Manager",
2102                         "SetUnitControlGroupAttributes");
2103         if (!m)
2104                 return log_oom();
2105
2106         dbus_message_iter_init_append(m, &iter);
2107         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2108             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub))
2109                 return log_oom();
2110
2111         STRV_FOREACH_PAIR(x, y, args + 2) {
2112                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2113                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) ||
2114                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) ||
2115                     !dbus_message_iter_close_container(&sub, &sub2))
2116                         return log_oom();
2117         }
2118
2119         if (!dbus_message_iter_close_container(&iter, &sub))
2120                 return -ENOMEM;
2121
2122         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2123         if (!reply) {
2124                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2125                 dbus_error_free(&error);
2126                 return -EIO;
2127         }
2128
2129         return 0;
2130 }
2131
2132 typedef struct ExecStatusInfo {
2133         char *name;
2134
2135         char *path;
2136         char **argv;
2137
2138         bool ignore;
2139
2140         usec_t start_timestamp;
2141         usec_t exit_timestamp;
2142         pid_t pid;
2143         int code;
2144         int status;
2145
2146         LIST_FIELDS(struct ExecStatusInfo, exec);
2147 } ExecStatusInfo;
2148
2149 static void exec_status_info_free(ExecStatusInfo *i) {
2150         assert(i);
2151
2152         free(i->name);
2153         free(i->path);
2154         strv_free(i->argv);
2155         free(i);
2156 }
2157
2158 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2159         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2160         DBusMessageIter sub2, sub3;
2161         const char*path;
2162         unsigned n;
2163         uint32_t pid;
2164         int32_t code, status;
2165         dbus_bool_t ignore;
2166
2167         assert(i);
2168         assert(i);
2169
2170         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2171                 return -EIO;
2172
2173         dbus_message_iter_recurse(sub, &sub2);
2174
2175         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2176                 return -EIO;
2177
2178         if (!(i->path = strdup(path)))
2179                 return -ENOMEM;
2180
2181         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2182             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2183                 return -EIO;
2184
2185         n = 0;
2186         dbus_message_iter_recurse(&sub2, &sub3);
2187         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2188                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2189                 dbus_message_iter_next(&sub3);
2190                 n++;
2191         }
2192
2193
2194         if (!(i->argv = new0(char*, n+1)))
2195                 return -ENOMEM;
2196
2197         n = 0;
2198         dbus_message_iter_recurse(&sub2, &sub3);
2199         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2200                 const char *s;
2201
2202                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2203                 dbus_message_iter_get_basic(&sub3, &s);
2204                 dbus_message_iter_next(&sub3);
2205
2206                 if (!(i->argv[n++] = strdup(s)))
2207                         return -ENOMEM;
2208         }
2209
2210         if (!dbus_message_iter_next(&sub2) ||
2211             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2212             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2213             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2214             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2215             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2216             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2217             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2218             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2219                 return -EIO;
2220
2221         i->ignore = ignore;
2222         i->start_timestamp = (usec_t) start_timestamp;
2223         i->exit_timestamp = (usec_t) exit_timestamp;
2224         i->pid = (pid_t) pid;
2225         i->code = code;
2226         i->status = status;
2227
2228         return 0;
2229 }
2230
2231 typedef struct UnitStatusInfo {
2232         const char *id;
2233         const char *load_state;
2234         const char *active_state;
2235         const char *sub_state;
2236         const char *unit_file_state;
2237
2238         const char *description;
2239         const char *following;
2240
2241         char **documentation;
2242
2243         const char *fragment_path;
2244         const char *source_path;
2245         const char *default_control_group;
2246
2247         const char *load_error;
2248         const char *result;
2249
2250         usec_t inactive_exit_timestamp;
2251         usec_t inactive_exit_timestamp_monotonic;
2252         usec_t active_enter_timestamp;
2253         usec_t active_exit_timestamp;
2254         usec_t inactive_enter_timestamp;
2255
2256         bool need_daemon_reload;
2257
2258         /* Service */
2259         pid_t main_pid;
2260         pid_t control_pid;
2261         const char *status_text;
2262         bool running:1;
2263
2264         usec_t start_timestamp;
2265         usec_t exit_timestamp;
2266
2267         int exit_code, exit_status;
2268
2269         usec_t condition_timestamp;
2270         bool condition_result;
2271
2272         /* Socket */
2273         unsigned n_accepted;
2274         unsigned n_connections;
2275         bool accept;
2276
2277         /* Device */
2278         const char *sysfs_path;
2279
2280         /* Mount, Automount */
2281         const char *where;
2282
2283         /* Swap */
2284         const char *what;
2285
2286         LIST_HEAD(ExecStatusInfo, exec);
2287 } UnitStatusInfo;
2288
2289 static void print_status_info(UnitStatusInfo *i) {
2290         ExecStatusInfo *p;
2291         const char *on, *off, *ss;
2292         usec_t timestamp;
2293         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2294         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2295         const char *path;
2296
2297         assert(i);
2298
2299         /* This shows pretty information about a unit. See
2300          * print_property() for a low-level property printer */
2301
2302         printf("%s", strna(i->id));
2303
2304         if (i->description && !streq_ptr(i->id, i->description))
2305                 printf(" - %s", i->description);
2306
2307         printf("\n");
2308
2309         if (i->following)
2310                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2311
2312         if (streq_ptr(i->load_state, "error")) {
2313                 on = ansi_highlight_red(true);
2314                 off = ansi_highlight_red(false);
2315         } else
2316                 on = off = "";
2317
2318         path = i->source_path ? i->source_path : i->fragment_path;
2319
2320         if (i->load_error)
2321                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2322         else if (path && i->unit_file_state)
2323                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2324         else if (path)
2325                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2326         else
2327                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2328
2329         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2330
2331         if (streq_ptr(i->active_state, "failed")) {
2332                 on = ansi_highlight_red(true);
2333                 off = ansi_highlight_red(false);
2334         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2335                 on = ansi_highlight_green(true);
2336                 off = ansi_highlight_green(false);
2337         } else
2338                 on = off = "";
2339
2340         if (ss)
2341                 printf("\t  Active: %s%s (%s)%s",
2342                        on,
2343                        strna(i->active_state),
2344                        ss,
2345                        off);
2346         else
2347                 printf("\t  Active: %s%s%s",
2348                        on,
2349                        strna(i->active_state),
2350                        off);
2351
2352         if (!isempty(i->result) && !streq(i->result, "success"))
2353                 printf(" (Result: %s)", i->result);
2354
2355         timestamp = (streq_ptr(i->active_state, "active")      ||
2356                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2357                     (streq_ptr(i->active_state, "inactive")    ||
2358                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2359                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2360                                                                   i->active_exit_timestamp;
2361
2362         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2363         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2364
2365         if (s1)
2366                 printf(" since %s; %s\n", s2, s1);
2367         else if (s2)
2368                 printf(" since %s\n", s2);
2369         else
2370                 printf("\n");
2371
2372         if (!i->condition_result && i->condition_timestamp > 0) {
2373                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2374                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2375
2376                 if (s1)
2377                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2378                 else if (s2)
2379                         printf("\t          start condition failed at %s\n", s2);
2380         }
2381
2382         if (i->sysfs_path)
2383                 printf("\t  Device: %s\n", i->sysfs_path);
2384         if (i->where)
2385                 printf("\t   Where: %s\n", i->where);
2386         if (i->what)
2387                 printf("\t    What: %s\n", i->what);
2388
2389         if (!strv_isempty(i->documentation)) {
2390                 char **t;
2391                 bool first = true;
2392
2393                 STRV_FOREACH(t, i->documentation) {
2394                         if (first) {
2395                                 printf("\t    Docs: %s\n", *t);
2396                                 first = false;
2397                         } else
2398                                 printf("\t          %s\n", *t);
2399                 }
2400         }
2401
2402         if (i->accept)
2403                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2404
2405         LIST_FOREACH(exec, p, i->exec) {
2406                 char *t;
2407                 bool good;
2408
2409                 /* Only show exited processes here */
2410                 if (p->code == 0)
2411                         continue;
2412
2413                 t = strv_join(p->argv, " ");
2414                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2415                 free(t);
2416
2417                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2418                 if (!good) {
2419                         on = ansi_highlight_red(true);
2420                         off = ansi_highlight_red(false);
2421                 } else
2422                         on = off = "";
2423
2424                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2425
2426                 if (p->code == CLD_EXITED) {
2427                         const char *c;
2428
2429                         printf("status=%i", p->status);
2430
2431                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2432                         if (c)
2433                                 printf("/%s", c);
2434
2435                 } else
2436                         printf("signal=%s", signal_to_string(p->status));
2437
2438                 printf(")%s\n", off);
2439
2440                 if (i->main_pid == p->pid &&
2441                     i->start_timestamp == p->start_timestamp &&
2442                     i->exit_timestamp == p->start_timestamp)
2443                         /* Let's not show this twice */
2444                         i->main_pid = 0;
2445
2446                 if (p->pid == i->control_pid)
2447                         i->control_pid = 0;
2448         }
2449
2450         if (i->main_pid > 0 || i->control_pid > 0) {
2451                 printf("\t");
2452
2453                 if (i->main_pid > 0) {
2454                         printf("Main PID: %u", (unsigned) i->main_pid);
2455
2456                         if (i->running) {
2457                                 char *t = NULL;
2458                                 get_process_comm(i->main_pid, &t);
2459                                 if (t) {
2460                                         printf(" (%s)", t);
2461                                         free(t);
2462                                 }
2463                         } else if (i->exit_code > 0) {
2464                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2465
2466                                 if (i->exit_code == CLD_EXITED) {
2467                                         const char *c;
2468
2469                                         printf("status=%i", i->exit_status);
2470
2471                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2472                                         if (c)
2473                                                 printf("/%s", c);
2474
2475                                 } else
2476                                         printf("signal=%s", signal_to_string(i->exit_status));
2477                                 printf(")");
2478                         }
2479                 }
2480
2481                 if (i->main_pid > 0 && i->control_pid > 0)
2482                         printf(";");
2483
2484                 if (i->control_pid > 0) {
2485                         char *t = NULL;
2486
2487                         printf(" Control: %u", (unsigned) i->control_pid);
2488
2489                         get_process_comm(i->control_pid, &t);
2490                         if (t) {
2491                                 printf(" (%s)", t);
2492                                 free(t);
2493                         }
2494                 }
2495
2496                 printf("\n");
2497         }
2498
2499         if (i->status_text)
2500                 printf("\t  Status: \"%s\"\n", i->status_text);
2501
2502         if (i->default_control_group &&
2503             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2504                 unsigned c;
2505
2506                 printf("\t  CGroup: %s\n", i->default_control_group);
2507
2508                 if (arg_transport != TRANSPORT_SSH) {
2509                         unsigned k = 0;
2510                         pid_t extra[2];
2511
2512                         c = columns();
2513                         if (c > 18)
2514                                 c -= 18;
2515                         else
2516                                 c = 0;
2517
2518                         if (i->main_pid > 0)
2519                                 extra[k++] = i->main_pid;
2520
2521                         if (i->control_pid > 0)
2522                                 extra[k++] = i->control_pid;
2523
2524                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2525                 }
2526         }
2527
2528         if (i->id && arg_transport != TRANSPORT_SSH) {
2529                 int flags =
2530                         arg_all * OUTPUT_SHOW_ALL |
2531                         (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2532                         on_tty() * OUTPUT_COLOR |
2533                         !arg_quiet * OUTPUT_WARN_CUTOFF;
2534
2535                 printf("\n");
2536                 show_journal_by_unit(stdout,
2537                                      i->id,
2538                                      arg_output,
2539                                      0,
2540                                      i->inactive_exit_timestamp_monotonic,
2541                                      arg_lines,
2542                                      flags);
2543         }
2544
2545         if (i->need_daemon_reload)
2546                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2547                        ansi_highlight_red(true),
2548                        ansi_highlight_red(false),
2549                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2550 }
2551
2552 static void show_unit_help(UnitStatusInfo *i) {
2553         char **p;
2554
2555         assert(i);
2556
2557         if (!i->documentation) {
2558                 log_info("Documentation for %s not known.", i->id);
2559                 return;
2560         }
2561
2562         STRV_FOREACH(p, i->documentation) {
2563
2564                 if (startswith(*p, "man:")) {
2565                         size_t k;
2566                         char *e = NULL;
2567                         char *page = NULL, *section = NULL;
2568                         const char *args[4] = { "man", NULL, NULL, NULL };
2569                         pid_t pid;
2570
2571                         k = strlen(*p);
2572
2573                         if ((*p)[k-1] == ')')
2574                                 e = strrchr(*p, '(');
2575
2576                         if (e) {
2577                                 page = strndup((*p) + 4, e - *p - 4);
2578                                 if (!page) {
2579                                         log_oom();
2580                                         return;
2581                                 }
2582
2583                                 section = strndup(e + 1, *p + k - e - 2);
2584                                 if (!section) {
2585                                         free(page);
2586                                         log_oom();
2587                                         return;
2588                                 }
2589
2590                                 args[1] = section;
2591                                 args[2] = page;
2592                         } else
2593                                 args[1] = *p + 4;
2594
2595                         pid = fork();
2596                         if (pid < 0) {
2597                                 log_error("Failed to fork: %m");
2598                                 free(page);
2599                                 free(section);
2600                                 continue;
2601                         }
2602
2603                         if (pid == 0) {
2604                                 /* Child */
2605                                 execvp(args[0], (char**) args);
2606                                 log_error("Failed to execute man: %m");
2607                                 _exit(EXIT_FAILURE);
2608                         }
2609
2610                         free(page);
2611                         free(section);
2612
2613                         wait_for_terminate(pid, NULL);
2614                 } else
2615                         log_info("Can't show: %s", *p);
2616         }
2617 }
2618
2619 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2620
2621         assert(name);
2622         assert(iter);
2623         assert(i);
2624
2625         switch (dbus_message_iter_get_arg_type(iter)) {
2626
2627         case DBUS_TYPE_STRING: {
2628                 const char *s;
2629
2630                 dbus_message_iter_get_basic(iter, &s);
2631
2632                 if (!isempty(s)) {
2633                         if (streq(name, "Id"))
2634                                 i->id = s;
2635                         else if (streq(name, "LoadState"))
2636                                 i->load_state = s;
2637                         else if (streq(name, "ActiveState"))
2638                                 i->active_state = s;
2639                         else if (streq(name, "SubState"))
2640                                 i->sub_state = s;
2641                         else if (streq(name, "Description"))
2642                                 i->description = s;
2643                         else if (streq(name, "FragmentPath"))
2644                                 i->fragment_path = s;
2645                         else if (streq(name, "SourcePath"))
2646                                 i->source_path = s;
2647                         else if (streq(name, "DefaultControlGroup"))
2648                                 i->default_control_group = s;
2649                         else if (streq(name, "StatusText"))
2650                                 i->status_text = s;
2651                         else if (streq(name, "SysFSPath"))
2652                                 i->sysfs_path = s;
2653                         else if (streq(name, "Where"))
2654                                 i->where = s;
2655                         else if (streq(name, "What"))
2656                                 i->what = s;
2657                         else if (streq(name, "Following"))
2658                                 i->following = s;
2659                         else if (streq(name, "UnitFileState"))
2660                                 i->unit_file_state = s;
2661                         else if (streq(name, "Result"))
2662                                 i->result = s;
2663                 }
2664
2665                 break;
2666         }
2667
2668         case DBUS_TYPE_BOOLEAN: {
2669                 dbus_bool_t b;
2670
2671                 dbus_message_iter_get_basic(iter, &b);
2672
2673                 if (streq(name, "Accept"))
2674                         i->accept = b;
2675                 else if (streq(name, "NeedDaemonReload"))
2676                         i->need_daemon_reload = b;
2677                 else if (streq(name, "ConditionResult"))
2678                         i->condition_result = b;
2679
2680                 break;
2681         }
2682
2683         case DBUS_TYPE_UINT32: {
2684                 uint32_t u;
2685
2686                 dbus_message_iter_get_basic(iter, &u);
2687
2688                 if (streq(name, "MainPID")) {
2689                         if (u > 0) {
2690                                 i->main_pid = (pid_t) u;
2691                                 i->running = true;
2692                         }
2693                 } else if (streq(name, "ControlPID"))
2694                         i->control_pid = (pid_t) u;
2695                 else if (streq(name, "ExecMainPID")) {
2696                         if (u > 0)
2697                                 i->main_pid = (pid_t) u;
2698                 } else if (streq(name, "NAccepted"))
2699                         i->n_accepted = u;
2700                 else if (streq(name, "NConnections"))
2701                         i->n_connections = u;
2702
2703                 break;
2704         }
2705
2706         case DBUS_TYPE_INT32: {
2707                 int32_t j;
2708
2709                 dbus_message_iter_get_basic(iter, &j);
2710
2711                 if (streq(name, "ExecMainCode"))
2712                         i->exit_code = (int) j;
2713                 else if (streq(name, "ExecMainStatus"))
2714                         i->exit_status = (int) j;
2715
2716                 break;
2717         }
2718
2719         case DBUS_TYPE_UINT64: {
2720                 uint64_t u;
2721
2722                 dbus_message_iter_get_basic(iter, &u);
2723
2724                 if (streq(name, "ExecMainStartTimestamp"))
2725                         i->start_timestamp = (usec_t) u;
2726                 else if (streq(name, "ExecMainExitTimestamp"))
2727                         i->exit_timestamp = (usec_t) u;
2728                 else if (streq(name, "ActiveEnterTimestamp"))
2729                         i->active_enter_timestamp = (usec_t) u;
2730                 else if (streq(name, "InactiveEnterTimestamp"))
2731                         i->inactive_enter_timestamp = (usec_t) u;
2732                 else if (streq(name, "InactiveExitTimestamp"))
2733                         i->inactive_exit_timestamp = (usec_t) u;
2734                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2735                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2736                 else if (streq(name, "ActiveExitTimestamp"))
2737                         i->active_exit_timestamp = (usec_t) u;
2738                 else if (streq(name, "ConditionTimestamp"))
2739                         i->condition_timestamp = (usec_t) u;
2740
2741                 break;
2742         }
2743
2744         case DBUS_TYPE_ARRAY: {
2745
2746                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2747                     startswith(name, "Exec")) {
2748                         DBusMessageIter sub;
2749
2750                         dbus_message_iter_recurse(iter, &sub);
2751                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2752                                 ExecStatusInfo *info;
2753                                 int r;
2754
2755                                 if (!(info = new0(ExecStatusInfo, 1)))
2756                                         return -ENOMEM;
2757
2758                                 if (!(info->name = strdup(name))) {
2759                                         free(info);
2760                                         return -ENOMEM;
2761                                 }
2762
2763                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2764                                         free(info);
2765                                         return r;
2766                                 }
2767
2768                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2769
2770                                 dbus_message_iter_next(&sub);
2771                         }
2772                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2773                            streq(name, "Documentation")) {
2774
2775                         DBusMessageIter sub;
2776
2777                         dbus_message_iter_recurse(iter, &sub);
2778                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2779                                 const char *s;
2780                                 char **l;
2781
2782                                 dbus_message_iter_get_basic(&sub, &s);
2783
2784                                 l = strv_append(i->documentation, s);
2785                                 if (!l)
2786                                         return -ENOMEM;
2787
2788                                 strv_free(i->documentation);
2789                                 i->documentation = l;
2790
2791                                 dbus_message_iter_next(&sub);
2792                         }
2793                 }
2794
2795                 break;
2796         }
2797
2798         case DBUS_TYPE_STRUCT: {
2799
2800                 if (streq(name, "LoadError")) {
2801                         DBusMessageIter sub;
2802                         const char *n, *message;
2803                         int r;
2804
2805                         dbus_message_iter_recurse(iter, &sub);
2806
2807                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2808                         if (r < 0)
2809                                 return r;
2810
2811                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2812                         if (r < 0)
2813                                 return r;
2814
2815                         if (!isempty(message))
2816                                 i->load_error = message;
2817                 }
2818
2819                 break;
2820         }
2821         }
2822
2823         return 0;
2824 }
2825
2826 static int print_property(const char *name, DBusMessageIter *iter) {
2827         assert(name);
2828         assert(iter);
2829
2830         /* This is a low-level property printer, see
2831          * print_status_info() for the nicer output */
2832
2833         if (arg_property && !strv_find(arg_property, name))
2834                 return 0;
2835
2836         switch (dbus_message_iter_get_arg_type(iter)) {
2837
2838         case DBUS_TYPE_STRUCT: {
2839                 DBusMessageIter sub;
2840                 dbus_message_iter_recurse(iter, &sub);
2841
2842                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2843                         uint32_t u;
2844
2845                         dbus_message_iter_get_basic(&sub, &u);
2846
2847                         if (u)
2848                                 printf("%s=%u\n", name, (unsigned) u);
2849                         else if (arg_all)
2850                                 printf("%s=\n", name);
2851
2852                         return 0;
2853                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2854                         const char *s;
2855
2856                         dbus_message_iter_get_basic(&sub, &s);
2857
2858                         if (arg_all || s[0])
2859                                 printf("%s=%s\n", name, s);
2860
2861                         return 0;
2862                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2863                         const char *a = NULL, *b = NULL;
2864
2865                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2866                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2867
2868                         if (arg_all || !isempty(a) || !isempty(b))
2869                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2870
2871                         return 0;
2872                 }
2873
2874                 break;
2875         }
2876
2877         case DBUS_TYPE_ARRAY:
2878
2879                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2880                         DBusMessageIter sub, sub2;
2881
2882                         dbus_message_iter_recurse(iter, &sub);
2883                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2884                                 const char *path;
2885                                 dbus_bool_t ignore;
2886
2887                                 dbus_message_iter_recurse(&sub, &sub2);
2888
2889                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2890                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2891                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2892
2893                                 dbus_message_iter_next(&sub);
2894                         }
2895
2896                         return 0;
2897
2898                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2899                         DBusMessageIter sub, sub2;
2900
2901                         dbus_message_iter_recurse(iter, &sub);
2902                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2903                                 const char *type, *path;
2904
2905                                 dbus_message_iter_recurse(&sub, &sub2);
2906
2907                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2908                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2909                                         printf("%s=%s\n", type, path);
2910
2911                                 dbus_message_iter_next(&sub);
2912                         }
2913
2914                         return 0;
2915
2916                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2917                         DBusMessageIter sub, sub2;
2918
2919                         dbus_message_iter_recurse(iter, &sub);
2920                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2921                                 const char *base;
2922                                 uint64_t value, next_elapse;
2923
2924                                 dbus_message_iter_recurse(&sub, &sub2);
2925
2926                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2927                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2928                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2929                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2930
2931                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2932                                                base,
2933                                                format_timespan(timespan1, sizeof(timespan1), value),
2934                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2935                                 }
2936
2937                                 dbus_message_iter_next(&sub);
2938                         }
2939
2940                         return 0;
2941
2942                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2943                         DBusMessageIter sub, sub2;
2944
2945                         dbus_message_iter_recurse(iter, &sub);
2946                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2947                                 const char *controller, *attr, *value;
2948
2949                                 dbus_message_iter_recurse(&sub, &sub2);
2950
2951                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2952                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2953                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2954
2955                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2956                                                controller,
2957                                                attr,
2958                                                value);
2959                                 }
2960
2961                                 dbus_message_iter_next(&sub);
2962                         }
2963
2964                         return 0;
2965
2966                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2967                         DBusMessageIter sub;
2968
2969                         dbus_message_iter_recurse(iter, &sub);
2970                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2971                                 ExecStatusInfo info;
2972
2973                                 zero(info);
2974                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2975                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2976                                         char *t;
2977
2978                                         t = strv_join(info.argv, " ");
2979
2980                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2981                                                name,
2982                                                strna(info.path),
2983                                                strna(t),
2984                                                yes_no(info.ignore),
2985                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2986                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2987                                                (unsigned) info. pid,
2988                                                sigchld_code_to_string(info.code),
2989                                                info.status,
2990                                                info.code == CLD_EXITED ? "" : "/",
2991                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2992
2993                                         free(t);
2994                                 }
2995
2996                                 free(info.path);
2997                                 strv_free(info.argv);
2998
2999                                 dbus_message_iter_next(&sub);
3000                         }
3001
3002                         return 0;
3003                 }
3004
3005                 break;
3006         }
3007
3008         if (generic_print_property(name, iter, arg_all) > 0)
3009                 return 0;
3010
3011         if (arg_all)
3012                 printf("%s=[unprintable]\n", name);
3013
3014         return 0;
3015 }
3016
3017 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3018         DBusMessage *reply = NULL;
3019         const char *interface = "";
3020         int r;
3021         DBusMessageIter iter, sub, sub2, sub3;
3022         UnitStatusInfo info;
3023         ExecStatusInfo *p;
3024
3025         assert(path);
3026         assert(new_line);
3027
3028         zero(info);
3029
3030         r = bus_method_call_with_reply (
3031                         bus,
3032                         "org.freedesktop.systemd1",
3033                         path,
3034                         "org.freedesktop.DBus.Properties",
3035                         "GetAll",
3036                         &reply,
3037                         NULL,
3038                         DBUS_TYPE_STRING, &interface,
3039                         DBUS_TYPE_INVALID);
3040         if (r)
3041                 goto finish;
3042
3043         if (!dbus_message_iter_init(reply, &iter) ||
3044             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3045             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3046                 log_error("Failed to parse reply.");
3047                 r = -EIO;
3048                 goto finish;
3049         }
3050
3051         dbus_message_iter_recurse(&iter, &sub);
3052
3053         if (*new_line)
3054                 printf("\n");
3055
3056         *new_line = true;
3057
3058         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3059                 const char *name;
3060
3061                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
3062                         log_error("Failed to parse reply.");
3063                         r = -EIO;
3064                         goto finish;
3065                 }
3066
3067                 dbus_message_iter_recurse(&sub, &sub2);
3068
3069                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
3070                         log_error("Failed to parse reply.");
3071                         r = -EIO;
3072                         goto finish;
3073                 }