chiark / gitweb /
core: drop KillMode parameter from KillUnit() bus call
[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                         log_error("Out of memory");
662                         return -ENOMEM;
663                 }
664
665                 r = unit_file_get_list(arg_scope, arg_root, h);
666                 if (r < 0) {
667                         unit_file_list_free(h);
668                         log_error("Failed to get unit file list: %s", strerror(-r));
669                         return r;
670                 }
671
672                 n_units = hashmap_size(h);
673                 units = new(UnitFileList, n_units);
674                 if (!units) {
675                         unit_file_list_free(h);
676                         log_error("Out of memory");
677                         return -ENOMEM;
678                 }
679
680                 HASHMAP_FOREACH(u, h, i) {
681                         memcpy(units + c++, u, sizeof(UnitFileList));
682                         free(u);
683                 }
684
685                 hashmap_free(h);
686         } else {
687                 assert(bus);
688
689                 m = dbus_message_new_method_call(
690                                 "org.freedesktop.systemd1",
691                                 "/org/freedesktop/systemd1",
692                                 "org.freedesktop.systemd1.Manager",
693                                 "ListUnitFiles");
694                 if (!m) {
695                         log_error("Could not allocate message.");
696                         return -ENOMEM;
697                 }
698
699                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
700                 if (!reply) {
701                         log_error("Failed to issue method call: %s", bus_error_message(&error));
702                         r = -EIO;
703                         goto finish;
704                 }
705
706                 if (!dbus_message_iter_init(reply, &iter) ||
707                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
708                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
709                         log_error("Failed to parse reply.");
710                         r = -EIO;
711                         goto finish;
712                 }
713
714                 dbus_message_iter_recurse(&iter, &sub);
715
716                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
717                         UnitFileList *u;
718                         const char *state;
719
720                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
721                                 log_error("Failed to parse reply.");
722                                 r = -EIO;
723                                 goto finish;
724                         }
725
726                         if (c >= n_units) {
727                                 UnitFileList *w;
728
729                                 n_units = MAX(2*c, 16);
730                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
731
732                                 if (!w) {
733                                         log_error("Failed to allocate unit array.");
734                                         r = -ENOMEM;
735                                         goto finish;
736                                 }
737
738                                 units = w;
739                         }
740
741                         u = units+c;
742
743                         dbus_message_iter_recurse(&sub, &sub2);
744
745                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
746                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
747                                 log_error("Failed to parse reply.");
748                                 r = -EIO;
749                                 goto finish;
750                         }
751
752                         u->state = unit_file_state_from_string(state);
753
754                         dbus_message_iter_next(&sub);
755                         c++;
756                 }
757         }
758
759         if (c > 0) {
760                 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
761                 output_unit_file_list(units, c);
762         }
763
764         r = 0;
765
766 finish:
767         if (m)
768                 dbus_message_unref(m);
769
770         if (reply)
771                 dbus_message_unref(reply);
772
773         free(units);
774
775         dbus_error_free(&error);
776
777         return r;
778 }
779
780 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
781         static const char * const colors[] = {
782                 "Requires",              "[color=\"black\"]",
783                 "RequiresOverridable",   "[color=\"black\"]",
784                 "Requisite",             "[color=\"darkblue\"]",
785                 "RequisiteOverridable",  "[color=\"darkblue\"]",
786                 "Wants",                 "[color=\"darkgrey\"]",
787                 "Conflicts",             "[color=\"red\"]",
788                 "ConflictedBy",          "[color=\"red\"]",
789                 "After",                 "[color=\"green\"]"
790         };
791
792         const char *c = NULL;
793         unsigned i;
794
795         assert(name);
796         assert(prop);
797         assert(iter);
798
799         for (i = 0; i < ELEMENTSOF(colors); i += 2)
800                 if (streq(colors[i], prop)) {
801                         c = colors[i+1];
802                         break;
803                 }
804
805         if (!c)
806                 return 0;
807
808         if (arg_dot != DOT_ALL)
809                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
810                         return 0;
811
812         switch (dbus_message_iter_get_arg_type(iter)) {
813
814         case DBUS_TYPE_ARRAY:
815
816                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
817                         DBusMessageIter sub;
818
819                         dbus_message_iter_recurse(iter, &sub);
820
821                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
822                                 const char *s;
823
824                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
825                                 dbus_message_iter_get_basic(&sub, &s);
826                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
827
828                                 dbus_message_iter_next(&sub);
829                         }
830
831                         return 0;
832                 }
833         }
834
835         return 0;
836 }
837
838 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
839         DBusMessage *m = NULL, *reply = NULL;
840         const char *interface = "org.freedesktop.systemd1.Unit";
841         int r;
842         DBusError error;
843         DBusMessageIter iter, sub, sub2, sub3;
844
845         assert(bus);
846         assert(path);
847
848         dbus_error_init(&error);
849
850         if (!(m = dbus_message_new_method_call(
851                               "org.freedesktop.systemd1",
852                               path,
853                               "org.freedesktop.DBus.Properties",
854                               "GetAll"))) {
855                 log_error("Could not allocate message.");
856                 r = -ENOMEM;
857                 goto finish;
858         }
859
860         if (!dbus_message_append_args(m,
861                                       DBUS_TYPE_STRING, &interface,
862                                       DBUS_TYPE_INVALID)) {
863                 log_error("Could not append arguments to message.");
864                 r = -ENOMEM;
865                 goto finish;
866         }
867
868         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
869                 log_error("Failed to issue method call: %s", bus_error_message(&error));
870                 r = -EIO;
871                 goto finish;
872         }
873
874         if (!dbus_message_iter_init(reply, &iter) ||
875             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
876             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
877                 log_error("Failed to parse reply.");
878                 r = -EIO;
879                 goto finish;
880         }
881
882         dbus_message_iter_recurse(&iter, &sub);
883
884         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
885                 const char *prop;
886
887                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
888                         log_error("Failed to parse reply.");
889                         r = -EIO;
890                         goto finish;
891                 }
892
893                 dbus_message_iter_recurse(&sub, &sub2);
894
895                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
896                         log_error("Failed to parse reply.");
897                         r = -EIO;
898                         goto finish;
899                 }
900
901                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
902                         log_error("Failed to parse reply.");
903                         r = -EIO;
904                         goto finish;
905                 }
906
907                 dbus_message_iter_recurse(&sub2, &sub3);
908
909                 if (dot_one_property(name, prop, &sub3)) {
910                         log_error("Failed to parse reply.");
911                         r = -EIO;
912                         goto finish;
913                 }
914
915                 dbus_message_iter_next(&sub);
916         }
917
918         r = 0;
919
920 finish:
921         if (m)
922                 dbus_message_unref(m);
923
924         if (reply)
925                 dbus_message_unref(reply);
926
927         dbus_error_free(&error);
928
929         return r;
930 }
931
932 static int dot(DBusConnection *bus, char **args) {
933         DBusMessage *m = NULL, *reply = NULL;
934         DBusError error;
935         int r;
936         DBusMessageIter iter, sub, sub2;
937
938         dbus_error_init(&error);
939
940         assert(bus);
941
942         if (!(m = dbus_message_new_method_call(
943                               "org.freedesktop.systemd1",
944                               "/org/freedesktop/systemd1",
945                               "org.freedesktop.systemd1.Manager",
946                               "ListUnits"))) {
947                 log_error("Could not allocate message.");
948                 return -ENOMEM;
949         }
950
951         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
952                 log_error("Failed to issue method call: %s", bus_error_message(&error));
953                 r = -EIO;
954                 goto finish;
955         }
956
957         if (!dbus_message_iter_init(reply, &iter) ||
958             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
959             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
960                 log_error("Failed to parse reply.");
961                 r = -EIO;
962                 goto finish;
963         }
964
965         printf("digraph systemd {\n");
966
967         dbus_message_iter_recurse(&iter, &sub);
968         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
969                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
970
971                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
972                         log_error("Failed to parse reply.");
973                         r = -EIO;
974                         goto finish;
975                 }
976
977                 dbus_message_iter_recurse(&sub, &sub2);
978
979                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
980                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
981                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
982                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
983                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
984                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
985                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
986                         log_error("Failed to parse reply.");
987                         r = -EIO;
988                         goto finish;
989                 }
990
991                 if ((r = dot_one(bus, id, unit_path)) < 0)
992                         goto finish;
993
994                 /* printf("\t\"%s\";\n", id); */
995                 dbus_message_iter_next(&sub);
996         }
997
998         printf("}\n");
999
1000         log_info("   Color legend: black     = Requires\n"
1001                  "                 dark blue = Requisite\n"
1002                  "                 dark grey = Wants\n"
1003                  "                 red       = Conflicts\n"
1004                  "                 green     = After\n");
1005
1006         if (on_tty())
1007                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
1008                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
1009
1010         r = 0;
1011
1012 finish:
1013         if (m)
1014                 dbus_message_unref(m);
1015
1016         if (reply)
1017                 dbus_message_unref(reply);
1018
1019         dbus_error_free(&error);
1020
1021         return r;
1022 }
1023
1024 static int list_jobs(DBusConnection *bus, char **args) {
1025         DBusMessage *m = NULL, *reply = NULL;
1026         DBusError error;
1027         int r;
1028         DBusMessageIter iter, sub, sub2;
1029         unsigned k = 0;
1030
1031         dbus_error_init(&error);
1032
1033         assert(bus);
1034
1035         pager_open_if_enabled();
1036
1037         if (!(m = dbus_message_new_method_call(
1038                               "org.freedesktop.systemd1",
1039                               "/org/freedesktop/systemd1",
1040                               "org.freedesktop.systemd1.Manager",
1041                               "ListJobs"))) {
1042                 log_error("Could not allocate message.");
1043                 return -ENOMEM;
1044         }
1045
1046         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1047                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1048                 r = -EIO;
1049                 goto finish;
1050         }
1051
1052         if (!dbus_message_iter_init(reply, &iter) ||
1053             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1054             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
1055                 log_error("Failed to parse reply.");
1056                 r = -EIO;
1057                 goto finish;
1058         }
1059
1060         dbus_message_iter_recurse(&iter, &sub);
1061
1062         if (on_tty())
1063                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1064
1065         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1066                 const char *name, *type, *state, *job_path, *unit_path;
1067                 uint32_t id;
1068                 char *e;
1069
1070                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1071                         log_error("Failed to parse reply.");
1072                         r = -EIO;
1073                         goto finish;
1074                 }
1075
1076                 dbus_message_iter_recurse(&sub, &sub2);
1077
1078                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1079                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1080                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1081                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1082                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1083                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1084                         log_error("Failed to parse reply.");
1085                         r = -EIO;
1086                         goto finish;
1087                 }
1088
1089                 e = arg_full ? NULL : ellipsize(name, 25, 33);
1090                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1091                 free(e);
1092
1093                 k++;
1094
1095                 dbus_message_iter_next(&sub);
1096         }
1097
1098         if (on_tty())
1099                 printf("\n%u jobs listed.\n", k);
1100
1101         r = 0;
1102
1103 finish:
1104         if (m)
1105                 dbus_message_unref(m);
1106
1107         if (reply)
1108                 dbus_message_unref(reply);
1109
1110         dbus_error_free(&error);
1111
1112         return r;
1113 }
1114
1115 static int load_unit(DBusConnection *bus, char **args) {
1116         DBusMessage *m = NULL;
1117         DBusError error;
1118         int r;
1119         char **name;
1120
1121         dbus_error_init(&error);
1122
1123         assert(bus);
1124         assert(args);
1125
1126         STRV_FOREACH(name, args+1) {
1127                 DBusMessage *reply;
1128                 bool b;
1129                 char *n;
1130
1131                 if (!(m = dbus_message_new_method_call(
1132                                       "org.freedesktop.systemd1",
1133                                       "/org/freedesktop/systemd1",
1134                                       "org.freedesktop.systemd1.Manager",
1135                                       "LoadUnit"))) {
1136                         log_error("Could not allocate message.");
1137                         r = -ENOMEM;
1138                         goto finish;
1139                 }
1140
1141                 n = unit_name_mangle(*name);
1142                 b = dbus_message_append_args(m,
1143                                              DBUS_TYPE_STRING, n ? &n : name,
1144                                              DBUS_TYPE_INVALID);
1145                 free(n);
1146                 if (!b) {
1147                         log_error("Could not append arguments to message.");
1148                         r = -ENOMEM;
1149                         goto finish;
1150                 }
1151
1152                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1153                 if (!reply) {
1154                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1155                         r = -EIO;
1156                         goto finish;
1157                 }
1158
1159                 dbus_message_unref(m);
1160                 dbus_message_unref(reply);
1161
1162                 m = reply = NULL;
1163         }
1164
1165         r = 0;
1166
1167 finish:
1168         if (m)
1169                 dbus_message_unref(m);
1170
1171         dbus_error_free(&error);
1172
1173         return r;
1174 }
1175
1176 static int cancel_job(DBusConnection *bus, char **args) {
1177         DBusMessage *m = NULL, *reply = NULL;
1178         DBusError error;
1179         int r;
1180         char **name;
1181
1182         dbus_error_init(&error);
1183
1184         assert(bus);
1185         assert(args);
1186
1187         if (strv_length(args) <= 1)
1188                 return daemon_reload(bus, args);
1189
1190         STRV_FOREACH(name, args+1) {
1191                 unsigned id;
1192                 const char *path;
1193
1194                 if (!(m = dbus_message_new_method_call(
1195                                       "org.freedesktop.systemd1",
1196                                       "/org/freedesktop/systemd1",
1197                                       "org.freedesktop.systemd1.Manager",
1198                                       "GetJob"))) {
1199                         log_error("Could not allocate message.");
1200                         r = -ENOMEM;
1201                         goto finish;
1202                 }
1203
1204                 if ((r = safe_atou(*name, &id)) < 0) {
1205                         log_error("Failed to parse job id: %s", strerror(-r));
1206                         goto finish;
1207                 }
1208
1209                 assert_cc(sizeof(uint32_t) == sizeof(id));
1210                 if (!dbus_message_append_args(m,
1211                                               DBUS_TYPE_UINT32, &id,
1212                                               DBUS_TYPE_INVALID)) {
1213                         log_error("Could not append arguments to message.");
1214                         r = -ENOMEM;
1215                         goto finish;
1216                 }
1217
1218                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1219                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1220                         r = -EIO;
1221                         goto finish;
1222                 }
1223
1224                 if (!dbus_message_get_args(reply, &error,
1225                                            DBUS_TYPE_OBJECT_PATH, &path,
1226                                            DBUS_TYPE_INVALID)) {
1227                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1228                         r = -EIO;
1229                         goto finish;
1230                 }
1231
1232                 dbus_message_unref(m);
1233                 if (!(m = dbus_message_new_method_call(
1234                                       "org.freedesktop.systemd1",
1235                                       path,
1236                                       "org.freedesktop.systemd1.Job",
1237                                       "Cancel"))) {
1238                         log_error("Could not allocate message.");
1239                         r = -ENOMEM;
1240                         goto finish;
1241                 }
1242
1243                 dbus_message_unref(reply);
1244                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1245                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1246                         r = -EIO;
1247                         goto finish;
1248                 }
1249
1250                 dbus_message_unref(m);
1251                 dbus_message_unref(reply);
1252                 m = reply = NULL;
1253         }
1254
1255         r = 0;
1256
1257 finish:
1258         if (m)
1259                 dbus_message_unref(m);
1260
1261         if (reply)
1262                 dbus_message_unref(reply);
1263
1264         dbus_error_free(&error);
1265
1266         return r;
1267 }
1268
1269 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1270         DBusMessage *m = NULL, *reply = NULL;
1271         dbus_bool_t b = FALSE;
1272         DBusMessageIter iter, sub;
1273         const char
1274                 *interface = "org.freedesktop.systemd1.Unit",
1275                 *property = "NeedDaemonReload",
1276                 *path;
1277         char *n;
1278         bool k;
1279
1280         /* We ignore all errors here, since this is used to show a warning only */
1281
1282         m = dbus_message_new_method_call(
1283                               "org.freedesktop.systemd1",
1284                               "/org/freedesktop/systemd1",
1285                               "org.freedesktop.systemd1.Manager",
1286                               "GetUnit");
1287         if (!m)
1288                 goto finish;
1289
1290         n = unit_name_mangle(unit);
1291         k = dbus_message_append_args(m,
1292                                      DBUS_TYPE_STRING, n ? (const char**) &n : &unit,
1293                                      DBUS_TYPE_INVALID);
1294         free(n);
1295         if (!k)
1296                 goto finish;
1297
1298         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL);
1299         if (!reply)
1300                 goto finish;
1301
1302         if (!dbus_message_get_args(reply, NULL,
1303                                    DBUS_TYPE_OBJECT_PATH, &path,
1304                                    DBUS_TYPE_INVALID))
1305                 goto finish;
1306
1307         dbus_message_unref(m);
1308         m = dbus_message_new_method_call(
1309                         "org.freedesktop.systemd1",
1310                         path,
1311                         "org.freedesktop.DBus.Properties",
1312                         "Get");
1313         if (!m)
1314                 goto finish;
1315
1316         if (!dbus_message_append_args(m,
1317                                       DBUS_TYPE_STRING, &interface,
1318                                       DBUS_TYPE_STRING, &property,
1319                                       DBUS_TYPE_INVALID)) {
1320                 goto finish;
1321         }
1322
1323         dbus_message_unref(reply);
1324         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL);
1325         if (!reply)
1326                 goto finish;
1327
1328         if (!dbus_message_iter_init(reply, &iter) ||
1329             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1330                 goto finish;
1331
1332         dbus_message_iter_recurse(&iter, &sub);
1333
1334         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1335                 goto finish;
1336
1337         dbus_message_iter_get_basic(&sub, &b);
1338
1339 finish:
1340         if (m)
1341                 dbus_message_unref(m);
1342
1343         if (reply)
1344                 dbus_message_unref(reply);
1345
1346         return b;
1347 }
1348
1349 typedef struct WaitData {
1350         Set *set;
1351         char *result;
1352 } WaitData;
1353
1354 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1355         DBusError error;
1356         WaitData *d = data;
1357
1358         assert(connection);
1359         assert(message);
1360         assert(d);
1361
1362         dbus_error_init(&error);
1363
1364         log_debug("Got D-Bus request: %s.%s() on %s",
1365                   dbus_message_get_interface(message),
1366                   dbus_message_get_member(message),
1367                   dbus_message_get_path(message));
1368
1369         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1370                 log_error("Warning! D-Bus connection terminated.");
1371                 dbus_connection_close(connection);
1372
1373         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1374                 uint32_t id;
1375                 const char *path, *result, *unit;
1376                 dbus_bool_t success = true;
1377
1378                 if (dbus_message_get_args(message, &error,
1379                                           DBUS_TYPE_UINT32, &id,
1380                                           DBUS_TYPE_OBJECT_PATH, &path,
1381                                           DBUS_TYPE_STRING, &unit,
1382                                           DBUS_TYPE_STRING, &result,
1383                                           DBUS_TYPE_INVALID)) {
1384                         char *p;
1385
1386                         p = set_remove(d->set, (char*) path);
1387                         free(p);
1388
1389                         if (*result)
1390                                 d->result = strdup(result);
1391
1392                         goto finish;
1393                 }
1394 #ifndef LEGACY
1395                 dbus_error_free(&error);
1396                 if (dbus_message_get_args(message, &error,
1397                                           DBUS_TYPE_UINT32, &id,
1398                                           DBUS_TYPE_OBJECT_PATH, &path,
1399                                           DBUS_TYPE_STRING, &result,
1400                                           DBUS_TYPE_INVALID)) {
1401                         char *p;
1402
1403                         /* Compatibility with older systemd versions <
1404                          * 183 during upgrades. This should be dropped
1405                          * one day. */
1406                         p = set_remove(d->set, (char*) path);
1407                         free(p);
1408
1409                         if (*result)
1410                                 d->result = strdup(result);
1411
1412                         goto finish;
1413                 }
1414
1415                 dbus_error_free(&error);
1416                 if (dbus_message_get_args(message, &error,
1417                                           DBUS_TYPE_UINT32, &id,
1418                                           DBUS_TYPE_OBJECT_PATH, &path,
1419                                           DBUS_TYPE_BOOLEAN, &success,
1420                                           DBUS_TYPE_INVALID)) {
1421                         char *p;
1422
1423                         /* Compatibility with older systemd versions <
1424                          * 19 during upgrades. This should be dropped
1425                          * one day */
1426
1427                         p = set_remove(d->set, (char*) path);
1428                         free(p);
1429
1430                         if (!success)
1431                                 d->result = strdup("failed");
1432
1433                         goto finish;
1434                 }
1435 #endif
1436
1437                 log_error("Failed to parse message: %s", bus_error_message(&error));
1438         }
1439
1440 finish:
1441         dbus_error_free(&error);
1442         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1443 }
1444
1445 static int enable_wait_for_jobs(DBusConnection *bus) {
1446         DBusError error;
1447
1448         assert(bus);
1449
1450         if (private_bus)
1451                 return 0;
1452
1453         dbus_error_init(&error);
1454         dbus_bus_add_match(bus,
1455                            "type='signal',"
1456                            "sender='org.freedesktop.systemd1',"
1457                            "interface='org.freedesktop.systemd1.Manager',"
1458                            "member='JobRemoved',"
1459                            "path='/org/freedesktop/systemd1'",
1460                            &error);
1461
1462         if (dbus_error_is_set(&error)) {
1463                 log_error("Failed to add match: %s", bus_error_message(&error));
1464                 dbus_error_free(&error);
1465                 return -EIO;
1466         }
1467
1468         /* This is slightly dirty, since we don't undo the match registrations. */
1469         return 0;
1470 }
1471
1472 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1473         int r;
1474         WaitData d;
1475
1476         assert(bus);
1477         assert(s);
1478
1479         zero(d);
1480         d.set = s;
1481
1482         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1483                 log_error("Failed to add filter.");
1484                 r = -ENOMEM;
1485                 goto finish;
1486         }
1487
1488         while (!set_isempty(s) &&
1489                dbus_connection_read_write_dispatch(bus, -1))
1490                 ;
1491
1492         if (!arg_quiet && d.result) {
1493                 if (streq(d.result, "timeout"))
1494                         log_error("Job timed out.");
1495                 else if (streq(d.result, "canceled"))
1496                         log_error("Job canceled.");
1497                 else if (streq(d.result, "dependency"))
1498                         log_error("A dependency job failed. See system journal for details.");
1499                 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1500                         log_error("Job failed. See system journal and 'systemctl status' for details.");
1501         }
1502
1503         if (streq_ptr(d.result, "timeout"))
1504                 r = -ETIME;
1505         else if (streq_ptr(d.result, "canceled"))
1506                 r = -ECANCELED;
1507         else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1508                 r = -EIO;
1509         else
1510                 r = 0;
1511
1512         free(d.result);
1513
1514 finish:
1515         /* This is slightly dirty, since we don't undo the filter registration. */
1516
1517         return r;
1518 }
1519
1520 static int check_one_unit(DBusConnection *bus, char *name, bool quiet) {
1521         DBusMessage *m = NULL, *reply = NULL;
1522         DBusError error;
1523         DBusMessageIter iter, sub;
1524         const char
1525                 *interface = "org.freedesktop.systemd1.Unit",
1526                 *property = "ActiveState";
1527         const char *path = NULL;
1528         const char *state;
1529         int r = 3; /* According to LSB: "program is not running" */
1530         char *n;
1531         bool b;
1532
1533         assert(bus);
1534         assert(name);
1535
1536         dbus_error_init(&error);
1537
1538         m = dbus_message_new_method_call(
1539                               "org.freedesktop.systemd1",
1540                               "/org/freedesktop/systemd1",
1541                               "org.freedesktop.systemd1.Manager",
1542                               "GetUnit");
1543         if (!m) {
1544                 log_error("Could not allocate message.");
1545                 r = -ENOMEM;
1546                 goto finish;
1547         }
1548
1549         n = unit_name_mangle(name);
1550         b = dbus_message_append_args(m,
1551                                      DBUS_TYPE_STRING, n ? &n : &name,
1552                                      DBUS_TYPE_INVALID);
1553         free(n);
1554         if (!b) {
1555                 log_error("Could not append arguments to message.");
1556                 r = -ENOMEM;
1557                 goto finish;
1558         }
1559
1560         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1561         if (!reply) {
1562                 /* Hmm, cannot figure out anything about this unit... */
1563                 if (!quiet)
1564                         puts("unknown");
1565
1566                 goto finish;
1567         }
1568
1569         if (!dbus_message_get_args(reply, &error,
1570                                    DBUS_TYPE_OBJECT_PATH, &path,
1571                                    DBUS_TYPE_INVALID)) {
1572                 log_error("Failed to parse reply: %s", bus_error_message(&error));
1573                 r = -EIO;
1574                 goto finish;
1575         }
1576
1577         dbus_message_unref(m);
1578         m = dbus_message_new_method_call(
1579                               "org.freedesktop.systemd1",
1580                               path,
1581                               "org.freedesktop.DBus.Properties",
1582                               "Get");
1583         if (!m) {
1584                 log_error("Could not allocate message.");
1585                 r = -ENOMEM;
1586                 goto finish;
1587         }
1588
1589         if (!dbus_message_append_args(m,
1590                                       DBUS_TYPE_STRING, &interface,
1591                                       DBUS_TYPE_STRING, &property,
1592                                       DBUS_TYPE_INVALID)) {
1593                 log_error("Could not append arguments to message.");
1594                 r = -ENOMEM;
1595                 goto finish;
1596         }
1597
1598         dbus_message_unref(reply);
1599         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1600         if (!reply) {
1601                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1602                 r = -EIO;
1603                 goto finish;
1604         }
1605
1606         if (!dbus_message_iter_init(reply, &iter) ||
1607             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1608                 log_error("Failed to parse reply.");
1609                 r = -EIO;
1610                 goto finish;
1611         }
1612
1613         dbus_message_iter_recurse(&iter, &sub);
1614
1615         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1616                 log_error("Failed to parse reply.");
1617                 r = -EIO;
1618                 goto finish;
1619         }
1620
1621         dbus_message_iter_get_basic(&sub, &state);
1622
1623         if (!quiet)
1624                 puts(state);
1625
1626         if (streq(state, "active") || streq(state, "reloading"))
1627                 r = 0;
1628
1629 finish:
1630         if (m)
1631                 dbus_message_unref(m);
1632
1633         if (reply)
1634                 dbus_message_unref(reply);
1635
1636         dbus_error_free(&error);
1637
1638         return r;
1639 }
1640
1641 static void check_triggering_units(
1642                 DBusConnection *bus,
1643                 const char *unit_name) {
1644
1645         DBusError error;
1646         DBusMessage *m = NULL, *reply = NULL;
1647         DBusMessageIter iter, sub;
1648         char *service_trigger = NULL;
1649         const char *interface = "org.freedesktop.systemd1.Unit",
1650                    *triggered_by_property = "TriggeredBy";
1651
1652         char *unit_path = NULL, *n = NULL;
1653         bool print_warning_label = true;
1654
1655         dbus_error_init(&error);
1656
1657         n = unit_name_mangle(unit_name);
1658         unit_path = unit_dbus_path_from_name(n ? n : unit_name);
1659         free(n);
1660         if (!unit_path) {
1661                 log_error("Could not allocate dbus path.");
1662                 goto finish;
1663         }
1664
1665         m = dbus_message_new_method_call("org.freedesktop.systemd1",
1666                                          unit_path,
1667                                          "org.freedesktop.DBus.Properties",
1668                                          "Get");
1669         if (!m) {
1670                 log_error("Could not allocate message.");
1671                 goto finish;
1672         }
1673
1674         if (!dbus_message_append_args(m,
1675                                       DBUS_TYPE_STRING, &interface,
1676                                       DBUS_TYPE_STRING, &triggered_by_property,
1677                                       DBUS_TYPE_INVALID)) {
1678                 log_error("Could not append arguments to message.");
1679                 goto finish;
1680         }
1681
1682         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1683         if (!reply) {
1684                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1685                 goto finish;
1686         }
1687
1688         if (!dbus_message_iter_init(reply, &iter) ||
1689             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1690                 log_error("Failed to parse reply: %s", bus_error_message(&error));
1691                 goto finish;
1692
1693         }
1694
1695         dbus_message_iter_recurse(&iter, &sub);
1696         dbus_message_iter_recurse(&sub, &iter);
1697         sub = iter;
1698
1699         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1700                 int r;
1701
1702                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1703                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1704                         goto finish;
1705                 }
1706
1707                 dbus_message_iter_get_basic(&sub, &service_trigger);
1708
1709                 r = check_one_unit(bus, service_trigger, true);
1710                 if (r < 0)
1711                         goto finish;
1712                 if (r == 0) {
1713                         if (print_warning_label) {
1714                                 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1715                                 print_warning_label = false;
1716                         }
1717                         log_warning("  %s", service_trigger);
1718                 }
1719
1720                 dbus_message_iter_next(&sub);
1721         }
1722 finish:
1723         if (m)
1724                 dbus_message_unref(m);
1725
1726         if (reply)
1727                 dbus_message_unref(reply);
1728
1729         dbus_error_free(&error);
1730
1731         free(unit_path);
1732 }
1733
1734 static int start_unit_one(
1735                 DBusConnection *bus,
1736                 const char *method,
1737                 const char *name,
1738                 const char *mode,
1739                 DBusError *error,
1740                 Set *s) {
1741
1742         DBusMessage *m = NULL, *reply = NULL;
1743         const char *path;
1744         int r;
1745         char *n;
1746         bool b;
1747
1748         assert(bus);
1749         assert(method);
1750         assert(name);
1751         assert(mode);
1752         assert(error);
1753         assert(arg_no_block || s);
1754
1755         m = dbus_message_new_method_call(
1756                         "org.freedesktop.systemd1",
1757                         "/org/freedesktop/systemd1",
1758                         "org.freedesktop.systemd1.Manager",
1759                         method);
1760         if (!m) {
1761                 log_error("Could not allocate message.");
1762                 r = -ENOMEM;
1763                 goto finish;
1764         }
1765
1766         n = unit_name_mangle(name);
1767         b = dbus_message_append_args(m,
1768                                      DBUS_TYPE_STRING, n ? (const char **) &n : &name,
1769                                      DBUS_TYPE_STRING, &mode,
1770                                      DBUS_TYPE_INVALID);
1771         free(n);
1772         if (!b) {
1773                 log_error("Could not append arguments to message.");
1774                 r = -ENOMEM;
1775                 goto finish;
1776         }
1777
1778         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
1779         if (!reply) {
1780
1781                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1782                         /* There's always a fallback possible for
1783                          * legacy actions. */
1784                         r = -EADDRNOTAVAIL;
1785                         goto finish;
1786                 }
1787
1788                 log_error("Failed to issue method call: %s", bus_error_message(error));
1789                 r = -EIO;
1790                 goto finish;
1791         }
1792
1793         if (!dbus_message_get_args(reply, error,
1794                                    DBUS_TYPE_OBJECT_PATH, &path,
1795                                    DBUS_TYPE_INVALID)) {
1796                 log_error("Failed to parse reply: %s", bus_error_message(error));
1797                 r = -EIO;
1798                 goto finish;
1799         }
1800
1801         if (need_daemon_reload(bus, name))
1802                 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1803                             arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1804
1805         if (!arg_no_block) {
1806                 char *p;
1807
1808                 if (!(p = strdup(path))) {
1809                         log_error("Failed to duplicate path.");
1810                         r = -ENOMEM;
1811                         goto finish;
1812                 }
1813
1814                 if ((r = set_put(s, p)) < 0) {
1815                         free(p);
1816                         log_error("Failed to add path to set.");
1817                         goto finish;
1818                 }
1819         }
1820
1821         /* When stopping a unit warn if it can still be triggered by
1822          * another active unit (socket, path, timer) */
1823         if (!arg_quiet && streq(method, "StopUnit"))
1824                 check_triggering_units(bus, name);
1825
1826         r = 0;
1827
1828 finish:
1829         if (m)
1830                 dbus_message_unref(m);
1831
1832         if (reply)
1833                 dbus_message_unref(reply);
1834
1835         return r;
1836 }
1837
1838 static enum action verb_to_action(const char *verb) {
1839         if (streq(verb, "halt"))
1840                 return ACTION_HALT;
1841         else if (streq(verb, "poweroff"))
1842                 return ACTION_POWEROFF;
1843         else if (streq(verb, "reboot"))
1844                 return ACTION_REBOOT;
1845         else if (streq(verb, "kexec"))
1846                 return ACTION_KEXEC;
1847         else if (streq(verb, "rescue"))
1848                 return ACTION_RESCUE;
1849         else if (streq(verb, "emergency"))
1850                 return ACTION_EMERGENCY;
1851         else if (streq(verb, "default"))
1852                 return ACTION_DEFAULT;
1853         else if (streq(verb, "exit"))
1854                 return ACTION_EXIT;
1855         else if (streq(verb, "suspend"))
1856                 return ACTION_SUSPEND;
1857         else if (streq(verb, "hibernate"))
1858                 return ACTION_HIBERNATE;
1859         else
1860                 return ACTION_INVALID;
1861 }
1862
1863 static int start_unit(DBusConnection *bus, char **args) {
1864
1865         static const char * const table[_ACTION_MAX] = {
1866                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1867                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1868                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1869                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1870                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1871                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1872                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1873                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1874                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1875                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1876                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1877                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1878                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1879                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
1880         };
1881
1882         int r, ret = 0;
1883         const char *method, *mode, *one_name;
1884         Set *s = NULL;
1885         DBusError error;
1886         char **name;
1887
1888         dbus_error_init(&error);
1889
1890         assert(bus);
1891
1892         ask_password_agent_open_if_enabled();
1893
1894         if (arg_action == ACTION_SYSTEMCTL) {
1895                 method =
1896                         streq(args[0], "stop") ||
1897                         streq(args[0], "condstop")              ? "StopUnit" :
1898                         streq(args[0], "reload")                ? "ReloadUnit" :
1899                         streq(args[0], "restart")               ? "RestartUnit" :
1900
1901                         streq(args[0], "try-restart")           ||
1902                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1903
1904                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1905
1906                         streq(args[0], "reload-or-try-restart") ||
1907                         streq(args[0], "condreload") ||
1908
1909                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1910                                                                   "StartUnit";
1911
1912                 mode =
1913                         (streq(args[0], "isolate") ||
1914                          streq(args[0], "rescue")  ||
1915                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1916
1917                 one_name = table[verb_to_action(args[0])];
1918
1919         } else {
1920                 assert(arg_action < ELEMENTSOF(table));
1921                 assert(table[arg_action]);
1922
1923                 method = "StartUnit";
1924
1925                 mode = (arg_action == ACTION_EMERGENCY ||
1926                         arg_action == ACTION_RESCUE ||
1927                         arg_action == ACTION_RUNLEVEL2 ||
1928                         arg_action == ACTION_RUNLEVEL3 ||
1929                         arg_action == ACTION_RUNLEVEL4 ||
1930                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1931
1932                 one_name = table[arg_action];
1933         }
1934
1935         if (!arg_no_block) {
1936                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1937                         log_error("Could not watch jobs: %s", strerror(-ret));
1938                         goto finish;
1939                 }
1940
1941                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1942                         log_error("Failed to allocate set.");
1943                         ret = -ENOMEM;
1944                         goto finish;
1945                 }
1946         }
1947
1948         if (one_name) {
1949                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1950                         goto finish;
1951         } else {
1952                 STRV_FOREACH(name, args+1)
1953                         if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1954                                 ret = translate_bus_error_to_exit_status(r, &error);
1955                                 dbus_error_free(&error);
1956                         }
1957         }
1958
1959         if (!arg_no_block)
1960                 if ((r = wait_for_jobs(bus, s)) < 0) {
1961                         ret = r;
1962                         goto finish;
1963                 }
1964
1965 finish:
1966         if (s)
1967                 set_free_free(s);
1968
1969         dbus_error_free(&error);
1970
1971         return ret;
1972 }
1973
1974 /* Ask systemd-logind, which might grant access to unprivileged users
1975  * through PolicyKit */
1976 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1977 #ifdef HAVE_LOGIND
1978         const char *method;
1979         DBusMessage *m = NULL, *reply = NULL;
1980         DBusError error;
1981         dbus_bool_t interactive = true;
1982         int r;
1983
1984         dbus_error_init(&error);
1985
1986         polkit_agent_open_if_enabled();
1987
1988         switch (a) {
1989
1990         case ACTION_REBOOT:
1991                 method = "Reboot";
1992                 break;
1993
1994         case ACTION_POWEROFF:
1995                 method = "PowerOff";
1996                 break;
1997
1998         case ACTION_SUSPEND:
1999                 method = "Suspend";
2000                 break;
2001
2002         case ACTION_HIBERNATE:
2003                 method = "Hibernate";
2004                 break;
2005
2006         default:
2007                 return -EINVAL;
2008         }
2009
2010         m = dbus_message_new_method_call(
2011                                 "org.freedesktop.login1",
2012                                 "/org/freedesktop/login1",
2013                                 "org.freedesktop.login1.Manager",
2014                                 method);
2015         if (!m) {
2016                 log_error("Could not allocate message.");
2017                 r = -ENOMEM;
2018                 goto finish;
2019         }
2020
2021         if (!dbus_message_append_args(m,
2022                                       DBUS_TYPE_BOOLEAN, &interactive,
2023                                       DBUS_TYPE_INVALID)) {
2024                 log_error("Could not append arguments to message.");
2025                 r = -ENOMEM;
2026                 goto finish;
2027         }
2028
2029         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2030         if (!reply) {
2031                 if (error_is_no_service(&error)) {
2032                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
2033                         r = -ENOENT;
2034                         goto finish;
2035                 }
2036
2037                 if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2038                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
2039                         r = -EACCES;
2040                         goto finish;
2041                 }
2042
2043                 log_info("Failed to issue method call: %s", bus_error_message(&error));
2044                 r = -EIO;
2045                 goto finish;
2046         }
2047
2048         r = 0;
2049
2050 finish:
2051         if (m)
2052                 dbus_message_unref(m);
2053
2054         if (reply)
2055                 dbus_message_unref(reply);
2056
2057         dbus_error_free(&error);
2058
2059         return r;
2060 #else
2061         return -ENOSYS;
2062 #endif
2063 }
2064
2065 static int start_special(DBusConnection *bus, char **args) {
2066         enum action a;
2067         int r;
2068
2069         assert(args);
2070
2071         a = verb_to_action(args[0]);
2072
2073         if (arg_force >= 2 && geteuid() != 0) {
2074                 log_error("Must be root.");
2075                 return -EPERM;
2076         }
2077
2078         if (arg_force >= 2 &&
2079             (a == ACTION_HALT ||
2080              a == ACTION_POWEROFF ||
2081              a == ACTION_REBOOT))
2082                 halt_now(a);
2083
2084         if (arg_force >= 1 &&
2085             (a == ACTION_HALT ||
2086              a == ACTION_POWEROFF ||
2087              a == ACTION_REBOOT ||
2088              a == ACTION_KEXEC ||
2089              a == ACTION_EXIT))
2090                 return daemon_reload(bus, args);
2091
2092         /* first try logind, to allow authentication with polkit */
2093         if (geteuid() != 0 &&
2094             (a == ACTION_POWEROFF ||
2095              a == ACTION_REBOOT ||
2096              a == ACTION_SUSPEND ||
2097              a == ACTION_HIBERNATE)) {
2098                 r = reboot_with_logind(bus, a);
2099                 if (r >= 0)
2100                         return r;
2101         }
2102
2103         r = start_unit(bus, args);
2104         if (r >= 0)
2105                 warn_wall(a);
2106
2107         return r;
2108 }
2109
2110 static int check_unit(DBusConnection *bus, char **args) {
2111         char **name;
2112         int r = 3; /* According to LSB: "program is not running" */
2113
2114         assert(bus);
2115         assert(args);
2116
2117         STRV_FOREACH(name, args+1) {
2118                 int state = check_one_unit(bus, *name, arg_quiet);
2119                 if (state < 0)
2120                         return state;
2121                 if (state == 0)
2122                         r = 0;
2123         }
2124
2125         return r;
2126 }
2127
2128 static int kill_unit(DBusConnection *bus, char **args) {
2129         DBusMessage *m = NULL;
2130         int r = 0;
2131         DBusError error;
2132         char **name;
2133
2134         assert(bus);
2135         assert(args);
2136
2137         dbus_error_init(&error);
2138
2139         if (!arg_kill_who)
2140                 arg_kill_who = "all";
2141
2142         STRV_FOREACH(name, args+1) {
2143                 DBusMessage *reply;
2144                 char *n;
2145                 bool b;
2146
2147                 m = dbus_message_new_method_call(
2148                                 "org.freedesktop.systemd1",
2149                                 "/org/freedesktop/systemd1",
2150                                 "org.freedesktop.systemd1.Manager",
2151                                 "KillUnit");
2152                 if (!m) {
2153                         log_error("Could not allocate message.");
2154                         r = -ENOMEM;
2155                         goto finish;
2156                 }
2157
2158                 n = unit_name_mangle(*name);
2159                 b = dbus_message_append_args(m,
2160                                              DBUS_TYPE_STRING, n ? &n : name,
2161                                              DBUS_TYPE_STRING, &arg_kill_who,
2162                                              DBUS_TYPE_INT32, &arg_signal,
2163                                              DBUS_TYPE_INVALID);
2164                 free(n);
2165                 if (!b) {
2166                         log_error("Could not append arguments to message.");
2167                         r = -ENOMEM;
2168                         goto finish;
2169                 }
2170
2171                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
2172                 if (!reply) {
2173                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2174                         dbus_error_free(&error);
2175                         r = -EIO;
2176                 }
2177
2178                 dbus_message_unref(m);
2179
2180                 if (reply)
2181                         dbus_message_unref(reply);
2182                 m = reply = NULL;
2183         }
2184
2185 finish:
2186         if (m)
2187                 dbus_message_unref(m);
2188
2189         dbus_error_free(&error);
2190
2191         return r;
2192 }
2193
2194 typedef struct ExecStatusInfo {
2195         char *name;
2196
2197         char *path;
2198         char **argv;
2199
2200         bool ignore;
2201
2202         usec_t start_timestamp;
2203         usec_t exit_timestamp;
2204         pid_t pid;
2205         int code;
2206         int status;
2207
2208         LIST_FIELDS(struct ExecStatusInfo, exec);
2209 } ExecStatusInfo;
2210
2211 static void exec_status_info_free(ExecStatusInfo *i) {
2212         assert(i);
2213
2214         free(i->name);
2215         free(i->path);
2216         strv_free(i->argv);
2217         free(i);
2218 }
2219
2220 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2221         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2222         DBusMessageIter sub2, sub3;
2223         const char*path;
2224         unsigned n;
2225         uint32_t pid;
2226         int32_t code, status;
2227         dbus_bool_t ignore;
2228
2229         assert(i);
2230         assert(i);
2231
2232         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2233                 return -EIO;
2234
2235         dbus_message_iter_recurse(sub, &sub2);
2236
2237         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2238                 return -EIO;
2239
2240         if (!(i->path = strdup(path)))
2241                 return -ENOMEM;
2242
2243         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2244             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2245                 return -EIO;
2246
2247         n = 0;
2248         dbus_message_iter_recurse(&sub2, &sub3);
2249         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2250                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2251                 dbus_message_iter_next(&sub3);
2252                 n++;
2253         }
2254
2255
2256         if (!(i->argv = new0(char*, n+1)))
2257                 return -ENOMEM;
2258
2259         n = 0;
2260         dbus_message_iter_recurse(&sub2, &sub3);
2261         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2262                 const char *s;
2263
2264                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2265                 dbus_message_iter_get_basic(&sub3, &s);
2266                 dbus_message_iter_next(&sub3);
2267
2268                 if (!(i->argv[n++] = strdup(s)))
2269                         return -ENOMEM;
2270         }
2271
2272         if (!dbus_message_iter_next(&sub2) ||
2273             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2274             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2275             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2276             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2277             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2278             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2279             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2280             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2281                 return -EIO;
2282
2283         i->ignore = ignore;
2284         i->start_timestamp = (usec_t) start_timestamp;
2285         i->exit_timestamp = (usec_t) exit_timestamp;
2286         i->pid = (pid_t) pid;
2287         i->code = code;
2288         i->status = status;
2289
2290         return 0;
2291 }
2292
2293 typedef struct UnitStatusInfo {
2294         const char *id;
2295         const char *load_state;
2296         const char *active_state;
2297         const char *sub_state;
2298         const char *unit_file_state;
2299
2300         const char *description;
2301         const char *following;
2302
2303         char **documentation;
2304
2305         const char *fragment_path;
2306         const char *source_path;
2307         const char *default_control_group;
2308
2309         const char *load_error;
2310         const char *result;
2311
2312         usec_t inactive_exit_timestamp;
2313         usec_t inactive_exit_timestamp_monotonic;
2314         usec_t active_enter_timestamp;
2315         usec_t active_exit_timestamp;
2316         usec_t inactive_enter_timestamp;
2317
2318         bool need_daemon_reload;
2319
2320         /* Service */
2321         pid_t main_pid;
2322         pid_t control_pid;
2323         const char *status_text;
2324         bool running:1;
2325
2326         usec_t start_timestamp;
2327         usec_t exit_timestamp;
2328
2329         int exit_code, exit_status;
2330
2331         usec_t condition_timestamp;
2332         bool condition_result;
2333
2334         /* Socket */
2335         unsigned n_accepted;
2336         unsigned n_connections;
2337         bool accept;
2338
2339         /* Device */
2340         const char *sysfs_path;
2341
2342         /* Mount, Automount */
2343         const char *where;
2344
2345         /* Swap */
2346         const char *what;
2347
2348         LIST_HEAD(ExecStatusInfo, exec);
2349 } UnitStatusInfo;
2350
2351 static void print_status_info(UnitStatusInfo *i) {
2352         ExecStatusInfo *p;
2353         const char *on, *off, *ss;
2354         usec_t timestamp;
2355         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2356         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2357         const char *path;
2358
2359         assert(i);
2360
2361         /* This shows pretty information about a unit. See
2362          * print_property() for a low-level property printer */
2363
2364         printf("%s", strna(i->id));
2365
2366         if (i->description && !streq_ptr(i->id, i->description))
2367                 printf(" - %s", i->description);
2368
2369         printf("\n");
2370
2371         if (i->following)
2372                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2373
2374         if (streq_ptr(i->load_state, "error")) {
2375                 on = ansi_highlight_red(true);
2376                 off = ansi_highlight_red(false);
2377         } else
2378                 on = off = "";
2379
2380         path = i->source_path ? i->source_path : i->fragment_path;
2381
2382         if (i->load_error)
2383                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2384         else if (path && i->unit_file_state)
2385                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2386         else if (path)
2387                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2388         else
2389                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2390
2391         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2392
2393         if (streq_ptr(i->active_state, "failed")) {
2394                 on = ansi_highlight_red(true);
2395                 off = ansi_highlight_red(false);
2396         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2397                 on = ansi_highlight_green(true);
2398                 off = ansi_highlight_green(false);
2399         } else
2400                 on = off = "";
2401
2402         if (ss)
2403                 printf("\t  Active: %s%s (%s)%s",
2404                        on,
2405                        strna(i->active_state),
2406                        ss,
2407                        off);
2408         else
2409                 printf("\t  Active: %s%s%s",
2410                        on,
2411                        strna(i->active_state),
2412                        off);
2413
2414         if (!isempty(i->result) && !streq(i->result, "success"))
2415                 printf(" (Result: %s)", i->result);
2416
2417         timestamp = (streq_ptr(i->active_state, "active")      ||
2418                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2419                     (streq_ptr(i->active_state, "inactive")    ||
2420                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2421                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2422                                                                   i->active_exit_timestamp;
2423
2424         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2425         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2426
2427         if (s1)
2428                 printf(" since %s; %s\n", s2, s1);
2429         else if (s2)
2430                 printf(" since %s\n", s2);
2431         else
2432                 printf("\n");
2433
2434         if (!i->condition_result && i->condition_timestamp > 0) {
2435                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2436                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2437
2438                 if (s1)
2439                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2440                 else if (s2)
2441                         printf("\t          start condition failed at %s\n", s2);
2442         }
2443
2444         if (i->sysfs_path)
2445                 printf("\t  Device: %s\n", i->sysfs_path);
2446         if (i->where)
2447                 printf("\t   Where: %s\n", i->where);
2448         if (i->what)
2449                 printf("\t    What: %s\n", i->what);
2450
2451         if (!strv_isempty(i->documentation)) {
2452                 char **t;
2453                 bool first = true;
2454
2455                 STRV_FOREACH(t, i->documentation) {
2456                         if (first) {
2457                                 printf("\t    Docs: %s\n", *t);
2458                                 first = false;
2459                         } else
2460                                 printf("\t          %s\n", *t);
2461                 }
2462         }
2463
2464         if (i->accept)
2465                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2466
2467         LIST_FOREACH(exec, p, i->exec) {
2468                 char *t;
2469                 bool good;
2470
2471                 /* Only show exited processes here */
2472                 if (p->code == 0)
2473                         continue;
2474
2475                 t = strv_join(p->argv, " ");
2476                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2477                 free(t);
2478
2479                 good = is_clean_exit_lsb(p->code, p->status);
2480                 if (!good) {
2481                         on = ansi_highlight_red(true);
2482                         off = ansi_highlight_red(false);
2483                 } else
2484                         on = off = "";
2485
2486                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2487
2488                 if (p->code == CLD_EXITED) {
2489                         const char *c;
2490
2491                         printf("status=%i", p->status);
2492
2493                         c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2494                         if (c)
2495                                 printf("/%s", c);
2496
2497                 } else
2498                         printf("signal=%s", signal_to_string(p->status));
2499
2500                 printf(")%s\n", off);
2501
2502                 if (i->main_pid == p->pid &&
2503                     i->start_timestamp == p->start_timestamp &&
2504                     i->exit_timestamp == p->start_timestamp)
2505                         /* Let's not show this twice */
2506                         i->main_pid = 0;
2507
2508                 if (p->pid == i->control_pid)
2509                         i->control_pid = 0;
2510         }
2511
2512         if (i->main_pid > 0 || i->control_pid > 0) {
2513                 printf("\t");
2514
2515                 if (i->main_pid > 0) {
2516                         printf("Main PID: %u", (unsigned) i->main_pid);
2517
2518                         if (i->running) {
2519                                 char *t = NULL;
2520                                 get_process_comm(i->main_pid, &t);
2521                                 if (t) {
2522                                         printf(" (%s)", t);
2523                                         free(t);
2524                                 }
2525                         } else if (i->exit_code > 0) {
2526                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2527
2528                                 if (i->exit_code == CLD_EXITED) {
2529                                         const char *c;
2530
2531                                         printf("status=%i", i->exit_status);
2532
2533                                         c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2534                                         if (c)
2535                                                 printf("/%s", c);
2536
2537                                 } else
2538                                         printf("signal=%s", signal_to_string(i->exit_status));
2539                                 printf(")");
2540                         }
2541                 }
2542
2543                 if (i->main_pid > 0 && i->control_pid > 0)
2544                         printf(";");
2545
2546                 if (i->control_pid > 0) {
2547                         char *t = NULL;
2548
2549                         printf(" Control: %u", (unsigned) i->control_pid);
2550
2551                         get_process_comm(i->control_pid, &t);
2552                         if (t) {
2553                                 printf(" (%s)", t);
2554                                 free(t);
2555                         }
2556                 }
2557
2558                 printf("\n");
2559         }
2560
2561         if (i->status_text)
2562                 printf("\t  Status: \"%s\"\n", i->status_text);
2563
2564         if (i->default_control_group) {
2565                 unsigned c;
2566
2567                 printf("\t  CGroup: %s\n", i->default_control_group);
2568
2569                 if (arg_transport != TRANSPORT_SSH) {
2570                         unsigned k = 0;
2571                         pid_t extra[2];
2572
2573                         c = columns();
2574                         if (c > 18)
2575                                 c -= 18;
2576                         else
2577                                 c = 0;
2578
2579                         if (i->main_pid > 0)
2580                                 extra[k++] = i->main_pid;
2581
2582                         if (i->control_pid > 0)
2583                                 extra[k++] = i->control_pid;
2584
2585                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2586                 }
2587         }
2588
2589         if (i->id && arg_transport != TRANSPORT_SSH) {
2590                 int flags = (arg_lines*OUTPUT_SHOW_ALL |
2591                              arg_follow*OUTPUT_FOLLOW |
2592                              !arg_quiet*OUTPUT_WARN_CUTOFF);
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_error("Out of memory.");
2634                                         return;
2635                                 }
2636
2637                                 section = strndup(e + 1, *p + k - e - 2);
2638                                 if (!section) {
2639                                         free(page);
2640                                         log_error("Out of memory");
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;