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