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