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