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