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