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