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