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