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