chiark / gitweb /
systemctl: make shutdown operations use irreversible jobs
[elogind.git] / src / systemctl / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <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 const char *arg_type = NULL;
72 static const char *arg_load_state = NULL;
73 static char **arg_property = 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();
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_type || ((dot = strrchr(u->id, '.')) &&
299                               streq(dot+1, arg_type))) &&
300                 (!arg_load_state || streq(u->load_state, arg_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, 25);
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, 25);
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, 16);
467                         w = realloc(*unit_infos, sizeof(struct unit_info) * n_units);
468                         if (!w)
469                                 return log_oom();
470
471                         *unit_infos = w;
472                 }
473
474                 u = *unit_infos + *c;
475
476                 bus_parse_unit_info(&sub, u);
477
478                 dbus_message_iter_next(&sub);
479                 (*c)++;
480         }
481
482         if (*c > 0)
483                 qsort(*unit_infos, *c, sizeof(struct unit_info), compare_unit_info);
484
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_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
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, 25);
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, 16);
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(),20);
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 static int list_jobs(DBusConnection *bus, char **args) {
899         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
900         DBusMessageIter iter, sub, sub2;
901         unsigned k = 0;
902         int r;
903
904         pager_open_if_enabled();
905
906         r = bus_method_call_with_reply(
907                         bus,
908                         "org.freedesktop.systemd1",
909                         "/org/freedesktop/systemd1",
910                         "org.freedesktop.systemd1.Manager",
911                         "ListJobs",
912                         &reply,
913                         NULL,
914                         DBUS_TYPE_INVALID);
915         if (r < 0)
916                 return r;
917
918         if (!dbus_message_iter_init(reply, &iter) ||
919             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
920             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
921                 log_error("Failed to parse reply.");
922                 return -EIO;
923         }
924
925         dbus_message_iter_recurse(&iter, &sub);
926
927         if (on_tty())
928                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
929
930         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
931                 const char *name, *type, *state, *job_path, *unit_path;
932                 uint32_t id;
933                 char _cleanup_free_ *e = NULL;
934
935                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
936                         log_error("Failed to parse reply.");
937                         return -EIO;
938                 }
939
940                 dbus_message_iter_recurse(&sub, &sub2);
941
942                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
943                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
944                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
945                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
946                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
947                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
948                         log_error("Failed to parse reply.");
949                         return -EIO;
950                 }
951
952                 e = arg_full ? NULL : ellipsize(name, 25, 33);
953                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
954
955                 k++;
956
957                 dbus_message_iter_next(&sub);
958         }
959
960         if (on_tty())
961                 printf("\n%u jobs listed.\n", k);
962
963         return 0;
964 }
965
966 static int load_unit(DBusConnection *bus, char **args) {
967         char **name;
968
969         assert(args);
970
971         STRV_FOREACH(name, args+1) {
972                 _cleanup_free_ char *n = NULL;
973                 int r;
974
975                 n = unit_name_mangle(*name);
976                 if (!n)
977                         return log_oom();
978
979                 r = bus_method_call_with_reply(
980                                 bus,
981                                 "org.freedesktop.systemd1",
982                                 "/org/freedesktop/systemd1",
983                                 "org.freedesktop.systemd1.Manager",
984                                 "LoadUnit",
985                                 NULL,
986                                 NULL,
987                                 DBUS_TYPE_STRING, &n,
988                                 DBUS_TYPE_INVALID);
989                 if (r < 0)
990                         return r;
991         }
992
993         return 0;
994 }
995
996 static int cancel_job(DBusConnection *bus, char **args) {
997         char **name;
998
999         assert(args);
1000
1001         if (strv_length(args) <= 1)
1002                 return daemon_reload(bus, args);
1003
1004         STRV_FOREACH(name, args+1) {
1005                 uint32_t id;
1006                 int r;
1007
1008                 r = safe_atou32(*name, &id);
1009                 if (r < 0) {
1010                         log_error("Failed to parse job id: %s", strerror(-r));
1011                         return r;
1012                 }
1013
1014                 r = bus_method_call_with_reply(
1015                                 bus,
1016                                 "org.freedesktop.systemd1",
1017                                 "/org/freedesktop/systemd1",
1018                                 "org.freedesktop.systemd1.Manager",
1019                                 "CancelJob",
1020                                 NULL,
1021                                 NULL,
1022                                 DBUS_TYPE_UINT32, &id,
1023                                 DBUS_TYPE_INVALID);
1024                 if (r < 0)
1025                         return r;
1026         }
1027
1028         return 0;
1029 }
1030
1031 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1032         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1033         dbus_bool_t b = FALSE;
1034         DBusMessageIter iter, sub;
1035         const char
1036                 *interface = "org.freedesktop.systemd1.Unit",
1037                 *property = "NeedDaemonReload",
1038                 *path;
1039         _cleanup_free_ char *n = NULL;
1040         int r;
1041
1042         /* We ignore all errors here, since this is used to show a warning only */
1043
1044         n = unit_name_mangle(unit);
1045         if (!n)
1046                 return log_oom();
1047
1048         r = bus_method_call_with_reply (
1049                         bus,
1050                         "org.freedesktop.systemd1",
1051                         "/org/freedesktop/systemd1",
1052                         "org.freedesktop.systemd1.Manager",
1053                         "GetUnit",
1054                         &reply,
1055                         NULL,
1056                         DBUS_TYPE_STRING, &n,
1057                         DBUS_TYPE_INVALID);
1058         if (r < 0)
1059                 return r;
1060
1061         if (!dbus_message_get_args(reply, NULL,
1062                                    DBUS_TYPE_OBJECT_PATH, &path,
1063                                    DBUS_TYPE_INVALID))
1064                 return -EIO;
1065
1066         dbus_message_unref(reply);
1067         reply = NULL;
1068
1069         r = bus_method_call_with_reply(
1070                         bus,
1071                         "org.freedesktop.systemd1",
1072                         path,
1073                         "org.freedesktop.DBus.Properties",
1074                         "Get",
1075                         &reply,
1076                         NULL,
1077                         DBUS_TYPE_STRING, &interface,
1078                         DBUS_TYPE_STRING, &property,
1079                         DBUS_TYPE_INVALID);
1080         if (r < 0)
1081                 return r;
1082
1083         if (!dbus_message_iter_init(reply, &iter) ||
1084             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1085                 return -EIO;
1086
1087         dbus_message_iter_recurse(&iter, &sub);
1088         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1089                 return -EIO;
1090
1091         dbus_message_iter_get_basic(&sub, &b);
1092         return b;
1093 }
1094
1095 typedef struct WaitData {
1096         Set *set;
1097
1098         char *name;
1099         char *result;
1100 } WaitData;
1101
1102 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1103         DBusError _cleanup_dbus_error_free_ error;
1104         WaitData *d = data;
1105
1106         dbus_error_init(&error);
1107
1108         assert(connection);
1109         assert(message);
1110         assert(d);
1111
1112         log_debug("Got D-Bus request: %s.%s() on %s",
1113                   dbus_message_get_interface(message),
1114                   dbus_message_get_member(message),
1115                   dbus_message_get_path(message));
1116
1117         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1118                 log_error("Warning! D-Bus connection terminated.");
1119                 dbus_connection_close(connection);
1120
1121         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1122                 uint32_t id;
1123                 const char *path, *result, *unit;
1124
1125                 if (dbus_message_get_args(message, &error,
1126                                           DBUS_TYPE_UINT32, &id,
1127                                           DBUS_TYPE_OBJECT_PATH, &path,
1128                                           DBUS_TYPE_STRING, &unit,
1129                                           DBUS_TYPE_STRING, &result,
1130                                           DBUS_TYPE_INVALID)) {
1131
1132                         free(set_remove(d->set, (char*) path));
1133
1134                         if (!isempty(result))
1135                                 d->result = strdup(result);
1136
1137                         if (!isempty(unit))
1138                                 d->name = strdup(unit);
1139
1140                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1141                 }
1142 #ifndef LEGACY
1143                 dbus_error_free(&error);
1144                 if (dbus_message_get_args(message, &error,
1145                                           DBUS_TYPE_UINT32, &id,
1146                                           DBUS_TYPE_OBJECT_PATH, &path,
1147                                           DBUS_TYPE_STRING, &result,
1148                                           DBUS_TYPE_INVALID)) {
1149                         /* Compatibility with older systemd versions <
1150                          * 183 during upgrades. This should be dropped
1151                          * one day. */
1152                         free(set_remove(d->set, (char*) path));
1153
1154                         if (*result)
1155                                 d->result = strdup(result);
1156
1157                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1158                 }
1159 #endif
1160
1161                 log_error("Failed to parse message: %s", bus_error_message(&error));
1162         }
1163
1164         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1165 }
1166
1167 static int enable_wait_for_jobs(DBusConnection *bus) {
1168         DBusError error;
1169
1170         assert(bus);
1171
1172         if (private_bus)
1173                 return 0;
1174
1175         dbus_error_init(&error);
1176         dbus_bus_add_match(bus,
1177                            "type='signal',"
1178                            "sender='org.freedesktop.systemd1',"
1179                            "interface='org.freedesktop.systemd1.Manager',"
1180                            "member='JobRemoved',"
1181                            "path='/org/freedesktop/systemd1'",
1182                            &error);
1183
1184         if (dbus_error_is_set(&error)) {
1185                 log_error("Failed to add match: %s", bus_error_message(&error));
1186                 dbus_error_free(&error);
1187                 return -EIO;
1188         }
1189
1190         /* This is slightly dirty, since we don't undo the match registrations. */
1191         return 0;
1192 }
1193
1194 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1195         int r = 0;
1196         WaitData d;
1197
1198         assert(bus);
1199         assert(s);
1200
1201         zero(d);
1202         d.set = s;
1203
1204         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1205                 return log_oom();
1206
1207         while (!set_isempty(s)) {
1208
1209                 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1210                         log_error("Disconnected from bus.");
1211                         return -ECONNREFUSED;
1212                 }
1213
1214                 if (!d.result)
1215                         goto free_name;
1216
1217                 if (!arg_quiet) {
1218                         if (streq(d.result, "timeout"))
1219                                 log_error("Job for %s timed out.", strna(d.name));
1220                         else if (streq(d.result, "canceled"))
1221                                 log_error("Job for %s canceled.", strna(d.name));
1222                         else if (streq(d.result, "dependency"))
1223                                 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
1224                         else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1225                                 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
1226                 }
1227
1228                 if (streq_ptr(d.result, "timeout"))
1229                         r = -ETIME;
1230                 else if (streq_ptr(d.result, "canceled"))
1231                         r = -ECANCELED;
1232                 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1233                         r = -EIO;
1234
1235                 free(d.result);
1236                 d.result = NULL;
1237
1238         free_name:
1239                 free(d.name);
1240                 d.name = NULL;
1241         }
1242
1243         dbus_connection_remove_filter(bus, wait_filter, &d);
1244         return r;
1245 }
1246
1247 static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1248         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1249         _cleanup_free_ char *n = NULL;
1250         DBusMessageIter iter, sub;
1251         const char
1252                 *interface = "org.freedesktop.systemd1.Unit",
1253                 *property = "ActiveState";
1254         const char *state, *path;
1255         DBusError error;
1256         int r;
1257
1258         assert(name);
1259
1260         dbus_error_init(&error);
1261
1262         n = unit_name_mangle(name);
1263         if (!n)
1264                 return log_oom();
1265
1266         r = bus_method_call_with_reply (
1267                         bus,
1268                         "org.freedesktop.systemd1",
1269                         "/org/freedesktop/systemd1",
1270                         "org.freedesktop.systemd1.Manager",
1271                         "GetUnit",
1272                         &reply,
1273                         &error,
1274                         DBUS_TYPE_STRING, &n,
1275                         DBUS_TYPE_INVALID);
1276         if (r < 0) {
1277                 dbus_error_free(&error);
1278
1279                 if (!quiet)
1280                         puts("unknown");
1281                 return 0;
1282         }
1283
1284         if (!dbus_message_get_args(reply, NULL,
1285                                    DBUS_TYPE_OBJECT_PATH, &path,
1286                                    DBUS_TYPE_INVALID)) {
1287                 log_error("Failed to parse reply.");
1288                 return -EIO;
1289         }
1290
1291         dbus_message_unref(reply);
1292         reply = NULL;
1293
1294         r = bus_method_call_with_reply(
1295                         bus,
1296                         "org.freedesktop.systemd1",
1297                         path,
1298                         "org.freedesktop.DBus.Properties",
1299                         "Get",
1300                         &reply,
1301                         NULL,
1302                         DBUS_TYPE_STRING, &interface,
1303                         DBUS_TYPE_STRING, &property,
1304                         DBUS_TYPE_INVALID);
1305         if (r < 0) {
1306                 if (!quiet)
1307                         puts("unknown");
1308                 return 0;
1309         }
1310
1311         if (!dbus_message_iter_init(reply, &iter) ||
1312             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1313                 log_error("Failed to parse reply.");
1314                 return r;
1315         }
1316
1317         dbus_message_iter_recurse(&iter, &sub);
1318
1319         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1320                 log_error("Failed to parse reply.");
1321                 return r;
1322         }
1323
1324         dbus_message_iter_get_basic(&sub, &state);
1325
1326         if (!quiet)
1327                 puts(state);
1328
1329         return strv_find(check_states, state) ? 1 : 0;
1330 }
1331
1332 static void check_triggering_units(
1333                 DBusConnection *bus,
1334                 const char *unit_name) {
1335
1336         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1337         DBusMessageIter iter, sub;
1338         const char *interface = "org.freedesktop.systemd1.Unit",
1339                    *load_state_property = "LoadState",
1340                    *triggered_by_property = "TriggeredBy",
1341                    *state;
1342         char _cleanup_free_ *unit_path = NULL, *n = NULL;
1343         bool print_warning_label = true;
1344         int r;
1345
1346         n = unit_name_mangle(unit_name);
1347         if (!n) {
1348                 log_oom();
1349                 return;
1350         }
1351
1352         unit_path = unit_dbus_path_from_name(n);
1353         if (!unit_path) {
1354                 log_oom();
1355                 return;
1356         }
1357
1358         r = bus_method_call_with_reply(
1359                         bus,
1360                         "org.freedesktop.systemd1",
1361                         unit_path,
1362                         "org.freedesktop.DBus.Properties",
1363                         "Get",
1364                         &reply,
1365                         NULL,
1366                         DBUS_TYPE_STRING, &interface,
1367                         DBUS_TYPE_STRING, &load_state_property,
1368                         DBUS_TYPE_INVALID);
1369         if (r < 0)
1370                 return;
1371
1372         if (!dbus_message_iter_init(reply, &iter) ||
1373             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1374                 log_error("Failed to parse reply.");
1375                 return;
1376         }
1377
1378         dbus_message_iter_recurse(&iter, &sub);
1379
1380         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1381             log_error("Failed to parse reply.");
1382             return;
1383         }
1384
1385         dbus_message_iter_get_basic(&sub, &state);
1386
1387         if (streq(state, "masked"))
1388             return;
1389
1390         dbus_message_unref(reply);
1391         reply = NULL;
1392
1393         r = bus_method_call_with_reply(
1394                         bus,
1395                         "org.freedesktop.systemd1",
1396                         unit_path,
1397                         "org.freedesktop.DBus.Properties",
1398                         "Get",
1399                         &reply,
1400                         NULL,
1401                         DBUS_TYPE_STRING, &interface,
1402                         DBUS_TYPE_STRING, &triggered_by_property,
1403                         DBUS_TYPE_INVALID);
1404         if (r < 0)
1405                 return;
1406
1407         if (!dbus_message_iter_init(reply, &iter) ||
1408             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1409                 log_error("Failed to parse reply.");
1410                 return;
1411         }
1412
1413         dbus_message_iter_recurse(&iter, &sub);
1414         dbus_message_iter_recurse(&sub, &iter);
1415         sub = iter;
1416
1417         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1418                 const char * const check_states[] = {
1419                         "active",
1420                         "reloading",
1421                         NULL
1422                 };
1423                 const char *service_trigger;
1424
1425                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1426                         log_error("Failed to parse reply.");
1427                         return;
1428                 }
1429
1430                 dbus_message_iter_get_basic(&sub, &service_trigger);
1431
1432                 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
1433                 if (r < 0)
1434                         return;
1435                 if (r > 0) {
1436                         if (print_warning_label) {
1437                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1438                                 print_warning_label = false;
1439                         }
1440
1441                         log_warning("  %s", service_trigger);
1442                 }
1443
1444                 dbus_message_iter_next(&sub);
1445         }
1446 }
1447
1448 static int start_unit_one(
1449                 DBusConnection *bus,
1450                 const char *method,
1451                 const char *name,
1452                 const char *mode,
1453                 DBusError *error,
1454                 Set *s) {
1455
1456         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1457         _cleanup_free_ char *n;
1458         const char *path;
1459         int r;
1460
1461         assert(method);
1462         assert(name);
1463         assert(mode);
1464         assert(error);
1465
1466         n = unit_name_mangle(name);
1467         if (!n)
1468                 return log_oom();
1469
1470         r = bus_method_call_with_reply(
1471                         bus,
1472                         "org.freedesktop.systemd1",
1473                         "/org/freedesktop/systemd1",
1474                         "org.freedesktop.systemd1.Manager",
1475                         method,
1476                         &reply,
1477                         error,
1478                         DBUS_TYPE_STRING, &n,
1479                         DBUS_TYPE_STRING, &mode,
1480                         DBUS_TYPE_INVALID);
1481         if (r) {
1482                 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1483                         /* There's always a fallback possible for
1484                          * legacy actions. */
1485                         r = -EADDRNOTAVAIL;
1486                 else
1487                         log_error("Failed to issue method call: %s", bus_error_message(error));
1488
1489                 return r;
1490         }
1491
1492         if (!dbus_message_get_args(reply, error,
1493                                    DBUS_TYPE_OBJECT_PATH, &path,
1494                                    DBUS_TYPE_INVALID)) {
1495                 log_error("Failed to parse reply: %s", bus_error_message(error));
1496                 return -EIO;
1497         }
1498
1499         if (need_daemon_reload(bus, n))
1500                 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1501                             n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1502
1503         if (s) {
1504                 char *p;
1505
1506                 p = strdup(path);
1507                 if (!p)
1508                         return log_oom();
1509
1510                 r = set_put(s, p);
1511                 if (r < 0) {
1512                         free(p);
1513                         log_error("Failed to add path to set.");
1514                         return r;
1515                 }
1516         }
1517
1518         return 0;
1519 }
1520
1521 static enum action verb_to_action(const char *verb) {
1522         if (streq(verb, "halt"))
1523                 return ACTION_HALT;
1524         else if (streq(verb, "poweroff"))
1525                 return ACTION_POWEROFF;
1526         else if (streq(verb, "reboot"))
1527                 return ACTION_REBOOT;
1528         else if (streq(verb, "kexec"))
1529                 return ACTION_KEXEC;
1530         else if (streq(verb, "rescue"))
1531                 return ACTION_RESCUE;
1532         else if (streq(verb, "emergency"))
1533                 return ACTION_EMERGENCY;
1534         else if (streq(verb, "default"))
1535                 return ACTION_DEFAULT;
1536         else if (streq(verb, "exit"))
1537                 return ACTION_EXIT;
1538         else if (streq(verb, "suspend"))
1539                 return ACTION_SUSPEND;
1540         else if (streq(verb, "hibernate"))
1541                 return ACTION_HIBERNATE;
1542         else if (streq(verb, "hybrid-sleep"))
1543                 return ACTION_HYBRID_SLEEP;
1544         else
1545                 return ACTION_INVALID;
1546 }
1547
1548 static int start_unit(DBusConnection *bus, char **args) {
1549
1550         static const char * const table[_ACTION_MAX] = {
1551                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1552                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1553                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1554                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1555                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1556                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1557                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1558                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1559                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1560                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1561                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1562                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1563                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1564                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
1565                 [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
1566         };
1567
1568         int r, ret = 0;
1569         const char *method, *mode, *one_name;
1570         Set _cleanup_set_free_free_ *s = NULL;
1571         DBusError _cleanup_dbus_error_free_ error;
1572         char **name;
1573
1574         dbus_error_init(&error);
1575
1576         assert(bus);
1577
1578         ask_password_agent_open_if_enabled();
1579
1580         if (arg_action == ACTION_SYSTEMCTL) {
1581                 method =
1582                         streq(args[0], "stop") ||
1583                         streq(args[0], "condstop")              ? "StopUnit" :
1584                         streq(args[0], "reload")                ? "ReloadUnit" :
1585                         streq(args[0], "restart")               ? "RestartUnit" :
1586
1587                         streq(args[0], "try-restart")           ||
1588                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1589
1590                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1591
1592                         streq(args[0], "reload-or-try-restart") ||
1593                         streq(args[0], "condreload") ||
1594
1595                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1596                                                                   "StartUnit";
1597
1598                 if (streq(args[0], "isolate") ||
1599                     streq(args[0], "rescue")  ||
1600                     streq(args[0], "emergency") ||
1601                     streq(args[0], "default"))
1602                         mode = "isolate";
1603                 else if (streq(args[0], "halt") ||
1604                          streq(args[0], "poweroff") ||
1605                          streq(args[0], "reboot") ||
1606                          streq(args[0], "kexec") ||
1607                          streq(args[0], "exit") ||
1608                          streq(args[0], "suspend") ||
1609                          streq(args[0], "hibernate") ||
1610                          streq(args[0], "hybrid-sleep"))
1611                         mode = "replace-irreversibly";
1612                 else
1613                         mode = arg_job_mode;
1614
1615                 one_name = table[verb_to_action(args[0])];
1616
1617         } else {
1618                 assert(arg_action < ELEMENTSOF(table));
1619                 assert(table[arg_action]);
1620
1621                 method = "StartUnit";
1622
1623                 mode = (arg_action == ACTION_EMERGENCY ||
1624                         arg_action == ACTION_RESCUE ||
1625                         arg_action == ACTION_RUNLEVEL2 ||
1626                         arg_action == ACTION_RUNLEVEL3 ||
1627                         arg_action == ACTION_RUNLEVEL4 ||
1628                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace-irreversibly";
1629
1630                 one_name = table[arg_action];
1631         }
1632
1633         if (!arg_no_block) {
1634                 ret = enable_wait_for_jobs(bus);
1635                 if (ret < 0) {
1636                         log_error("Could not watch jobs: %s", strerror(-ret));
1637                         return ret;
1638                 }
1639
1640                 s = set_new(string_hash_func, string_compare_func);
1641                 if (!s)
1642                         return log_oom();
1643         }
1644
1645         if (one_name) {
1646                 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1647                 if (ret < 0)
1648                         ret = translate_bus_error_to_exit_status(ret, &error);
1649         } else {
1650                 STRV_FOREACH(name, args+1) {
1651                         r = start_unit_one(bus, method, *name, mode, &error, s);
1652                         if (r < 0) {
1653                                 ret = translate_bus_error_to_exit_status(r, &error);
1654                                 dbus_error_free(&error);
1655                         }
1656                 }
1657         }
1658
1659         if (!arg_no_block) {
1660                 r = wait_for_jobs(bus, s);
1661                 if (r < 0)
1662                         return r;
1663
1664                 /* When stopping units, warn if they can still be triggered by
1665                  * another active unit (socket, path, timer) */
1666                 if (!arg_quiet && streq(method, "StopUnit")) {
1667                         if (one_name)
1668                                 check_triggering_units(bus, one_name);
1669                         else
1670                                 STRV_FOREACH(name, args+1)
1671                                         check_triggering_units(bus, *name);
1672                 }
1673         }
1674
1675         return ret;
1676 }
1677
1678 /* Ask systemd-logind, which might grant access to unprivileged users
1679  * through PolicyKit */
1680 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1681 #ifdef HAVE_LOGIND
1682         const char *method;
1683         dbus_bool_t interactive = true;
1684
1685         if (!bus)
1686                 return -EIO;
1687
1688         polkit_agent_open_if_enabled();
1689
1690         switch (a) {
1691
1692         case ACTION_REBOOT:
1693                 method = "Reboot";
1694                 break;
1695
1696         case ACTION_POWEROFF:
1697                 method = "PowerOff";
1698                 break;
1699
1700         case ACTION_SUSPEND:
1701                 method = "Suspend";
1702                 break;
1703
1704         case ACTION_HIBERNATE:
1705                 method = "Hibernate";
1706                 break;
1707
1708         case ACTION_HYBRID_SLEEP:
1709                 method = "HybridSleep";
1710                 break;
1711
1712         default:
1713                 return -EINVAL;
1714         }
1715
1716         return bus_method_call_with_reply(
1717                         bus,
1718                         "org.freedesktop.login1",
1719                         "/org/freedesktop/login1",
1720                         "org.freedesktop.login1.Manager",
1721                         method,
1722                         NULL,
1723                         NULL,
1724                         DBUS_TYPE_BOOLEAN, &interactive,
1725                         DBUS_TYPE_INVALID);
1726 #else
1727         return -ENOSYS;
1728 #endif
1729 }
1730
1731 static int check_inhibitors(DBusConnection *bus, enum action a) {
1732 #ifdef HAVE_LOGIND
1733         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1734         DBusMessageIter iter, sub, sub2;
1735         int r;
1736         unsigned c = 0;
1737         _cleanup_strv_free_ char **sessions = NULL;
1738         char **s;
1739
1740         if (!bus)
1741                 return 0;
1742
1743         if (arg_ignore_inhibitors || arg_force > 0)
1744                 return 0;
1745
1746         if (arg_when > 0)
1747                 return 0;
1748
1749         if (geteuid() == 0)
1750                 return 0;
1751
1752         if (!on_tty())
1753                 return 0;
1754
1755         r = bus_method_call_with_reply(
1756                         bus,
1757                         "org.freedesktop.login1",
1758                         "/org/freedesktop/login1",
1759                         "org.freedesktop.login1.Manager",
1760                         "ListInhibitors",
1761                         &reply,
1762                         NULL,
1763                         DBUS_TYPE_INVALID);
1764         if (r < 0)
1765                 /* If logind is not around, then there are no inhibitors... */
1766                 return 0;
1767
1768         if (!dbus_message_iter_init(reply, &iter) ||
1769             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1770             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1771                 log_error("Failed to parse reply.");
1772                 return -EIO;
1773         }
1774
1775         dbus_message_iter_recurse(&iter, &sub);
1776         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1777                 const char *what, *who, *why, *mode;
1778                 uint32_t uid, pid;
1779                 _cleanup_strv_free_ char **sv = NULL;
1780                 _cleanup_free_ char *comm = NULL, *user = NULL;
1781
1782                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1783                         log_error("Failed to parse reply.");
1784                         return -EIO;
1785                 }
1786
1787                 dbus_message_iter_recurse(&sub, &sub2);
1788
1789                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
1790                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
1791                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
1792                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
1793                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
1794                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
1795                         log_error("Failed to parse reply.");
1796                         return -EIO;
1797                 }
1798
1799                 if (!streq(mode, "block"))
1800                         goto next;
1801
1802                 sv = strv_split(what, ":");
1803                 if (!sv)
1804                         return log_oom();
1805
1806                 if (!strv_contains(sv,
1807                                   a == ACTION_HALT ||
1808                                   a == ACTION_POWEROFF ||
1809                                   a == ACTION_REBOOT ||
1810                                   a == ACTION_KEXEC ? "shutdown" : "sleep"))
1811                         goto next;
1812
1813                 get_process_comm(pid, &comm);
1814                 user = uid_to_name(uid);
1815                 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
1816                             who, (unsigned long) pid, strna(comm), strna(user), why);
1817                 c++;
1818
1819         next:
1820                 dbus_message_iter_next(&sub);
1821         }
1822
1823         dbus_message_iter_recurse(&iter, &sub);
1824
1825         /* Check for current sessions */
1826         sd_get_sessions(&sessions);
1827         STRV_FOREACH(s, sessions) {
1828                 uid_t uid;
1829                 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1830
1831                 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1832                         continue;
1833
1834                 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1835                         continue;
1836
1837                 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1838                         continue;
1839
1840                 sd_session_get_tty(*s, &tty);
1841                 sd_session_get_seat(*s, &seat);
1842                 sd_session_get_service(*s, &service);
1843                 user = uid_to_name(uid);
1844
1845                 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1846                 c++;
1847         }
1848
1849         if (c <= 0)
1850                 return 0;
1851
1852         log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
1853                   a == ACTION_HALT ? "halt" :
1854                   a == ACTION_POWEROFF ? "poweroff" :
1855                   a == ACTION_REBOOT ? "reboot" :
1856                   a == ACTION_KEXEC ? "kexec" :
1857                   a == ACTION_SUSPEND ? "suspend" :
1858                   a == ACTION_HIBERNATE ? "hibernate" : "hybrid-sleep");
1859
1860         return -EPERM;
1861 #else
1862         return 0;
1863 #endif
1864 }
1865
1866 static int start_special(DBusConnection *bus, char **args) {
1867         enum action a;
1868         int r;
1869
1870         assert(args);
1871
1872         a = verb_to_action(args[0]);
1873
1874         r = check_inhibitors(bus, a);
1875         if (r < 0)
1876                 return r;
1877
1878         if (arg_force >= 2 && geteuid() != 0) {
1879                 log_error("Must be root.");
1880                 return -EPERM;
1881         }
1882
1883         if (arg_force >= 2 &&
1884             (a == ACTION_HALT ||
1885              a == ACTION_POWEROFF ||
1886              a == ACTION_REBOOT))
1887                 halt_now(a);
1888
1889         if (arg_force >= 1 &&
1890             (a == ACTION_HALT ||
1891              a == ACTION_POWEROFF ||
1892              a == ACTION_REBOOT ||
1893              a == ACTION_KEXEC ||
1894              a == ACTION_EXIT))
1895                 return daemon_reload(bus, args);
1896
1897         /* first try logind, to allow authentication with polkit */
1898         if (geteuid() != 0 &&
1899             (a == ACTION_POWEROFF ||
1900              a == ACTION_REBOOT ||
1901              a == ACTION_SUSPEND ||
1902              a == ACTION_HIBERNATE ||
1903              a == ACTION_HYBRID_SLEEP)) {
1904                 r = reboot_with_logind(bus, a);
1905                 if (r >= 0)
1906                         return r;
1907         }
1908
1909         r = start_unit(bus, args);
1910         if (r == EXIT_SUCCESS)
1911                 warn_wall(a);
1912
1913         return r;
1914 }
1915
1916 static int check_unit_active(DBusConnection *bus, char **args) {
1917         const char * const check_states[] = {
1918                 "active",
1919                 "reloading",
1920                 NULL
1921         };
1922
1923         char **name;
1924         int r = 3; /* According to LSB: "program is not running" */
1925
1926         assert(bus);
1927         assert(args);
1928
1929         STRV_FOREACH(name, args+1) {
1930                 int state;
1931
1932                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1933                 if (state < 0)
1934                         return state;
1935                 if (state > 0)
1936                         r = 0;
1937         }
1938
1939         return r;
1940 }
1941
1942 static int check_unit_failed(DBusConnection *bus, char **args) {
1943         const char * const check_states[] = {
1944                 "failed",
1945                 NULL
1946         };
1947
1948         char **name;
1949         int r = 1;
1950
1951         assert(bus);
1952         assert(args);
1953
1954         STRV_FOREACH(name, args+1) {
1955                 int state;
1956
1957                 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1958                 if (state < 0)
1959                         return state;
1960                 if (state > 0)
1961                         r = 0;
1962         }
1963
1964         return r;
1965 }
1966
1967 static int kill_unit(DBusConnection *bus, char **args) {
1968         char **name;
1969         int r = 0;
1970
1971         assert(bus);
1972         assert(args);
1973
1974         if (!arg_kill_who)
1975                 arg_kill_who = "all";
1976
1977         STRV_FOREACH(name, args+1) {
1978                 _cleanup_free_ char *n = NULL;
1979
1980                 n = unit_name_mangle(*name);
1981                 if (!n)
1982                         return log_oom();
1983
1984                 r = bus_method_call_with_reply(
1985                                 bus,
1986                                 "org.freedesktop.systemd1",
1987                                 "/org/freedesktop/systemd1",
1988                                 "org.freedesktop.systemd1.Manager",
1989                                 "KillUnit",
1990                                 NULL,
1991                                 NULL,
1992                                 DBUS_TYPE_STRING, &n,
1993                                 DBUS_TYPE_STRING, &arg_kill_who,
1994                                 DBUS_TYPE_INT32, &arg_signal,
1995                                 DBUS_TYPE_INVALID);
1996                 if (r < 0)
1997                         return r;
1998         }
1999         return 0;
2000 }
2001
2002 static int set_cgroup(DBusConnection *bus, char **args) {
2003         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2004         DBusError error;
2005         const char *method;
2006         DBusMessageIter iter;
2007         int r;
2008         _cleanup_free_ char *n = NULL;
2009         const char *runtime;
2010
2011         assert(bus);
2012         assert(args);
2013
2014         dbus_error_init(&error);
2015
2016         method =
2017                 streq(args[0], "set-cgroup")  ? "SetUnitControlGroups" :
2018                 streq(args[0], "unset-group") ? "UnsetUnitControlGroups"
2019                                               : "UnsetUnitControlGroupAttributes";
2020
2021         n = unit_name_mangle(args[1]);
2022         if (!n)
2023                 return log_oom();
2024
2025         m = dbus_message_new_method_call(
2026                         "org.freedesktop.systemd1",
2027                         "/org/freedesktop/systemd1",
2028                         "org.freedesktop.systemd1.Manager",
2029                         method);
2030         if (!m)
2031                 return log_oom();
2032
2033         dbus_message_iter_init_append(m, &iter);
2034         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2035                 return log_oom();
2036
2037         r = bus_append_strv_iter(&iter, args + 2);
2038         if (r < 0)
2039                 return log_oom();
2040
2041         runtime = arg_runtime ? "runtime" : "persistent";
2042         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2043                 return log_oom();
2044
2045         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2046         if (!reply) {
2047                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2048                 dbus_error_free(&error);
2049                 return -EIO;
2050         }
2051
2052         return 0;
2053 }
2054
2055 static int set_cgroup_attr(DBusConnection *bus, char **args) {
2056         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2057         DBusError error;
2058         DBusMessageIter iter, sub, sub2;
2059         char **x, **y;
2060         _cleanup_free_ char *n = NULL;
2061         const char *runtime;
2062
2063         assert(bus);
2064         assert(args);
2065
2066         dbus_error_init(&error);
2067
2068         if (strv_length(args) % 2 != 0) {
2069                 log_error("Expecting an uneven number of arguments!");
2070                 return -EINVAL;
2071         }
2072
2073         n = unit_name_mangle(args[1]);
2074         if (!n)
2075                 return log_oom();
2076
2077         m = dbus_message_new_method_call(
2078                         "org.freedesktop.systemd1",
2079                         "/org/freedesktop/systemd1",
2080                         "org.freedesktop.systemd1.Manager",
2081                         "SetUnitControlGroupAttributes");
2082         if (!m)
2083                 return log_oom();
2084
2085         dbus_message_iter_init_append(m, &iter);
2086         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
2087             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub))
2088                 return log_oom();
2089
2090         STRV_FOREACH_PAIR(x, y, args + 2) {
2091                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2092                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) ||
2093                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) ||
2094                     !dbus_message_iter_close_container(&sub, &sub2))
2095                         return log_oom();
2096         }
2097
2098         runtime = arg_runtime ? "runtime" : "persistent";
2099         if (!dbus_message_iter_close_container(&iter, &sub) ||
2100             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
2101                 return log_oom();
2102
2103         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2104         if (!reply) {
2105                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2106                 dbus_error_free(&error);
2107                 return -EIO;
2108         }
2109
2110         return 0;
2111 }
2112
2113 static int get_cgroup_attr(DBusConnection *bus, char **args) {
2114         _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2115         DBusError error;
2116         DBusMessageIter iter;
2117         int r;
2118         _cleanup_free_ char *n = NULL;
2119         _cleanup_strv_free_ char **list = NULL;
2120         char **a;
2121
2122         assert(bus);
2123         assert(args);
2124
2125         dbus_error_init(&error);
2126
2127         n = unit_name_mangle(args[1]);
2128         if (!n)
2129                 return log_oom();
2130
2131         m = dbus_message_new_method_call(
2132                         "org.freedesktop.systemd1",
2133                         "/org/freedesktop/systemd1",
2134                         "org.freedesktop.systemd1.Manager",
2135                         "GetUnitControlGroupAttributes");
2136         if (!m)
2137                 return log_oom();
2138
2139         dbus_message_iter_init_append(m, &iter);
2140         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
2141                 return log_oom();
2142
2143         r = bus_append_strv_iter(&iter, args + 2);
2144         if (r < 0)
2145                 return log_oom();
2146
2147         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2148         if (!reply) {
2149                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2150                 dbus_error_free(&error);
2151                 return -EIO;
2152         }
2153
2154         dbus_message_iter_init(reply, &iter);
2155         r = bus_parse_strv_iter(&iter, &list);
2156         if (r < 0) {
2157                 log_error("Failed to parse value list.");
2158                 return r;
2159         }
2160
2161         STRV_FOREACH(a, list) {
2162                 if (endswith(*a, "\n"))
2163                         fputs(*a, stdout);
2164                 else
2165                         puts(*a);
2166         }
2167
2168         return 0;
2169 }
2170
2171 typedef struct ExecStatusInfo {
2172         char *name;
2173
2174         char *path;
2175         char **argv;
2176
2177         bool ignore;
2178
2179         usec_t start_timestamp;
2180         usec_t exit_timestamp;
2181         pid_t pid;
2182         int code;
2183         int status;
2184
2185         LIST_FIELDS(struct ExecStatusInfo, exec);
2186 } ExecStatusInfo;
2187
2188 static void exec_status_info_free(ExecStatusInfo *i) {
2189         assert(i);
2190
2191         free(i->name);
2192         free(i->path);
2193         strv_free(i->argv);
2194         free(i);
2195 }
2196
2197 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2198         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2199         DBusMessageIter sub2, sub3;
2200         const char*path;
2201         unsigned n;
2202         uint32_t pid;
2203         int32_t code, status;
2204         dbus_bool_t ignore;
2205
2206         assert(i);
2207         assert(i);
2208
2209         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2210                 return -EIO;
2211
2212         dbus_message_iter_recurse(sub, &sub2);
2213
2214         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2215                 return -EIO;
2216
2217         i->path = strdup(path);
2218         if (!i->path)
2219                 return -ENOMEM;
2220
2221         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2222             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2223                 return -EIO;
2224
2225         n = 0;
2226         dbus_message_iter_recurse(&sub2, &sub3);
2227         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2228                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2229                 dbus_message_iter_next(&sub3);
2230                 n++;
2231         }
2232
2233         i->argv = new0(char*, n+1);
2234         if (!i->argv)
2235                 return -ENOMEM;
2236
2237         n = 0;
2238         dbus_message_iter_recurse(&sub2, &sub3);
2239         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2240                 const char *s;
2241
2242                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2243                 dbus_message_iter_get_basic(&sub3, &s);
2244                 dbus_message_iter_next(&sub3);
2245
2246                 i->argv[n] = strdup(s);
2247                 if (!i->argv[n])
2248                         return -ENOMEM;
2249
2250                 n++;
2251         }
2252
2253         if (!dbus_message_iter_next(&sub2) ||
2254             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2255             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2256             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2257             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2258             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2259             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2260             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2261             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2262                 return -EIO;
2263
2264         i->ignore = ignore;
2265         i->start_timestamp = (usec_t) start_timestamp;
2266         i->exit_timestamp = (usec_t) exit_timestamp;
2267         i->pid = (pid_t) pid;
2268         i->code = code;
2269         i->status = status;
2270
2271         return 0;
2272 }
2273
2274 typedef struct UnitStatusInfo {
2275         const char *id;
2276         const char *load_state;
2277         const char *active_state;
2278         const char *sub_state;
2279         const char *unit_file_state;
2280
2281         const char *description;
2282         const char *following;
2283
2284         char **documentation;
2285
2286         const char *fragment_path;
2287         const char *source_path;
2288         const char *default_control_group;
2289
2290         const char *load_error;
2291         const char *result;
2292
2293         usec_t inactive_exit_timestamp;
2294         usec_t inactive_exit_timestamp_monotonic;
2295         usec_t active_enter_timestamp;
2296         usec_t active_exit_timestamp;
2297         usec_t inactive_enter_timestamp;
2298
2299         bool need_daemon_reload;
2300
2301         /* Service */
2302         pid_t main_pid;
2303         pid_t control_pid;
2304         const char *status_text;
2305         bool running:1;
2306
2307         usec_t start_timestamp;
2308         usec_t exit_timestamp;
2309
2310         int exit_code, exit_status;
2311
2312         usec_t condition_timestamp;
2313         bool condition_result;
2314
2315         /* Socket */
2316         unsigned n_accepted;
2317         unsigned n_connections;
2318         bool accept;
2319
2320         /* Device */
2321         const char *sysfs_path;
2322
2323         /* Mount, Automount */
2324         const char *where;
2325
2326         /* Swap */
2327         const char *what;
2328
2329         LIST_HEAD(ExecStatusInfo, exec);
2330 } UnitStatusInfo;
2331
2332 static void print_status_info(UnitStatusInfo *i) {
2333         ExecStatusInfo *p;
2334         const char *on, *off, *ss;
2335         usec_t timestamp;
2336         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
2337         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2338         const char *path;
2339         int flags =
2340                 arg_all * OUTPUT_SHOW_ALL |
2341                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2342                 on_tty() * OUTPUT_COLOR |
2343                 !arg_quiet * OUTPUT_WARN_CUTOFF |
2344                 arg_full * OUTPUT_FULL_WIDTH;
2345
2346         assert(i);
2347
2348         /* This shows pretty information about a unit. See
2349          * print_property() for a low-level property printer */
2350
2351         printf("%s", strna(i->id));
2352
2353         if (i->description && !streq_ptr(i->id, i->description))
2354                 printf(" - %s", i->description);
2355
2356         printf("\n");
2357
2358         if (i->following)
2359                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2360
2361         if (streq_ptr(i->load_state, "error")) {
2362                 on = ansi_highlight_red(true);
2363                 off = ansi_highlight_red(false);
2364         } else
2365                 on = off = "";
2366
2367         path = i->source_path ? i->source_path : i->fragment_path;
2368
2369         if (i->load_error)
2370                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2371         else if (path && i->unit_file_state)
2372                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2373         else if (path)
2374                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2375         else
2376                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2377
2378         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2379
2380         if (streq_ptr(i->active_state, "failed")) {
2381                 on = ansi_highlight_red(true);
2382                 off = ansi_highlight_red(false);
2383         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2384                 on = ansi_highlight_green(true);
2385                 off = ansi_highlight_green(false);
2386         } else
2387                 on = off = "";
2388
2389         if (ss)
2390                 printf("\t  Active: %s%s (%s)%s",
2391                        on,
2392                        strna(i->active_state),
2393                        ss,
2394                        off);
2395         else
2396                 printf("\t  Active: %s%s%s",
2397                        on,
2398                        strna(i->active_state),
2399                        off);
2400
2401         if (!isempty(i->result) && !streq(i->result, "success"))
2402                 printf(" (Result: %s)", i->result);
2403
2404         timestamp = (streq_ptr(i->active_state, "active")      ||
2405                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2406                     (streq_ptr(i->active_state, "inactive")    ||
2407                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2408                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2409                                                                   i->active_exit_timestamp;
2410
2411         s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
2412         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2413
2414         if (s1)
2415                 printf(" since %s; %s\n", s2, s1);
2416         else if (s2)
2417                 printf(" since %s\n", s2);
2418         else
2419                 printf("\n");
2420
2421         if (!i->condition_result && i->condition_timestamp > 0) {
2422                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
2423                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2424
2425                 if (s1)
2426                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2427                 else if (s2)
2428                         printf("\t          start condition failed at %s\n", s2);
2429         }
2430
2431         if (i->sysfs_path)
2432                 printf("\t  Device: %s\n", i->sysfs_path);
2433         if (i->where)
2434                 printf("\t   Where: %s\n", i->where);
2435         if (i->what)
2436                 printf("\t    What: %s\n", i->what);
2437
2438         if (!strv_isempty(i->documentation)) {
2439                 char **t;
2440                 bool first = true;
2441
2442                 STRV_FOREACH(t, i->documentation) {
2443                         if (first) {
2444                                 printf("\t    Docs: %s\n", *t);
2445                                 first = false;
2446                         } else
2447                                 printf("\t          %s\n", *t);
2448                 }
2449         }
2450
2451         if (i->accept)
2452                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2453
2454         LIST_FOREACH(exec, p, i->exec) {
2455                 _cleanup_free_ char *t = NULL;
2456                 bool good;
2457
2458                 /* Only show exited processes here */
2459                 if (p->code == 0)
2460                         continue;
2461
2462                 t = strv_join(p->argv, " ");
2463                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2464
2465                 good = is_clean_exit_lsb(p->code, p->status, NULL);
2466                 if (!good) {
2467                         on = ansi_highlight_red(true);
2468                         off = ansi_highlight_red(false);
2469                 } else
2470                         on = off = "";
2471
2472                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2473
2474                 if (p->code == CLD_EXITED) {
2475                         const char *c;
2476
2477                         printf("status=%i", p->status);
2478
2479                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2480                         if (c)
2481                                 printf("/%s", c);
2482
2483                 } else
2484                         printf("signal=%s", signal_to_string(p->status));
2485
2486                 printf(")%s\n", off);
2487
2488                 if (i->main_pid == p->pid &&
2489                     i->start_timestamp == p->start_timestamp &&
2490                     i->exit_timestamp == p->start_timestamp)
2491                         /* Let's not show this twice */
2492                         i->main_pid = 0;
2493
2494                 if (p->pid == i->control_pid)
2495                         i->control_pid = 0;
2496         }
2497
2498         if (i->main_pid > 0 || i->control_pid > 0) {
2499                 printf("\t");
2500
2501                 if (i->main_pid > 0) {
2502                         printf("Main PID: %u", (unsigned) i->main_pid);
2503
2504                         if (i->running) {
2505                                 _cleanup_free_ char *t = NULL;
2506                                 get_process_comm(i->main_pid, &t);
2507                                 if (t)
2508                                         printf(" (%s)", t);
2509                         } else if (i->exit_code > 0) {
2510                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2511
2512                                 if (i->exit_code == CLD_EXITED) {
2513                                         const char *c;
2514
2515                                         printf("status=%i", i->exit_status);
2516
2517                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2518                                         if (c)
2519                                                 printf("/%s", c);
2520
2521                                 } else
2522                                         printf("signal=%s", signal_to_string(i->exit_status));
2523                                 printf(")");
2524                         }
2525                 }
2526
2527                 if (i->main_pid > 0 && i->control_pid > 0)
2528                         printf(";");
2529
2530                 if (i->control_pid > 0) {
2531                         _cleanup_free_ char *t = NULL;
2532
2533                         printf(" Control: %u", (unsigned) i->control_pid);
2534
2535                         get_process_comm(i->control_pid, &t);
2536                         if (t)
2537                                 printf(" (%s)", t);
2538                 }
2539
2540                 printf("\n");
2541         }
2542
2543         if (i->status_text)
2544                 printf("\t  Status: \"%s\"\n", i->status_text);
2545
2546         if (i->default_control_group &&
2547             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
2548                 unsigned c;
2549
2550                 printf("\t  CGroup: %s\n", i->default_control_group);
2551
2552                 if (arg_transport != TRANSPORT_SSH) {
2553                         unsigned k = 0;
2554                         pid_t extra[2];
2555
2556                         c = columns();
2557                         if (c > 18)
2558                                 c -= 18;
2559                         else
2560                                 c = 0;
2561
2562                         if (i->main_pid > 0)
2563                                 extra[k++] = i->main_pid;
2564
2565                         if (i->control_pid > 0)
2566                                 extra[k++] = i->control_pid;
2567
2568                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, extra, k, flags);
2569                 }
2570         }
2571
2572         if (i->id && arg_transport != TRANSPORT_SSH) {
2573                 printf("\n");
2574                 if(arg_scope == UNIT_FILE_SYSTEM)
2575                         show_journal_by_unit(stdout,
2576                                              i->id,
2577                                              arg_output,
2578                                              0,
2579                                              i->inactive_exit_timestamp_monotonic,
2580                                              arg_lines,
2581                                              flags);
2582                 else
2583                         show_journal_by_user_unit(stdout,
2584                                                   i->id,
2585                                                   arg_output,
2586                                                   0,
2587                                                   i->inactive_exit_timestamp_monotonic,
2588                                                   arg_lines,
2589                                                   getuid(),
2590                                                   flags);
2591         }
2592
2593         if (i->need_daemon_reload)
2594                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2595                        ansi_highlight_red(true),
2596                        ansi_highlight_red(false),
2597                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2598 }
2599
2600 static void show_unit_help(UnitStatusInfo *i) {
2601         char **p;
2602
2603         assert(i);
2604
2605         if (!i->documentation) {
2606                 log_info("Documentation for %s not known.", i->id);
2607                 return;
2608         }
2609
2610         STRV_FOREACH(p, i->documentation) {
2611
2612                 if (startswith(*p, "man:")) {
2613                         size_t k;
2614                         char *e = NULL;
2615                         char _cleanup_free_ *page = NULL, *section = NULL;
2616                         const char *args[4] = { "man", NULL, NULL, NULL };
2617                         pid_t pid;
2618
2619                         k = strlen(*p);
2620
2621                         if ((*p)[k-1] == ')')
2622                                 e = strrchr(*p, '(');
2623
2624                         if (e) {
2625                                 page = strndup((*p) + 4, e - *p - 4);
2626                                 section = strndup(e + 1, *p + k - e - 2);
2627                                 if (!page || !section) {
2628                                         log_oom();
2629                                         return;
2630                                 }
2631
2632                                 args[1] = section;
2633                                 args[2] = page;
2634                         } else
2635                                 args[1] = *p + 4;
2636
2637                         pid = fork();
2638                         if (pid < 0) {
2639                                 log_error("Failed to fork: %m");
2640                                 continue;
2641                         }
2642
2643                         if (pid == 0) {
2644                                 /* Child */
2645                                 execvp(args[0], (char**) args);
2646                                 log_error("Failed to execute man: %m");
2647                                 _exit(EXIT_FAILURE);
2648                         }
2649
2650                         wait_for_terminate(pid, NULL);
2651                 } else
2652                         log_info("Can't show: %s", *p);
2653         }
2654 }
2655
2656 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2657
2658         assert(name);
2659         assert(iter);
2660         assert(i);
2661
2662         switch (dbus_message_iter_get_arg_type(iter)) {
2663
2664         case DBUS_TYPE_STRING: {
2665                 const char *s;
2666
2667                 dbus_message_iter_get_basic(iter, &s);
2668
2669                 if (!isempty(s)) {
2670                         if (streq(name, "Id"))
2671                                 i->id = s;
2672                         else if (streq(name, "LoadState"))
2673                                 i->load_state = s;
2674                         else if (streq(name, "ActiveState"))
2675                                 i->active_state = s;
2676                         else if (streq(name, "SubState"))
2677                                 i->sub_state = s;
2678                         else if (streq(name, "Description"))
2679                                 i->description = s;
2680                         else if (streq(name, "FragmentPath"))
2681                                 i->fragment_path = s;
2682                         else if (streq(name, "SourcePath"))
2683                                 i->source_path = s;
2684                         else if (streq(name, "DefaultControlGroup"))
2685                                 i->default_control_group = s;
2686                         else if (streq(name, "StatusText"))
2687                                 i->status_text = s;
2688                         else if (streq(name, "SysFSPath"))
2689                                 i->sysfs_path = s;
2690                         else if (streq(name, "Where"))
2691                                 i->where = s;
2692                         else if (streq(name, "What"))
2693                                 i->what = s;
2694                         else if (streq(name, "Following"))
2695                                 i->following = s;
2696                         else if (streq(name, "UnitFileState"))
2697                                 i->unit_file_state = s;
2698                         else if (streq(name, "Result"))
2699                                 i->result = s;
2700                 }
2701
2702                 break;
2703         }
2704
2705         case DBUS_TYPE_BOOLEAN: {
2706                 dbus_bool_t b;
2707
2708                 dbus_message_iter_get_basic(iter, &b);
2709
2710                 if (streq(name, "Accept"))
2711                         i->accept = b;
2712                 else if (streq(name, "NeedDaemonReload"))
2713                         i->need_daemon_reload = b;
2714                 else if (streq(name, "ConditionResult"))
2715                         i->condition_result = b;
2716
2717                 break;
2718         }
2719
2720         case DBUS_TYPE_UINT32: {
2721                 uint32_t u;
2722
2723                 dbus_message_iter_get_basic(iter, &u);
2724
2725                 if (streq(name, "MainPID")) {
2726                         if (u > 0) {
2727                                 i->main_pid = (pid_t) u;
2728                                 i->running = true;
2729                         }
2730                 } else if (streq(name, "ControlPID"))
2731                         i->control_pid = (pid_t) u;
2732                 else if (streq(name, "ExecMainPID")) {
2733                         if (u > 0)
2734                                 i->main_pid = (pid_t) u;
2735                 } else if (streq(name, "NAccepted"))
2736                         i->n_accepted = u;
2737                 else if (streq(name, "NConnections"))
2738                         i->n_connections = u;
2739
2740                 break;
2741         }
2742
2743         case DBUS_TYPE_INT32: {
2744                 int32_t j;
2745
2746                 dbus_message_iter_get_basic(iter, &j);
2747
2748                 if (streq(name, "ExecMainCode"))
2749                         i->exit_code = (int) j;
2750                 else if (streq(name, "ExecMainStatus"))
2751                         i->exit_status = (int) j;
2752
2753                 break;
2754         }
2755
2756         case DBUS_TYPE_UINT64: {
2757                 uint64_t u;
2758
2759                 dbus_message_iter_get_basic(iter, &u);
2760
2761                 if (streq(name, "ExecMainStartTimestamp"))
2762                         i->start_timestamp = (usec_t) u;
2763                 else if (streq(name, "ExecMainExitTimestamp"))
2764                         i->exit_timestamp = (usec_t) u;
2765                 else if (streq(name, "ActiveEnterTimestamp"))
2766                         i->active_enter_timestamp = (usec_t) u;
2767                 else if (streq(name, "InactiveEnterTimestamp"))
2768                         i->inactive_enter_timestamp = (usec_t) u;
2769                 else if (streq(name, "InactiveExitTimestamp"))
2770                         i->inactive_exit_timestamp = (usec_t) u;
2771                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2772                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2773                 else if (streq(name, "ActiveExitTimestamp"))
2774                         i->active_exit_timestamp = (usec_t) u;
2775                 else if (streq(name, "ConditionTimestamp"))
2776                         i->condition_timestamp = (usec_t) u;
2777
2778                 break;
2779         }
2780
2781         case DBUS_TYPE_ARRAY: {
2782
2783                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2784                     startswith(name, "Exec")) {
2785                         DBusMessageIter sub;
2786
2787                         dbus_message_iter_recurse(iter, &sub);
2788                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2789                                 ExecStatusInfo *info;
2790                                 int r;
2791
2792                                 if (!(info = new0(ExecStatusInfo, 1)))
2793                                         return -ENOMEM;
2794
2795                                 if (!(info->name = strdup(name))) {
2796                                         free(info);
2797                                         return -ENOMEM;
2798                                 }
2799
2800                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2801                                         free(info);
2802                                         return r;
2803                                 }
2804
2805                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2806
2807                                 dbus_message_iter_next(&sub);
2808                         }
2809                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2810                            streq(name, "Documentation")) {
2811
2812                         DBusMessageIter sub;
2813
2814                         dbus_message_iter_recurse(iter, &sub);
2815                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2816                                 const char *s;
2817                                 char **l;
2818
2819                                 dbus_message_iter_get_basic(&sub, &s);
2820
2821                                 l = strv_append(i->documentation, s);
2822                                 if (!l)
2823                                         return -ENOMEM;
2824
2825                                 strv_free(i->documentation);
2826                                 i->documentation = l;
2827
2828                                 dbus_message_iter_next(&sub);
2829                         }
2830                 }
2831
2832                 break;
2833         }
2834
2835         case DBUS_TYPE_STRUCT: {
2836
2837                 if (streq(name, "LoadError")) {
2838                         DBusMessageIter sub;
2839                         const char *n, *message;
2840                         int r;
2841
2842                         dbus_message_iter_recurse(iter, &sub);
2843
2844                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2845                         if (r < 0)
2846                                 return r;
2847
2848                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2849                         if (r < 0)
2850                                 return r;
2851
2852                         if (!isempty(message))
2853                                 i->load_error = message;
2854                 }
2855
2856                 break;
2857         }
2858         }
2859
2860         return 0;
2861 }
2862
2863 static int print_property(const char *name, DBusMessageIter *iter) {
2864         assert(name);
2865         assert(iter);
2866
2867         /* This is a low-level property printer, see
2868          * print_status_info() for the nicer output */
2869
2870         if (arg_property && !strv_find(arg_property, name))
2871                 return 0;
2872
2873         switch (dbus_message_iter_get_arg_type(iter)) {
2874
2875         case DBUS_TYPE_STRUCT: {
2876                 DBusMessageIter sub;
2877                 dbus_message_iter_recurse(iter, &sub);
2878
2879                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2880                         uint32_t u;
2881
2882                         dbus_message_iter_get_basic(&sub, &u);
2883
2884                         if (u)
2885                                 printf("%s=%u\n", name, (unsigned) u);
2886                         else if (arg_all)
2887                                 printf("%s=\n", name);
2888
2889                         return 0;
2890                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2891                         const char *s;
2892
2893                         dbus_message_iter_get_basic(&sub, &s);
2894
2895                         if (arg_all || s[0])
2896                                 printf("%s=%s\n", name, s);
2897
2898                         return 0;
2899                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2900                         const char *a = NULL, *b = NULL;
2901
2902                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2903                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2904
2905                         if (arg_all || !isempty(a) || !isempty(b))
2906                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2907
2908                         return 0;
2909                 }
2910
2911                 break;
2912         }
2913
2914         case DBUS_TYPE_ARRAY:
2915
2916                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2917                         DBusMessageIter sub, sub2;
2918
2919                         dbus_message_iter_recurse(iter, &sub);
2920                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2921                                 const char *path;
2922                                 dbus_bool_t ignore;
2923
2924                                 dbus_message_iter_recurse(&sub, &sub2);
2925
2926                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2927                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2928                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2929
2930                                 dbus_message_iter_next(&sub);
2931                         }
2932
2933                         return 0;
2934
2935                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2936                         DBusMessageIter sub, sub2;
2937
2938                         dbus_message_iter_recurse(iter, &sub);
2939                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2940                                 const char *type, *path;
2941
2942                                 dbus_message_iter_recurse(&sub, &sub2);
2943
2944                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2945                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2946                                         printf("%s=%s\n", type, path);
2947
2948                                 dbus_message_iter_next(&sub);
2949                         }
2950
2951                         return 0;
2952
2953                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2954                         DBusMessageIter sub, sub2;
2955
2956                         dbus_message_iter_recurse(iter, &sub);
2957                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2958                                 const char *base;
2959                                 uint64_t value, next_elapse;
2960
2961                                 dbus_message_iter_recurse(&sub, &sub2);
2962
2963                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2964                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2965                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2966                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2967
2968                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2969                                                base,
2970                                                format_timespan(timespan1, sizeof(timespan1), value),
2971                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2972                                 }
2973
2974                                 dbus_message_iter_next(&sub);
2975                         }
2976
2977                         return 0;
2978
2979                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2980                         DBusMessageIter sub, sub2;
2981
2982                         dbus_message_iter_recurse(iter, &sub);
2983                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2984                                 const char *controller, *attr, *value;
2985
2986                                 dbus_message_iter_recurse(&sub, &sub2);
2987
2988                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2989                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2990                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2991
2992                                         printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2993                                                controller,
2994                                                attr,
2995                                                value);
2996                                 }
2997
2998                                 dbus_message_iter_next(&sub);
2999                         }
3000
3001                         return 0;
3002
3003                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3004                         DBusMessageIter sub;
3005
3006                         dbus_message_iter_recurse(iter, &sub);
3007                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3008                                 ExecStatusInfo info;
3009
3010                                 zero(info);
3011                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
3012                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3013                                         char _cleanup_free_ *t;
3014
3015                                         t = strv_join(info.argv, " ");
3016
3017                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3018                                                name,
3019                                                strna(info.path),
3020                                                strna(t),
3021                                                yes_no(info.ignore),
3022                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3023                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3024                                                (unsigned) info. pid,
3025                                                sigchld_code_to_string(info.code),
3026                                                info.status,
3027                                                info.code == CLD_EXITED ? "" : "/",
3028                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
3029                                 }
3030
3031                                 free(info.path);
3032                                 strv_free(info.argv);
3033
3034                                 dbus_message_iter_next(&sub);
3035                         }
3036
3037                         return 0;
3038                 }
3039
3040                 break;
3041         }
3042
3043         if (generic_print_property(name, iter, arg_all) > 0)
3044                 return 0;
3045
3046         if (arg_all)
3047                 printf("%s=[unprintable]\n", name);
3048
3049         return 0;
3050 }
3051
3052 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
3053         _cleanup_free_ DBusMessage *reply = NULL;
3054         const char *interface = "";
3055         int r;
3056         DBusMessageIter iter, sub, sub2, sub3;
3057         UnitStatusInfo info;
3058         ExecStatusInfo *p;
3059
3060         assert(path);
3061         assert(new_line);
3062
3063         zero(info);
3064
3065         r = bus_method_call_with_reply(
3066                         bus,
3067                         "org.freedesktop.systemd1",
3068                         path,
3069                         "org.freedesktop.DBus.Properties",
3070                         "GetAll",
3071                         &reply,
3072                         NULL,
3073                         DBUS_TYPE_STRING, &interface,
3074                         DBUS_TYPE_INVALID);
3075         if (r < 0)
3076                 return r;
3077
3078         if (!dbus_message_iter_init(reply, &iter) ||
3079             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3080             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
3081                 log_error("Failed to parse reply.");