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