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