chiark / gitweb /
systemctl: introduce "systemctl man" to show man page for unit
[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 void man_status_info(UnitStatusInfo *i) {
2462         char **p;
2463
2464         assert(i);
2465
2466         if (!i->documentation) {
2467                 log_info("Documentation for %s not known.", i->id);
2468                 return;
2469         }
2470
2471         STRV_FOREACH(p, i->documentation) {
2472
2473                 if (startswith(*p, "man:")) {
2474                         size_t k;
2475                         char *e = NULL;
2476                         char *page = NULL, *section = NULL;
2477                         const char *args[4] = { "man", NULL, NULL, NULL };
2478                         pid_t pid;
2479
2480                         k = strlen(*p);
2481
2482                         if ((*p)[k-1] == ')')
2483                                 e = strrchr(*p, '(');
2484
2485                         if (e) {
2486                                 page = strndup((*p) + 4, e - *p - 4);
2487                                 if (!page) {
2488                                         log_error("Out of memory.");
2489                                         return;
2490                                 }
2491
2492                                 section = strndup(e + 1, *p + k - e - 2);
2493                                 if (!section) {
2494                                         free(page);
2495                                         log_error("Out of memory");
2496                                         return;
2497                                 }
2498
2499                                 args[1] = section;
2500                                 args[2] = page;
2501                         } else
2502                                 args[1] = *p + 4;
2503
2504                         pid = fork();
2505                         if (pid < 0) {
2506                                 log_error("Failed to fork: %m");
2507                                 free(page);
2508                                 free(section);
2509                                 continue;
2510                         }
2511
2512                         if (pid == 0) {
2513                                 /* Child */
2514                                 execvp(args[0], (char**) args);
2515                                 log_error("Failed to execute man: %m");
2516                                 _exit(EXIT_FAILURE);
2517                         }
2518
2519                         free(page);
2520                         free(section);
2521
2522                         wait_for_terminate(pid, NULL);
2523                 } else
2524                         log_info("Can't show %s.", *p);
2525         }
2526 }
2527
2528 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2529
2530         assert(name);
2531         assert(iter);
2532         assert(i);
2533
2534         switch (dbus_message_iter_get_arg_type(iter)) {
2535
2536         case DBUS_TYPE_STRING: {
2537                 const char *s;
2538
2539                 dbus_message_iter_get_basic(iter, &s);
2540
2541                 if (!isempty(s)) {
2542                         if (streq(name, "Id"))
2543                                 i->id = s;
2544                         else if (streq(name, "LoadState"))
2545                                 i->load_state = s;
2546                         else if (streq(name, "ActiveState"))
2547                                 i->active_state = s;
2548                         else if (streq(name, "SubState"))
2549                                 i->sub_state = s;
2550                         else if (streq(name, "Description"))
2551                                 i->description = s;
2552                         else if (streq(name, "FragmentPath"))
2553                                 i->fragment_path = s;
2554                         else if (streq(name, "SourcePath"))
2555                                 i->source_path = s;
2556                         else if (streq(name, "DefaultControlGroup"))
2557                                 i->default_control_group = s;
2558                         else if (streq(name, "StatusText"))
2559                                 i->status_text = s;
2560                         else if (streq(name, "SysFSPath"))
2561                                 i->sysfs_path = s;
2562                         else if (streq(name, "Where"))
2563                                 i->where = s;
2564                         else if (streq(name, "What"))
2565                                 i->what = s;
2566                         else if (streq(name, "Following"))
2567                                 i->following = s;
2568                         else if (streq(name, "UnitFileState"))
2569                                 i->unit_file_state = s;
2570                         else if (streq(name, "Result"))
2571                                 i->result = s;
2572                 }
2573
2574                 break;
2575         }
2576
2577         case DBUS_TYPE_BOOLEAN: {
2578                 dbus_bool_t b;
2579
2580                 dbus_message_iter_get_basic(iter, &b);
2581
2582                 if (streq(name, "Accept"))
2583                         i->accept = b;
2584                 else if (streq(name, "NeedDaemonReload"))
2585                         i->need_daemon_reload = b;
2586                 else if (streq(name, "ConditionResult"))
2587                         i->condition_result = b;
2588
2589                 break;
2590         }
2591
2592         case DBUS_TYPE_UINT32: {
2593                 uint32_t u;
2594
2595                 dbus_message_iter_get_basic(iter, &u);
2596
2597                 if (streq(name, "MainPID")) {
2598                         if (u > 0) {
2599                                 i->main_pid = (pid_t) u;
2600                                 i->running = true;
2601                         }
2602                 } else if (streq(name, "ControlPID"))
2603                         i->control_pid = (pid_t) u;
2604                 else if (streq(name, "ExecMainPID")) {
2605                         if (u > 0)
2606                                 i->main_pid = (pid_t) u;
2607                 } else if (streq(name, "NAccepted"))
2608                         i->n_accepted = u;
2609                 else if (streq(name, "NConnections"))
2610                         i->n_connections = u;
2611
2612                 break;
2613         }
2614
2615         case DBUS_TYPE_INT32: {
2616                 int32_t j;
2617
2618                 dbus_message_iter_get_basic(iter, &j);
2619
2620                 if (streq(name, "ExecMainCode"))
2621                         i->exit_code = (int) j;
2622                 else if (streq(name, "ExecMainStatus"))
2623                         i->exit_status = (int) j;
2624
2625                 break;
2626         }
2627
2628         case DBUS_TYPE_UINT64: {
2629                 uint64_t u;
2630
2631                 dbus_message_iter_get_basic(iter, &u);
2632
2633                 if (streq(name, "ExecMainStartTimestamp"))
2634                         i->start_timestamp = (usec_t) u;
2635                 else if (streq(name, "ExecMainExitTimestamp"))
2636                         i->exit_timestamp = (usec_t) u;
2637                 else if (streq(name, "ActiveEnterTimestamp"))
2638                         i->active_enter_timestamp = (usec_t) u;
2639                 else if (streq(name, "InactiveEnterTimestamp"))
2640                         i->inactive_enter_timestamp = (usec_t) u;
2641                 else if (streq(name, "InactiveExitTimestamp"))
2642                         i->inactive_exit_timestamp = (usec_t) u;
2643                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2644                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2645                 else if (streq(name, "ActiveExitTimestamp"))
2646                         i->active_exit_timestamp = (usec_t) u;
2647                 else if (streq(name, "ConditionTimestamp"))
2648                         i->condition_timestamp = (usec_t) u;
2649
2650                 break;
2651         }
2652
2653         case DBUS_TYPE_ARRAY: {
2654
2655                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2656                     startswith(name, "Exec")) {
2657                         DBusMessageIter sub;
2658
2659                         dbus_message_iter_recurse(iter, &sub);
2660                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2661                                 ExecStatusInfo *info;
2662                                 int r;
2663
2664                                 if (!(info = new0(ExecStatusInfo, 1)))
2665                                         return -ENOMEM;
2666
2667                                 if (!(info->name = strdup(name))) {
2668                                         free(info);
2669                                         return -ENOMEM;
2670                                 }
2671
2672                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2673                                         free(info);
2674                                         return r;
2675                                 }
2676
2677                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2678
2679                                 dbus_message_iter_next(&sub);
2680                         }
2681                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2682                            streq(name, "Documentation")) {
2683
2684                         DBusMessageIter sub;
2685
2686                         dbus_message_iter_recurse(iter, &sub);
2687                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2688                                 const char *s;
2689                                 char **l;
2690
2691                                 dbus_message_iter_get_basic(&sub, &s);
2692
2693                                 l = strv_append(i->documentation, s);
2694                                 if (!l)
2695                                         return -ENOMEM;
2696
2697                                 strv_free(i->documentation);
2698                                 i->documentation = l;
2699
2700                                 dbus_message_iter_next(&sub);
2701                         }
2702                 }
2703
2704                 break;
2705         }
2706
2707         case DBUS_TYPE_STRUCT: {
2708
2709                 if (streq(name, "LoadError")) {
2710                         DBusMessageIter sub;
2711                         const char *n, *message;
2712                         int r;
2713
2714                         dbus_message_iter_recurse(iter, &sub);
2715
2716                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2717                         if (r < 0)
2718                                 return r;
2719
2720                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2721                         if (r < 0)
2722                                 return r;
2723
2724                         if (!isempty(message))
2725                                 i->load_error = message;
2726                 }
2727
2728                 break;
2729         }
2730         }
2731
2732         return 0;
2733 }
2734
2735 static int print_property(const char *name, DBusMessageIter *iter) {
2736         assert(name);
2737         assert(iter);
2738
2739         /* This is a low-level property printer, see
2740          * print_status_info() for the nicer output */
2741
2742         if (arg_property && !strv_find(arg_property, name))
2743                 return 0;
2744
2745         switch (dbus_message_iter_get_arg_type(iter)) {
2746
2747         case DBUS_TYPE_STRUCT: {
2748                 DBusMessageIter sub;
2749                 dbus_message_iter_recurse(iter, &sub);
2750
2751                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2752                         uint32_t u;
2753
2754                         dbus_message_iter_get_basic(&sub, &u);
2755
2756                         if (u)
2757                                 printf("%s=%u\n", name, (unsigned) u);
2758                         else if (arg_all)
2759                                 printf("%s=\n", name);
2760
2761                         return 0;
2762                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2763                         const char *s;
2764
2765                         dbus_message_iter_get_basic(&sub, &s);
2766
2767                         if (arg_all || s[0])
2768                                 printf("%s=%s\n", name, s);
2769
2770                         return 0;
2771                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2772                         const char *a = NULL, *b = NULL;
2773
2774                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2775                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2776
2777                         if (arg_all || !isempty(a) || !isempty(b))
2778                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2779
2780                         return 0;
2781                 }
2782
2783                 break;
2784         }
2785
2786         case DBUS_TYPE_ARRAY:
2787
2788                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2789                         DBusMessageIter sub, sub2;
2790
2791                         dbus_message_iter_recurse(iter, &sub);
2792                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2793                                 const char *path;
2794                                 dbus_bool_t ignore;
2795
2796                                 dbus_message_iter_recurse(&sub, &sub2);
2797
2798                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2799                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2800                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2801
2802                                 dbus_message_iter_next(&sub);
2803                         }
2804
2805                         return 0;
2806
2807                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2808                         DBusMessageIter sub, sub2;
2809
2810                         dbus_message_iter_recurse(iter, &sub);
2811                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2812                                 const char *type, *path;
2813
2814                                 dbus_message_iter_recurse(&sub, &sub2);
2815
2816                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2817                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2818                                         printf("%s=%s\n", type, path);
2819
2820                                 dbus_message_iter_next(&sub);
2821                         }
2822
2823                         return 0;
2824
2825                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2826                         DBusMessageIter sub, sub2;
2827
2828                         dbus_message_iter_recurse(iter, &sub);
2829                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2830                                 const char *base;
2831                                 uint64_t value, next_elapse;
2832
2833                                 dbus_message_iter_recurse(&sub, &sub2);
2834
2835                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2836                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2837                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2838                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2839
2840                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2841                                                base,
2842                                                format_timespan(timespan1, sizeof(timespan1), value),
2843                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2844                                 }
2845
2846                                 dbus_message_iter_next(&sub);
2847                         }
2848
2849                         return 0;
2850
2851                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2852                         DBusMessageIter sub, sub2;
2853
2854                         dbus_message_iter_recurse(iter, &sub);
2855                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2856                                 const char *controller, *attr, *value;
2857
2858                                 dbus_message_iter_recurse(&sub, &sub2);
2859
2860                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2861                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2862                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2863
2864                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2865                                                controller,
2866                                                attr,
2867                                                value);
2868                                 }
2869
2870                                 dbus_message_iter_next(&sub);
2871                         }
2872
2873                         return 0;
2874
2875                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2876                         DBusMessageIter sub;
2877
2878                         dbus_message_iter_recurse(iter, &sub);
2879                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2880                                 ExecStatusInfo info;
2881
2882                                 zero(info);
2883                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2884                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2885                                         char *t;
2886
2887                                         t = strv_join(info.argv, " ");
2888
2889                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2890                                                name,
2891                                                strna(info.path),
2892                                                strna(t),
2893                                                yes_no(info.ignore),
2894                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2895                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2896                                                (unsigned) info. pid,
2897                                                sigchld_code_to_string(info.code),
2898                                                info.status,
2899                                                info.code == CLD_EXITED ? "" : "/",
2900                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2901
2902                                         free(t);
2903                                 }
2904
2905                                 free(info.path);
2906                                 strv_free(info.argv);
2907
2908                                 dbus_message_iter_next(&sub);
2909                         }
2910
2911                         return 0;
2912                 }
2913
2914                 break;
2915         }
2916
2917         if (generic_print_property(name, iter, arg_all) > 0)
2918                 return 0;
2919
2920         if (arg_all)
2921                 printf("%s=[unprintable]\n", name);
2922
2923         return 0;
2924 }
2925
2926 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2927         DBusMessage *m = NULL, *reply = NULL;
2928         const char *interface = "";
2929         int r;
2930         DBusError error;
2931         DBusMessageIter iter, sub, sub2, sub3;
2932         UnitStatusInfo info;
2933         ExecStatusInfo *p;
2934
2935         assert(bus);
2936         assert(path);
2937         assert(new_line);
2938
2939         zero(info);
2940         dbus_error_init(&error);
2941
2942         if (!(m = dbus_message_new_method_call(
2943                               "org.freedesktop.systemd1",
2944                               path,
2945                               "org.freedesktop.DBus.Properties",
2946                               "GetAll"))) {
2947                 log_error("Could not allocate message.");
2948                 r = -ENOMEM;
2949                 goto finish;
2950         }
2951
2952         if (!dbus_message_append_args(m,
2953                                       DBUS_TYPE_STRING, &interface,
2954                                       DBUS_TYPE_INVALID)) {
2955                 log_error("Could not append arguments to message.");
2956                 r = -ENOMEM;
2957                 goto finish;
2958         }
2959
2960         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2961                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2962                 r = -EIO;
2963                 goto finish;
2964         }
2965
2966         if (!dbus_message_iter_init(reply, &iter) ||
2967             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2968             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2969                 log_error("Failed to parse reply.");
2970                 r = -EIO;
2971                 goto finish;
2972         }
2973
2974         dbus_message_iter_recurse(&iter, &sub);
2975
2976         if (*new_line)
2977                 printf("\n");
2978
2979         *new_line = true;
2980
2981         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2982                 const char *name;
2983
2984                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2985                         log_error("Failed to parse reply.");
2986                         r = -EIO;
2987                         goto finish;
2988                 }
2989
2990                 dbus_message_iter_recurse(&sub, &sub2);
2991
2992                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2993                         log_error("Failed to parse reply.");
2994                         r = -EIO;
2995                         goto finish;
2996                 }
2997
2998                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2999                         log_error("Failed to parse reply.");
3000                         r = -EIO;
3001                         goto finish;
3002                 }
3003
3004                 dbus_message_iter_recurse(&sub2, &sub3);
3005
3006                 if (show_properties)
3007                         r = print_property(name, &sub3);
3008                 else
3009                         r = status_property(name, &sub3, &info);
3010
3011                 if (r < 0) {
3012                         log_error("Failed to parse reply.");
3013                         r = -EIO;
3014                         goto finish;
3015                 }
3016
3017                 dbus_message_iter_next(&sub);
3018         }
3019
3020         r = 0;
3021
3022         if (!show_properties) {
3023                 if (streq(verb, "man"))
3024                         man_status_info(&info);
3025                 else
3026                         print_status_info(&info);
3027         }
3028
3029         strv_free(info.documentation);
3030
3031         if (!streq_ptr(info.active_state, "active") &&
3032             !streq_ptr(info.active_state, "reloading") &&
3033             streq(verb, "status"))
3034                 /* According to LSB: "program not running" */
3035                 r = 3;
3036
3037         while ((p = info.exec)) {
3038                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3039                 exec_status_info_free(p);
3040         }
3041
3042 finish:
3043         if (m)
3044                 dbus_message_unref(m);
3045
3046         if (reply)
3047                 dbus_message_unref(reply);
3048
3049         dbus_error_free(&error);
3050
3051         return r;
3052 }
3053
3054 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
3055         DBusMessage *m = NULL, *reply = NULL;
3056         const char *path = NULL;
3057         DBusError error;
3058         int r;
3059
3060         dbus_error_init(&error);
3061
3062         m = dbus_message_new_method_call(
3063                               "org.freedesktop.systemd1",
3064                               "/org/freedesktop/systemd1",
3065                               "org.freedesktop.systemd1.Manager",
3066                               "GetUnitByPID");
3067         if (!m) {
3068                 log_error("Could not allocate message.");
3069                 r = -ENOMEM;
3070                 goto finish;
3071         }
3072
3073         if (!dbus_message_append_args(m,
3074                                       DBUS_TYPE_UINT32, &pid,
3075                                       DBUS_TYPE_INVALID)) {
3076                 log_error("Could not append arguments to message.");
3077                 r = -ENOMEM;
3078                 goto finish;
3079         }
3080