chiark / gitweb /
main: only fall back to /bin/sh in case /sbin/init does not exist
[elogind.git] / src / systemctl / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <stddef.h>
35 #include <sys/prctl.h>
36 #include <dbus/dbus.h>
37
38 #include <systemd/sd-daemon.h>
39 #include <systemd/sd-shutdown.h>
40
41 #include "log.h"
42 #include "util.h"
43 #include "macro.h"
44 #include "set.h"
45 #include "utmp-wtmp.h"
46 #include "special.h"
47 #include "initreq.h"
48 #include "path-util.h"
49 #include "strv.h"
50 #include "dbus-common.h"
51 #include "cgroup-show.h"
52 #include "cgroup-util.h"
53 #include "list.h"
54 #include "path-lookup.h"
55 #include "conf-parser.h"
56 #include "exit-status.h"
57 #include "bus-errors.h"
58 #include "build.h"
59 #include "unit-name.h"
60 #include "pager.h"
61 #include "spawn-ask-password-agent.h"
62 #include "spawn-polkit-agent.h"
63 #include "install.h"
64 #include "logs-show.h"
65 #include "path-util.h"
66
67 static const char *arg_type = NULL;
68 static char **arg_property = NULL;
69 static bool arg_all = false;
70 static const char *arg_job_mode = "replace";
71 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
72 static bool arg_no_block = false;
73 static bool arg_no_legend = false;
74 static bool arg_no_pager = false;
75 static bool arg_no_wtmp = false;
76 static bool arg_no_sync = false;
77 static bool arg_no_wall = false;
78 static bool arg_no_reload = false;
79 static bool arg_dry = false;
80 static bool arg_quiet = false;
81 static bool arg_full = false;
82 static int arg_force = 0;
83 static bool arg_ask_password = true;
84 static bool arg_failed = false;
85 static bool arg_runtime = false;
86 static char **arg_wall = NULL;
87 static const char *arg_kill_who = NULL;
88 static const char *arg_kill_mode = NULL;
89 static int arg_signal = SIGTERM;
90 static const char *arg_root = NULL;
91 static usec_t arg_when = 0;
92 static enum action {
93         ACTION_INVALID,
94         ACTION_SYSTEMCTL,
95         ACTION_HALT,
96         ACTION_POWEROFF,
97         ACTION_REBOOT,
98         ACTION_KEXEC,
99         ACTION_EXIT,
100         ACTION_SUSPEND,
101         ACTION_HIBERNATE,
102         ACTION_RUNLEVEL2,
103         ACTION_RUNLEVEL3,
104         ACTION_RUNLEVEL4,
105         ACTION_RUNLEVEL5,
106         ACTION_RESCUE,
107         ACTION_EMERGENCY,
108         ACTION_DEFAULT,
109         ACTION_RELOAD,
110         ACTION_REEXEC,
111         ACTION_RUNLEVEL,
112         ACTION_CANCEL_SHUTDOWN,
113         _ACTION_MAX
114 } arg_action = ACTION_SYSTEMCTL;
115 static enum dot {
116         DOT_ALL,
117         DOT_ORDER,
118         DOT_REQUIRE
119 } arg_dot = DOT_ALL;
120 static enum transport {
121         TRANSPORT_NORMAL,
122         TRANSPORT_SSH,
123         TRANSPORT_POLKIT
124 } arg_transport = TRANSPORT_NORMAL;
125 static const char *arg_host = NULL;
126 static bool arg_follow = false;
127 static unsigned arg_lines = 10;
128 static OutputMode arg_output = OUTPUT_SHORT;
129
130 static bool private_bus = false;
131
132 static int daemon_reload(DBusConnection *bus, char **args);
133 static void halt_now(enum action a);
134
135 static bool on_tty(void) {
136         static int t = -1;
137
138         /* Note that this is invoked relatively early, before we start
139          * the pager. That means the value we return reflects whether
140          * we originally were started on a tty, not if we currently
141          * are. But this is intended, since we want colour and so on
142          * when run in our own pager. */
143
144         if (_unlikely_(t < 0))
145                 t = isatty(STDOUT_FILENO) > 0;
146
147         return t;
148 }
149
150 static void pager_open_if_enabled(void) {
151
152         /* Cache result before we open the pager */
153         on_tty();
154
155         if (arg_no_pager)
156                 return;
157
158         pager_open();
159 }
160
161 static void ask_password_agent_open_if_enabled(void) {
162
163         /* Open the password agent as a child process if necessary */
164
165         if (!arg_ask_password)
166                 return;
167
168         if (arg_scope != UNIT_FILE_SYSTEM)
169                 return;
170
171         ask_password_agent_open();
172 }
173
174 static void polkit_agent_open_if_enabled(void) {
175
176         /* Open the polkit agent as a child process if necessary */
177
178         if (!arg_ask_password)
179                 return;
180
181         if (arg_scope != UNIT_FILE_SYSTEM)
182                 return;
183
184         polkit_agent_open();
185 }
186
187 static const char *ansi_highlight_red(bool b) {
188
189         if (!on_tty())
190                 return "";
191
192         return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
193 }
194
195 static const char *ansi_highlight_green(bool b) {
196
197         if (!on_tty())
198                 return "";
199
200         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
201 }
202
203 static bool error_is_no_service(const DBusError *error) {
204         assert(error);
205
206         if (!dbus_error_is_set(error))
207                 return false;
208
209         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
210                 return true;
211
212         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
213                 return true;
214
215         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
216 }
217
218 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
219         assert(error);
220
221         if (!dbus_error_is_set(error))
222                 return r;
223
224         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
225             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
226             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
227             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
228                 return EXIT_NOPERMISSION;
229
230         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
231                 return EXIT_NOTINSTALLED;
232
233         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
234             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
235                 return EXIT_NOTIMPLEMENTED;
236
237         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
238                 return EXIT_NOTCONFIGURED;
239
240         if (r != 0)
241                 return r;
242
243         return EXIT_FAILURE;
244 }
245
246 static void warn_wall(enum action a) {
247         static const char *table[_ACTION_MAX] = {
248                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
249                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
250                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
251                 [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
252                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
253                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
254         };
255
256         if (arg_no_wall)
257                 return;
258
259         if (arg_wall) {
260                 char *p;
261
262                 p = strv_join(arg_wall, " ");
263                 if (!p) {
264                         log_error("Failed to join strings.");
265                         return;
266                 }
267
268                 if (*p) {
269                         utmp_wall(p, NULL);
270                         free(p);
271                         return;
272                 }
273
274                 free(p);
275         }
276
277         if (!table[a])
278                 return;
279
280         utmp_wall(table[a], NULL);
281 }
282
283 static bool avoid_bus(void) {
284
285         if (running_in_chroot() > 0)
286                 return true;
287
288         if (sd_booted() <= 0)
289                 return true;
290
291         if (!isempty(arg_root))
292                 return true;
293
294         if (arg_scope == UNIT_FILE_GLOBAL)
295                 return true;
296
297         return false;
298 }
299
300 struct unit_info {
301         const char *id;
302         const char *description;
303         const char *load_state;
304         const char *active_state;
305         const char *sub_state;
306         const char *following;
307         const char *unit_path;
308         uint32_t job_id;
309         const char *job_type;
310         const char *job_path;
311 };
312
313 static int compare_unit_info(const void *a, const void *b) {
314         const char *d1, *d2;
315         const struct unit_info *u = a, *v = b;
316
317         d1 = strrchr(u->id, '.');
318         d2 = strrchr(v->id, '.');
319
320         if (d1 && d2) {
321                 int r;
322
323                 if ((r = strcasecmp(d1, d2)) != 0)
324                         return r;
325         }
326
327         return strcasecmp(u->id, v->id);
328 }
329
330 static bool output_show_unit(const struct unit_info *u) {
331         const char *dot;
332
333         if (arg_failed)
334                 return streq(u->active_state, "failed");
335
336         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
337                               streq(dot+1, arg_type))) &&
338                 (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
339 }
340
341 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
342         unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
343         const struct unit_info *u;
344
345         max_id_len = sizeof("UNIT")-1;
346         active_len = sizeof("ACTIVE")-1;
347         sub_len = sizeof("SUB")-1;
348         job_len = sizeof("JOB")-1;
349         desc_len = 0;
350
351         for (u = unit_infos; u < unit_infos + c; u++) {
352                 if (!output_show_unit(u))
353                         continue;
354
355                 max_id_len = MAX(max_id_len, strlen(u->id));
356                 active_len = MAX(active_len, strlen(u->active_state));
357                 sub_len = MAX(sub_len, strlen(u->sub_state));
358                 if (u->job_id != 0)
359                         job_len = MAX(job_len, strlen(u->job_type));
360         }
361
362         if (!arg_full) {
363                 unsigned basic_len;
364                 id_len = MIN(max_id_len, 25);
365                 basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
366                 if (basic_len < (unsigned) columns()) {
367                         unsigned extra_len, incr;
368                         extra_len = columns() - basic_len;
369                         /* Either UNIT already got 25, or is fully satisfied.
370                          * Grant up to 25 to DESC now. */
371                         incr = MIN(extra_len, 25);
372                         desc_len += incr;
373                         extra_len -= incr;
374                         /* split the remaining space between UNIT and DESC,
375                          * but do not give UNIT more than it needs. */
376                         if (extra_len > 0) {
377                                 incr = MIN(extra_len / 2, max_id_len - id_len);
378                                 id_len += incr;
379                                 desc_len += extra_len - incr;
380                         }
381                 }
382         } else
383                 id_len = max_id_len;
384
385         if (!arg_no_legend) {
386                 printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
387                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
388                 if (!arg_full && arg_no_pager)
389                         printf("%.*s\n", desc_len, "DESCRIPTION");
390                 else
391                         printf("%s\n", "DESCRIPTION");
392         }
393
394         for (u = unit_infos; u < unit_infos + c; u++) {
395                 char *e;
396                 const char *on_loaded, *off_loaded;
397                 const char *on_active, *off_active;
398
399                 if (!output_show_unit(u))
400                         continue;
401
402                 n_shown++;
403
404                 if (streq(u->load_state, "error")) {
405                         on_loaded = ansi_highlight_red(true);
406                         off_loaded = ansi_highlight_red(false);
407                 } else
408                         on_loaded = off_loaded = "";
409
410                 if (streq(u->active_state, "failed")) {
411                         on_active = ansi_highlight_red(true);
412                         off_active = ansi_highlight_red(false);
413                 } else
414                         on_active = off_active = "";
415
416                 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
417
418                 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
419                        id_len, e ? e : u->id,
420                        on_loaded, u->load_state, off_loaded,
421                        on_active, active_len, u->active_state,
422                        sub_len, u->sub_state, off_active,
423                        job_len, u->job_id ? u->job_type : "");
424                 if (!arg_full && arg_no_pager)
425                         printf("%.*s\n", desc_len, u->description);
426                 else
427                         printf("%s\n", u->description);
428
429                 free(e);
430         }
431
432         if (!arg_no_legend) {
433                 printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
434                        "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
435                        "SUB    = The low-level unit activation state, values depend on unit type.\n"
436                        "JOB    = Pending job for the unit.\n");
437
438                 if (arg_all)
439                         printf("\n%u units listed.\n", n_shown);
440                 else
441                         printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
442         }
443 }
444
445 static int list_units(DBusConnection *bus, char **args) {
446         DBusMessage *m = NULL, *reply = NULL;
447         DBusError error;
448         int r;
449         DBusMessageIter iter, sub, sub2;
450         unsigned c = 0, n_units = 0;
451         struct unit_info *unit_infos = NULL;
452
453         dbus_error_init(&error);
454
455         assert(bus);
456
457         pager_open_if_enabled();
458
459         if (!(m = dbus_message_new_method_call(
460                               "org.freedesktop.systemd1",
461                               "/org/freedesktop/systemd1",
462                               "org.freedesktop.systemd1.Manager",
463                               "ListUnits"))) {
464                 log_error("Could not allocate message.");
465                 return -ENOMEM;
466         }
467
468         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
469                 log_error("Failed to issue method call: %s", bus_error_message(&error));
470                 r = -EIO;
471                 goto finish;
472         }
473
474         if (!dbus_message_iter_init(reply, &iter) ||
475             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
476             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
477                 log_error("Failed to parse reply.");
478                 r = -EIO;
479                 goto finish;
480         }
481
482         dbus_message_iter_recurse(&iter, &sub);
483
484         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
485                 struct unit_info *u;
486
487                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
488                         log_error("Failed to parse reply.");
489                         r = -EIO;
490                         goto finish;
491                 }
492
493                 if (c >= n_units) {
494                         struct unit_info *w;
495
496                         n_units = MAX(2*c, 16);
497                         w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
498
499                         if (!w) {
500                                 log_error("Failed to allocate unit array.");
501                                 r = -ENOMEM;
502                                 goto finish;
503                         }
504
505                         unit_infos = w;
506                 }
507
508                 u = unit_infos+c;
509
510                 dbus_message_iter_recurse(&sub, &sub2);
511
512                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
513                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
514                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
515                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
516                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
517                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
518                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
519                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
520                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
521                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
522                         log_error("Failed to parse reply.");
523                         r = -EIO;
524                         goto finish;
525                 }
526
527                 dbus_message_iter_next(&sub);
528                 c++;
529         }
530
531         if (c > 0) {
532                 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
533                 output_units_list(unit_infos, c);
534         }
535
536         r = 0;
537
538 finish:
539         if (m)
540                 dbus_message_unref(m);
541
542         if (reply)
543                 dbus_message_unref(reply);
544
545         free(unit_infos);
546
547         dbus_error_free(&error);
548
549         return r;
550 }
551
552 static int compare_unit_file_list(const void *a, const void *b) {
553         const char *d1, *d2;
554         const UnitFileList *u = a, *v = b;
555
556         d1 = strrchr(u->path, '.');
557         d2 = strrchr(v->path, '.');
558
559         if (d1 && d2) {
560                 int r;
561
562                 r = strcasecmp(d1, d2);
563                 if (r != 0)
564                         return r;
565         }
566
567         return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
568 }
569
570 static bool output_show_unit_file(const UnitFileList *u) {
571         const char *dot;
572
573         return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
574 }
575
576 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
577         unsigned max_id_len, id_cols, state_cols, n_shown = 0;
578         const UnitFileList *u;
579
580         max_id_len = sizeof("UNIT FILE")-1;
581         state_cols = sizeof("STATE")-1;
582         for (u = units; u < units + c; u++) {
583                 if (!output_show_unit_file(u))
584                         continue;
585
586                 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
587                 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
588         }
589
590         if (!arg_full) {
591                 unsigned basic_cols;
592                 id_cols = MIN(max_id_len, 25);
593                 basic_cols = 1 + id_cols + state_cols;
594                 if (basic_cols < (unsigned) columns())
595                         id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
596         } else
597                 id_cols = max_id_len;
598
599         if (!arg_no_legend)
600                 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
601
602         for (u = units; u < units + c; u++) {
603                 char *e;
604                 const char *on, *off;
605                 const char *id;
606
607                 if (!output_show_unit_file(u))
608                         continue;
609
610                 n_shown++;
611
612                 if (u->state == UNIT_FILE_MASKED ||
613                     u->state == UNIT_FILE_MASKED_RUNTIME ||
614                     u->state == UNIT_FILE_DISABLED) {
615                         on  = ansi_highlight_red(true);
616                         off = ansi_highlight_red(false);
617                 } else if (u->state == UNIT_FILE_ENABLED) {
618                         on  = ansi_highlight_green(true);
619                         off = ansi_highlight_green(false);
620                 } else
621                         on = off = "";
622
623                 id = path_get_file_name(u->path);
624
625                 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
626
627                 printf("%-*s %s%-*s%s\n",
628                        id_cols, e ? e : id,
629                        on, state_cols, unit_file_state_to_string(u->state), off);
630
631                 free(e);
632         }
633
634         if (!arg_no_legend)
635                 printf("\n%u unit files listed.\n", n_shown);
636 }
637
638 static int list_unit_files(DBusConnection *bus, char **args) {
639         DBusMessage *m = NULL, *reply = NULL;
640         DBusError error;
641         int r;
642         DBusMessageIter iter, sub, sub2;
643         unsigned c = 0, n_units = 0;
644         UnitFileList *units = NULL;
645
646         dbus_error_init(&error);
647
648         pager_open_if_enabled();
649
650         if (avoid_bus()) {
651                 Hashmap *h;
652                 UnitFileList *u;
653                 Iterator i;
654
655                 h = hashmap_new(string_hash_func, string_compare_func);
656                 if (!h) {
657                         log_error("Out of memory");
658                         return -ENOMEM;
659                 }
660
661                 r = unit_file_get_list(arg_scope, arg_root, h);
662                 if (r < 0) {
663                         unit_file_list_free(h);
664                         log_error("Failed to get unit file list: %s", strerror(-r));
665                         return r;
666                 }
667
668                 n_units = hashmap_size(h);
669                 units = new(UnitFileList, n_units);
670                 if (!units) {
671                         unit_file_list_free(h);
672                         log_error("Out of memory");
673                         return -ENOMEM;
674                 }
675
676                 HASHMAP_FOREACH(u, h, i) {
677                         memcpy(units + c++, u, sizeof(UnitFileList));
678                         free(u);
679                 }
680
681                 hashmap_free(h);
682         } else {
683                 assert(bus);
684
685                 m = dbus_message_new_method_call(
686                                 "org.freedesktop.systemd1",
687                                 "/org/freedesktop/systemd1",
688                                 "org.freedesktop.systemd1.Manager",
689                                 "ListUnitFiles");
690                 if (!m) {
691                         log_error("Could not allocate message.");
692                         return -ENOMEM;
693                 }
694
695                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
696                 if (!reply) {
697                         log_error("Failed to issue method call: %s", bus_error_message(&error));
698                         r = -EIO;
699                         goto finish;
700                 }
701
702                 if (!dbus_message_iter_init(reply, &iter) ||
703                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
704                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
705                         log_error("Failed to parse reply.");
706                         r = -EIO;
707                         goto finish;
708                 }
709
710                 dbus_message_iter_recurse(&iter, &sub);
711
712                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
713                         UnitFileList *u;
714                         const char *state;
715
716                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
717                                 log_error("Failed to parse reply.");
718                                 r = -EIO;
719                                 goto finish;
720                         }
721
722                         if (c >= n_units) {
723                                 UnitFileList *w;
724
725                                 n_units = MAX(2*c, 16);
726                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
727
728                                 if (!w) {
729                                         log_error("Failed to allocate unit array.");
730                                         r = -ENOMEM;
731                                         goto finish;
732                                 }
733
734                                 units = w;
735                         }
736
737                         u = units+c;
738
739                         dbus_message_iter_recurse(&sub, &sub2);
740
741                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
742                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
743                                 log_error("Failed to parse reply.");
744                                 r = -EIO;
745                                 goto finish;
746                         }
747
748                         u->state = unit_file_state_from_string(state);
749
750                         dbus_message_iter_next(&sub);
751                         c++;
752                 }
753         }
754
755         if (c > 0) {
756                 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
757                 output_unit_file_list(units, c);
758         }
759
760         r = 0;
761
762 finish:
763         if (m)
764                 dbus_message_unref(m);
765
766         if (reply)
767                 dbus_message_unref(reply);
768
769         free(units);
770
771         dbus_error_free(&error);
772
773         return r;
774 }
775
776 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
777         static const char * const colors[] = {
778                 "Requires",              "[color=\"black\"]",
779                 "RequiresOverridable",   "[color=\"black\"]",
780                 "Requisite",             "[color=\"darkblue\"]",
781                 "RequisiteOverridable",  "[color=\"darkblue\"]",
782                 "Wants",                 "[color=\"darkgrey\"]",
783                 "Conflicts",             "[color=\"red\"]",
784                 "ConflictedBy",          "[color=\"red\"]",
785                 "After",                 "[color=\"green\"]"
786         };
787
788         const char *c = NULL;
789         unsigned i;
790
791         assert(name);
792         assert(prop);
793         assert(iter);
794
795         for (i = 0; i < ELEMENTSOF(colors); i += 2)
796                 if (streq(colors[i], prop)) {
797                         c = colors[i+1];
798                         break;
799                 }
800
801         if (!c)
802                 return 0;
803
804         if (arg_dot != DOT_ALL)
805                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
806                         return 0;
807
808         switch (dbus_message_iter_get_arg_type(iter)) {
809
810         case DBUS_TYPE_ARRAY:
811
812                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
813                         DBusMessageIter sub;
814
815                         dbus_message_iter_recurse(iter, &sub);
816
817                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
818                                 const char *s;
819
820                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
821                                 dbus_message_iter_get_basic(&sub, &s);
822                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
823
824                                 dbus_message_iter_next(&sub);
825                         }
826
827                         return 0;
828                 }
829         }
830
831         return 0;
832 }
833
834 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
835         DBusMessage *m = NULL, *reply = NULL;
836         const char *interface = "org.freedesktop.systemd1.Unit";
837         int r;
838         DBusError error;
839         DBusMessageIter iter, sub, sub2, sub3;
840
841         assert(bus);
842         assert(path);
843
844         dbus_error_init(&error);
845
846         if (!(m = dbus_message_new_method_call(
847                               "org.freedesktop.systemd1",
848                               path,
849                               "org.freedesktop.DBus.Properties",
850                               "GetAll"))) {
851                 log_error("Could not allocate message.");
852                 r = -ENOMEM;
853                 goto finish;
854         }
855
856         if (!dbus_message_append_args(m,
857                                       DBUS_TYPE_STRING, &interface,
858                                       DBUS_TYPE_INVALID)) {
859                 log_error("Could not append arguments to message.");
860                 r = -ENOMEM;
861                 goto finish;
862         }
863
864         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
865                 log_error("Failed to issue method call: %s", bus_error_message(&error));
866                 r = -EIO;
867                 goto finish;
868         }
869
870         if (!dbus_message_iter_init(reply, &iter) ||
871             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
872             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
873                 log_error("Failed to parse reply.");
874                 r = -EIO;
875                 goto finish;
876         }
877
878         dbus_message_iter_recurse(&iter, &sub);
879
880         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
881                 const char *prop;
882
883                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
884                         log_error("Failed to parse reply.");
885                         r = -EIO;
886                         goto finish;
887                 }
888
889                 dbus_message_iter_recurse(&sub, &sub2);
890
891                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
892                         log_error("Failed to parse reply.");
893                         r = -EIO;
894                         goto finish;
895                 }
896
897                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
898                         log_error("Failed to parse reply.");
899                         r = -EIO;
900                         goto finish;
901                 }
902
903                 dbus_message_iter_recurse(&sub2, &sub3);
904
905                 if (dot_one_property(name, prop, &sub3)) {
906                         log_error("Failed to parse reply.");
907                         r = -EIO;
908                         goto finish;
909                 }
910
911                 dbus_message_iter_next(&sub);
912         }
913
914         r = 0;
915
916 finish:
917         if (m)
918                 dbus_message_unref(m);
919
920         if (reply)
921                 dbus_message_unref(reply);
922
923         dbus_error_free(&error);
924
925         return r;
926 }
927
928 static int dot(DBusConnection *bus, char **args) {
929         DBusMessage *m = NULL, *reply = NULL;
930         DBusError error;
931         int r;
932         DBusMessageIter iter, sub, sub2;
933
934         dbus_error_init(&error);
935
936         assert(bus);
937
938         if (!(m = dbus_message_new_method_call(
939                               "org.freedesktop.systemd1",
940                               "/org/freedesktop/systemd1",
941                               "org.freedesktop.systemd1.Manager",
942                               "ListUnits"))) {
943                 log_error("Could not allocate message.");
944                 return -ENOMEM;
945         }
946
947         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
948                 log_error("Failed to issue method call: %s", bus_error_message(&error));
949                 r = -EIO;
950                 goto finish;
951         }
952
953         if (!dbus_message_iter_init(reply, &iter) ||
954             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
955             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
956                 log_error("Failed to parse reply.");
957                 r = -EIO;
958                 goto finish;
959         }
960
961         printf("digraph systemd {\n");
962
963         dbus_message_iter_recurse(&iter, &sub);
964         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
965                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
966
967                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
968                         log_error("Failed to parse reply.");
969                         r = -EIO;
970                         goto finish;
971                 }
972
973                 dbus_message_iter_recurse(&sub, &sub2);
974
975                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
976                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
977                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
978                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
979                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
980                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
981                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
982                         log_error("Failed to parse reply.");
983                         r = -EIO;
984                         goto finish;
985                 }
986
987                 if ((r = dot_one(bus, id, unit_path)) < 0)
988                         goto finish;
989
990                 /* printf("\t\"%s\";\n", id); */
991                 dbus_message_iter_next(&sub);
992         }
993
994         printf("}\n");
995
996         log_info("   Color legend: black     = Requires\n"
997                  "                 dark blue = Requisite\n"
998                  "                 dark grey = Wants\n"
999                  "                 red       = Conflicts\n"
1000                  "                 green     = After\n");
1001
1002         if (on_tty())
1003                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
1004                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
1005
1006         r = 0;
1007
1008 finish:
1009         if (m)
1010                 dbus_message_unref(m);
1011
1012         if (reply)
1013                 dbus_message_unref(reply);
1014
1015         dbus_error_free(&error);
1016
1017         return r;
1018 }
1019
1020 static int list_jobs(DBusConnection *bus, char **args) {
1021         DBusMessage *m = NULL, *reply = NULL;
1022         DBusError error;
1023         int r;
1024         DBusMessageIter iter, sub, sub2;
1025         unsigned k = 0;
1026
1027         dbus_error_init(&error);
1028
1029         assert(bus);
1030
1031         pager_open_if_enabled();
1032
1033         if (!(m = dbus_message_new_method_call(
1034                               "org.freedesktop.systemd1",
1035                               "/org/freedesktop/systemd1",
1036                               "org.freedesktop.systemd1.Manager",
1037                               "ListJobs"))) {
1038                 log_error("Could not allocate message.");
1039                 return -ENOMEM;
1040         }
1041
1042         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1043                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1044                 r = -EIO;
1045                 goto finish;
1046         }
1047
1048         if (!dbus_message_iter_init(reply, &iter) ||
1049             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1050             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
1051                 log_error("Failed to parse reply.");
1052                 r = -EIO;
1053                 goto finish;
1054         }
1055
1056         dbus_message_iter_recurse(&iter, &sub);
1057
1058         if (on_tty())
1059                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1060
1061         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1062                 const char *name, *type, *state, *job_path, *unit_path;
1063                 uint32_t id;
1064                 char *e;
1065
1066                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1067                         log_error("Failed to parse reply.");
1068                         r = -EIO;
1069                         goto finish;
1070                 }
1071
1072                 dbus_message_iter_recurse(&sub, &sub2);
1073
1074                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1075                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1076                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1077                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1078                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1079                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1080                         log_error("Failed to parse reply.");
1081                         r = -EIO;
1082                         goto finish;
1083                 }
1084
1085                 e = arg_full ? NULL : ellipsize(name, 25, 33);
1086                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1087                 free(e);
1088
1089                 k++;
1090
1091                 dbus_message_iter_next(&sub);
1092         }
1093
1094         if (on_tty())
1095                 printf("\n%u jobs listed.\n", k);
1096
1097         r = 0;
1098
1099 finish:
1100         if (m)
1101                 dbus_message_unref(m);
1102
1103         if (reply)
1104                 dbus_message_unref(reply);
1105
1106         dbus_error_free(&error);
1107
1108         return r;
1109 }
1110
1111 static int load_unit(DBusConnection *bus, char **args) {
1112         DBusMessage *m = NULL;
1113         DBusError error;
1114         int r;
1115         char **name;
1116
1117         dbus_error_init(&error);
1118
1119         assert(bus);
1120         assert(args);
1121
1122         STRV_FOREACH(name, args+1) {
1123                 DBusMessage *reply;
1124
1125                 if (!(m = dbus_message_new_method_call(
1126                                       "org.freedesktop.systemd1",
1127                                       "/org/freedesktop/systemd1",
1128                                       "org.freedesktop.systemd1.Manager",
1129                                       "LoadUnit"))) {
1130                         log_error("Could not allocate message.");
1131                         r = -ENOMEM;
1132                         goto finish;
1133                 }
1134
1135                 if (!dbus_message_append_args(m,
1136                                               DBUS_TYPE_STRING, name,
1137                                               DBUS_TYPE_INVALID)) {
1138                         log_error("Could not append arguments to message.");
1139                         r = -ENOMEM;
1140                         goto finish;
1141                 }
1142
1143                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1144                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1145                         r = -EIO;
1146                         goto finish;
1147                 }
1148
1149                 dbus_message_unref(m);
1150                 dbus_message_unref(reply);
1151
1152                 m = reply = NULL;
1153         }
1154
1155         r = 0;
1156
1157 finish:
1158         if (m)
1159                 dbus_message_unref(m);
1160
1161         dbus_error_free(&error);
1162
1163         return r;
1164 }
1165
1166 static int cancel_job(DBusConnection *bus, char **args) {
1167         DBusMessage *m = NULL, *reply = NULL;
1168         DBusError error;
1169         int r;
1170         char **name;
1171
1172         dbus_error_init(&error);
1173
1174         assert(bus);
1175         assert(args);
1176
1177         if (strv_length(args) <= 1)
1178                 return daemon_reload(bus, args);
1179
1180         STRV_FOREACH(name, args+1) {
1181                 unsigned id;
1182                 const char *path;
1183
1184                 if (!(m = dbus_message_new_method_call(
1185                                       "org.freedesktop.systemd1",
1186                                       "/org/freedesktop/systemd1",
1187                                       "org.freedesktop.systemd1.Manager",
1188                                       "GetJob"))) {
1189                         log_error("Could not allocate message.");
1190                         r = -ENOMEM;
1191                         goto finish;
1192                 }
1193
1194                 if ((r = safe_atou(*name, &id)) < 0) {
1195                         log_error("Failed to parse job id: %s", strerror(-r));
1196                         goto finish;
1197                 }
1198
1199                 assert_cc(sizeof(uint32_t) == sizeof(id));
1200                 if (!dbus_message_append_args(m,
1201                                               DBUS_TYPE_UINT32, &id,
1202                                               DBUS_TYPE_INVALID)) {
1203                         log_error("Could not append arguments to message.");
1204                         r = -ENOMEM;
1205                         goto finish;
1206                 }
1207
1208                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1209                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1210                         r = -EIO;
1211                         goto finish;
1212                 }
1213
1214                 if (!dbus_message_get_args(reply, &error,
1215                                            DBUS_TYPE_OBJECT_PATH, &path,
1216                                            DBUS_TYPE_INVALID)) {
1217                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1218                         r = -EIO;
1219                         goto finish;
1220                 }
1221
1222                 dbus_message_unref(m);
1223                 if (!(m = dbus_message_new_method_call(
1224                                       "org.freedesktop.systemd1",
1225                                       path,
1226                                       "org.freedesktop.systemd1.Job",
1227                                       "Cancel"))) {
1228                         log_error("Could not allocate message.");
1229                         r = -ENOMEM;
1230                         goto finish;
1231                 }
1232
1233                 dbus_message_unref(reply);
1234                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1235                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1236                         r = -EIO;
1237                         goto finish;
1238                 }
1239
1240                 dbus_message_unref(m);
1241                 dbus_message_unref(reply);
1242                 m = reply = NULL;
1243         }
1244
1245         r = 0;
1246
1247 finish:
1248         if (m)
1249                 dbus_message_unref(m);
1250
1251         if (reply)
1252                 dbus_message_unref(reply);
1253
1254         dbus_error_free(&error);
1255
1256         return r;
1257 }
1258
1259 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1260         DBusMessage *m = NULL, *reply = NULL;
1261         dbus_bool_t b = FALSE;
1262         DBusMessageIter iter, sub;
1263         const char
1264                 *interface = "org.freedesktop.systemd1.Unit",
1265                 *property = "NeedDaemonReload",
1266                 *path;
1267
1268         /* We ignore all errors here, since this is used to show a warning only */
1269
1270         if (!(m = dbus_message_new_method_call(
1271                               "org.freedesktop.systemd1",
1272                               "/org/freedesktop/systemd1",
1273                               "org.freedesktop.systemd1.Manager",
1274                               "GetUnit")))
1275                 goto finish;
1276
1277         if (!dbus_message_append_args(m,
1278                                       DBUS_TYPE_STRING, &unit,
1279                                       DBUS_TYPE_INVALID))
1280                 goto finish;
1281
1282         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1283                 goto finish;
1284
1285         if (!dbus_message_get_args(reply, NULL,
1286                                    DBUS_TYPE_OBJECT_PATH, &path,
1287                                    DBUS_TYPE_INVALID))
1288                 goto finish;
1289
1290         dbus_message_unref(m);
1291         if (!(m = dbus_message_new_method_call(
1292                               "org.freedesktop.systemd1",
1293                               path,
1294                               "org.freedesktop.DBus.Properties",
1295                               "Get")))
1296                 goto finish;
1297
1298         if (!dbus_message_append_args(m,
1299                                       DBUS_TYPE_STRING, &interface,
1300                                       DBUS_TYPE_STRING, &property,
1301                                       DBUS_TYPE_INVALID)) {
1302                 goto finish;
1303         }
1304
1305         dbus_message_unref(reply);
1306         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1307                 goto finish;
1308
1309         if (!dbus_message_iter_init(reply, &iter) ||
1310             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1311                 goto finish;
1312
1313         dbus_message_iter_recurse(&iter, &sub);
1314
1315         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1316                 goto finish;
1317
1318         dbus_message_iter_get_basic(&sub, &b);
1319
1320 finish:
1321         if (m)
1322                 dbus_message_unref(m);
1323
1324         if (reply)
1325                 dbus_message_unref(reply);
1326
1327         return b;
1328 }
1329
1330 typedef struct WaitData {
1331         Set *set;
1332         char *result;
1333 } WaitData;
1334
1335 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1336         DBusError error;
1337         WaitData *d = data;
1338
1339         assert(connection);
1340         assert(message);
1341         assert(d);
1342
1343         dbus_error_init(&error);
1344
1345         log_debug("Got D-Bus request: %s.%s() on %s",
1346                   dbus_message_get_interface(message),
1347                   dbus_message_get_member(message),
1348                   dbus_message_get_path(message));
1349
1350         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1351                 log_error("Warning! D-Bus connection terminated.");
1352                 dbus_connection_close(connection);
1353
1354         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1355                 uint32_t id;
1356                 const char *path, *result, *unit;
1357                 dbus_bool_t success = true;
1358
1359                 if (dbus_message_get_args(message, &error,
1360                                           DBUS_TYPE_UINT32, &id,
1361                                           DBUS_TYPE_OBJECT_PATH, &path,
1362                                           DBUS_TYPE_STRING, &unit,
1363                                           DBUS_TYPE_STRING, &result,
1364                                           DBUS_TYPE_INVALID)) {
1365                         char *p;
1366
1367                         p = set_remove(d->set, (char*) path);
1368                         free(p);
1369
1370                         if (*result)
1371                                 d->result = strdup(result);
1372
1373                         goto finish;
1374                 }
1375 #ifndef LEGACY
1376                 dbus_error_free(&error);
1377                 if (dbus_message_get_args(message, &error,
1378                                           DBUS_TYPE_UINT32, &id,
1379                                           DBUS_TYPE_OBJECT_PATH, &path,
1380                                           DBUS_TYPE_STRING, &result,
1381                                           DBUS_TYPE_INVALID)) {
1382                         char *p;
1383
1384                         /* Compatibility with older systemd versions <
1385                          * 183 during upgrades. This should be dropped
1386                          * one day. */
1387                         p = set_remove(d->set, (char*) path);
1388                         free(p);
1389
1390                         if (*result)
1391                                 d->result = strdup(result);
1392
1393                         goto finish;
1394                 }
1395
1396                 dbus_error_free(&error);
1397                 if (dbus_message_get_args(message, &error,
1398                                           DBUS_TYPE_UINT32, &id,
1399                                           DBUS_TYPE_OBJECT_PATH, &path,
1400                                           DBUS_TYPE_BOOLEAN, &success,
1401                                           DBUS_TYPE_INVALID)) {
1402                         char *p;
1403
1404                         /* Compatibility with older systemd versions <
1405                          * 19 during upgrades. This should be dropped
1406                          * one day */
1407
1408                         p = set_remove(d->set, (char*) path);
1409                         free(p);
1410
1411                         if (!success)
1412                                 d->result = strdup("failed");
1413
1414                         goto finish;
1415                 }
1416 #endif
1417
1418                 log_error("Failed to parse message: %s", bus_error_message(&error));
1419         }
1420
1421 finish:
1422         dbus_error_free(&error);
1423         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1424 }
1425
1426 static int enable_wait_for_jobs(DBusConnection *bus) {
1427         DBusError error;
1428
1429         assert(bus);
1430
1431         if (private_bus)
1432                 return 0;
1433
1434         dbus_error_init(&error);
1435         dbus_bus_add_match(bus,
1436                            "type='signal',"
1437                            "sender='org.freedesktop.systemd1',"
1438                            "interface='org.freedesktop.systemd1.Manager',"
1439                            "member='JobRemoved',"
1440                            "path='/org/freedesktop/systemd1'",
1441                            &error);
1442
1443         if (dbus_error_is_set(&error)) {
1444                 log_error("Failed to add match: %s", bus_error_message(&error));
1445                 dbus_error_free(&error);
1446                 return -EIO;
1447         }
1448
1449         /* This is slightly dirty, since we don't undo the match registrations. */
1450         return 0;
1451 }
1452
1453 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1454         int r;
1455         WaitData d;
1456
1457         assert(bus);
1458         assert(s);
1459
1460         zero(d);
1461         d.set = s;
1462
1463         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1464                 log_error("Failed to add filter.");
1465                 r = -ENOMEM;
1466                 goto finish;
1467         }
1468
1469         while (!set_isempty(s) &&
1470                dbus_connection_read_write_dispatch(bus, -1))
1471                 ;
1472
1473         if (!arg_quiet && d.result) {
1474                 if (streq(d.result, "timeout"))
1475                         log_error("Job timed out.");
1476                 else if (streq(d.result, "canceled"))
1477                         log_error("Job canceled.");
1478                 else if (streq(d.result, "dependency"))
1479                         log_error("A dependency job failed. See system journal for details.");
1480                 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1481                         log_error("Job failed. See system journal and 'systemctl status' for details.");
1482         }
1483
1484         if (streq_ptr(d.result, "timeout"))
1485                 r = -ETIME;
1486         else if (streq_ptr(d.result, "canceled"))
1487                 r = -ECANCELED;
1488         else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1489                 r = -EIO;
1490         else
1491                 r = 0;
1492
1493         free(d.result);
1494
1495 finish:
1496         /* This is slightly dirty, since we don't undo the filter registration. */
1497
1498         return r;
1499 }
1500
1501 static int start_unit_one(
1502                 DBusConnection *bus,
1503                 const char *method,
1504                 const char *name,
1505                 const char *mode,
1506                 DBusError *error,
1507                 Set *s) {
1508
1509         DBusMessage *m = NULL, *reply = NULL;
1510         const char *path;
1511         int r;
1512
1513         assert(bus);
1514         assert(method);
1515         assert(name);
1516         assert(mode);
1517         assert(error);
1518         assert(arg_no_block || s);
1519
1520         if (!(m = dbus_message_new_method_call(
1521                               "org.freedesktop.systemd1",
1522                               "/org/freedesktop/systemd1",
1523                               "org.freedesktop.systemd1.Manager",
1524                               method))) {
1525                 log_error("Could not allocate message.");
1526                 r = -ENOMEM;
1527                 goto finish;
1528         }
1529
1530         if (!dbus_message_append_args(m,
1531                                       DBUS_TYPE_STRING, &name,
1532                                       DBUS_TYPE_STRING, &mode,
1533                                       DBUS_TYPE_INVALID)) {
1534                 log_error("Could not append arguments to message.");
1535                 r = -ENOMEM;
1536                 goto finish;
1537         }
1538
1539         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1540
1541                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1542                         /* There's always a fallback possible for
1543                          * legacy actions. */
1544                         r = -EADDRNOTAVAIL;
1545                         goto finish;
1546                 }
1547
1548                 log_error("Failed to issue method call: %s", bus_error_message(error));
1549                 r = -EIO;
1550                 goto finish;
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                 r = -EIO;
1558                 goto finish;
1559         }
1560
1561         if (need_daemon_reload(bus, name))
1562                 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1563                             arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1564
1565         if (!arg_no_block) {
1566                 char *p;
1567
1568                 if (!(p = strdup(path))) {
1569                         log_error("Failed to duplicate path.");
1570                         r = -ENOMEM;
1571                         goto finish;
1572                 }
1573
1574                 if ((r = set_put(s, p)) < 0) {
1575                         free(p);
1576                         log_error("Failed to add path to set.");
1577                         goto finish;
1578                 }
1579         }
1580
1581         r = 0;
1582
1583 finish:
1584         if (m)
1585                 dbus_message_unref(m);
1586
1587         if (reply)
1588                 dbus_message_unref(reply);
1589
1590         return r;
1591 }
1592
1593 static enum action verb_to_action(const char *verb) {
1594         if (streq(verb, "halt"))
1595                 return ACTION_HALT;
1596         else if (streq(verb, "poweroff"))
1597                 return ACTION_POWEROFF;
1598         else if (streq(verb, "reboot"))
1599                 return ACTION_REBOOT;
1600         else if (streq(verb, "kexec"))
1601                 return ACTION_KEXEC;
1602         else if (streq(verb, "rescue"))
1603                 return ACTION_RESCUE;
1604         else if (streq(verb, "emergency"))
1605                 return ACTION_EMERGENCY;
1606         else if (streq(verb, "default"))
1607                 return ACTION_DEFAULT;
1608         else if (streq(verb, "exit"))
1609                 return ACTION_EXIT;
1610         else if (streq(verb, "suspend"))
1611                 return ACTION_SUSPEND;
1612         else if (streq(verb, "hibernate"))
1613                 return ACTION_HIBERNATE;
1614         else
1615                 return ACTION_INVALID;
1616 }
1617
1618 static int start_unit(DBusConnection *bus, char **args) {
1619
1620         static const char * const table[_ACTION_MAX] = {
1621                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1622                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1623                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1624                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1625                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1626                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1627                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1628                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1629                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1630                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1631                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1632                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1633                 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1634                 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
1635         };
1636
1637         int r, ret = 0;
1638         const char *method, *mode, *one_name;
1639         Set *s = NULL;
1640         DBusError error;
1641         char **name;
1642
1643         dbus_error_init(&error);
1644
1645         assert(bus);
1646
1647         ask_password_agent_open_if_enabled();
1648
1649         if (arg_action == ACTION_SYSTEMCTL) {
1650                 method =
1651                         streq(args[0], "stop") ||
1652                         streq(args[0], "condstop")              ? "StopUnit" :
1653                         streq(args[0], "reload")                ? "ReloadUnit" :
1654                         streq(args[0], "restart")               ? "RestartUnit" :
1655
1656                         streq(args[0], "try-restart")           ||
1657                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1658
1659                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1660
1661                         streq(args[0], "reload-or-try-restart") ||
1662                         streq(args[0], "condreload") ||
1663
1664                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1665                                                                   "StartUnit";
1666
1667                 mode =
1668                         (streq(args[0], "isolate") ||
1669                          streq(args[0], "rescue")  ||
1670                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1671
1672                 one_name = table[verb_to_action(args[0])];
1673
1674         } else {
1675                 assert(arg_action < ELEMENTSOF(table));
1676                 assert(table[arg_action]);
1677
1678                 method = "StartUnit";
1679
1680                 mode = (arg_action == ACTION_EMERGENCY ||
1681                         arg_action == ACTION_RESCUE ||
1682                         arg_action == ACTION_RUNLEVEL2 ||
1683                         arg_action == ACTION_RUNLEVEL3 ||
1684                         arg_action == ACTION_RUNLEVEL4 ||
1685                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1686
1687                 one_name = table[arg_action];
1688         }
1689
1690         if (!arg_no_block) {
1691                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1692                         log_error("Could not watch jobs: %s", strerror(-ret));
1693                         goto finish;
1694                 }
1695
1696                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1697                         log_error("Failed to allocate set.");
1698                         ret = -ENOMEM;
1699                         goto finish;
1700                 }
1701         }
1702
1703         if (one_name) {
1704                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1705                         goto finish;
1706         } else {
1707                 STRV_FOREACH(name, args+1)
1708                         if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1709                                 ret = translate_bus_error_to_exit_status(r, &error);
1710                                 dbus_error_free(&error);
1711                         }
1712         }
1713
1714         if (!arg_no_block)
1715                 if ((r = wait_for_jobs(bus, s)) < 0) {
1716                         ret = r;
1717                         goto finish;
1718                 }
1719
1720 finish:
1721         if (s)
1722                 set_free_free(s);
1723
1724         dbus_error_free(&error);
1725
1726         return ret;
1727 }
1728
1729 /* Ask systemd-logind, which might grant access to unprivileged users
1730  * through PolicyKit */
1731 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1732 #ifdef HAVE_LOGIND
1733         const char *method;
1734         DBusMessage *m = NULL, *reply = NULL;
1735         DBusError error;
1736         dbus_bool_t interactive = true;
1737         int r;
1738
1739         dbus_error_init(&error);
1740
1741         polkit_agent_open_if_enabled();
1742
1743         switch (a) {
1744
1745         case ACTION_REBOOT:
1746                 method = "Reboot";
1747                 break;
1748
1749         case ACTION_POWEROFF:
1750                 method = "PowerOff";
1751                 break;
1752
1753         case ACTION_SUSPEND:
1754                 method = "Suspend";
1755                 break;
1756
1757         case ACTION_HIBERNATE:
1758                 method = "Hibernate";
1759                 break;
1760
1761         default:
1762                 return -EINVAL;
1763         }
1764
1765         m = dbus_message_new_method_call(
1766                                 "org.freedesktop.login1",
1767                                 "/org/freedesktop/login1",
1768                                 "org.freedesktop.login1.Manager",
1769                                 method);
1770         if (!m) {
1771                 log_error("Could not allocate message.");
1772                 r = -ENOMEM;
1773                 goto finish;
1774         }
1775
1776         if (!dbus_message_append_args(m,
1777                                       DBUS_TYPE_BOOLEAN, &interactive,
1778                                       DBUS_TYPE_INVALID)) {
1779                 log_error("Could not append arguments to message.");
1780                 r = -ENOMEM;
1781                 goto finish;
1782         }
1783
1784         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1785         if (!reply) {
1786                 if (error_is_no_service(&error)) {
1787                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
1788                         r = -ENOENT;
1789                         goto finish;
1790                 }
1791
1792                 if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
1793                         log_debug("Failed to issue method call: %s", bus_error_message(&error));
1794                         r = -EACCES;
1795                         goto finish;
1796                 }
1797
1798                 log_info("Failed to issue method call: %s", bus_error_message(&error));
1799                 r = -EIO;
1800                 goto finish;
1801         }
1802
1803         r = 0;
1804
1805 finish:
1806         if (m)
1807                 dbus_message_unref(m);
1808
1809         if (reply)
1810                 dbus_message_unref(reply);
1811
1812         dbus_error_free(&error);
1813
1814         return r;
1815 #else
1816         return -ENOSYS;
1817 #endif
1818 }
1819
1820 static int start_special(DBusConnection *bus, char **args) {
1821         enum action a;
1822         int r;
1823
1824         assert(args);
1825
1826         a = verb_to_action(args[0]);
1827
1828         if (arg_force >= 2 && geteuid() != 0) {
1829                 log_error("Must be root.");
1830                 return -EPERM;
1831         }
1832
1833         if (arg_force >= 2 &&
1834             (a == ACTION_HALT ||
1835              a == ACTION_POWEROFF ||
1836              a == ACTION_REBOOT))
1837                 halt_now(a);
1838
1839         if (arg_force >= 1 &&
1840             (a == ACTION_HALT ||
1841              a == ACTION_POWEROFF ||
1842              a == ACTION_REBOOT ||
1843              a == ACTION_KEXEC ||
1844              a == ACTION_EXIT))
1845                 return daemon_reload(bus, args);
1846
1847         /* first try logind, to allow authentication with polkit */
1848         if (geteuid() != 0 &&
1849             (a == ACTION_POWEROFF ||
1850              a == ACTION_REBOOT ||
1851              a == ACTION_SUSPEND ||
1852              a == ACTION_HIBERNATE)) {
1853                 r = reboot_with_logind(bus, a);
1854                 if (r >= 0)
1855                         return r;
1856         }
1857
1858         r = start_unit(bus, args);
1859         if (r >= 0)
1860                 warn_wall(a);
1861
1862         return r;
1863 }
1864
1865 static int check_unit(DBusConnection *bus, char **args) {
1866         DBusMessage *m = NULL, *reply = NULL;
1867         const char
1868                 *interface = "org.freedesktop.systemd1.Unit",
1869                 *property = "ActiveState";
1870         int r = 3; /* According to LSB: "program is not running" */
1871         DBusError error;
1872         char **name;
1873
1874         assert(bus);
1875         assert(args);
1876
1877         dbus_error_init(&error);
1878
1879         STRV_FOREACH(name, args+1) {
1880                 const char *path = NULL;
1881                 const char *state;
1882                 DBusMessageIter iter, sub;
1883
1884                 if (!(m = dbus_message_new_method_call(
1885                                       "org.freedesktop.systemd1",
1886                                       "/org/freedesktop/systemd1",
1887                                       "org.freedesktop.systemd1.Manager",
1888                                       "GetUnit"))) {
1889                         log_error("Could not allocate message.");
1890                         r = -ENOMEM;
1891                         goto finish;
1892                 }
1893
1894                 if (!dbus_message_append_args(m,
1895                                               DBUS_TYPE_STRING, name,
1896                                               DBUS_TYPE_INVALID)) {
1897                         log_error("Could not append arguments to message.");
1898                         r = -ENOMEM;
1899                         goto finish;
1900                 }
1901
1902                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1903
1904                         /* Hmm, cannot figure out anything about this unit... */
1905                         if (!arg_quiet)
1906                                 puts("unknown");
1907
1908                         dbus_error_free(&error);
1909                         dbus_message_unref(m);
1910                         m = NULL;
1911                         continue;
1912                 }
1913
1914                 if (!dbus_message_get_args(reply, &error,
1915                                            DBUS_TYPE_OBJECT_PATH, &path,
1916                                            DBUS_TYPE_INVALID)) {
1917                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1918                         r = -EIO;
1919                         goto finish;
1920                 }
1921
1922                 dbus_message_unref(m);
1923                 if (!(m = dbus_message_new_method_call(
1924                                       "org.freedesktop.systemd1",
1925                                       path,
1926                                       "org.freedesktop.DBus.Properties",
1927                                       "Get"))) {
1928                         log_error("Could not allocate message.");
1929                         r = -ENOMEM;
1930                         goto finish;
1931                 }
1932
1933                 if (!dbus_message_append_args(m,
1934                                               DBUS_TYPE_STRING, &interface,
1935                                               DBUS_TYPE_STRING, &property,
1936                                               DBUS_TYPE_INVALID)) {
1937                         log_error("Could not append arguments to message.");
1938                         r = -ENOMEM;
1939                         goto finish;
1940                 }
1941
1942                 dbus_message_unref(reply);
1943                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1944                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1945                         r = -EIO;
1946                         goto finish;
1947                 }
1948
1949                 if (!dbus_message_iter_init(reply, &iter) ||
1950                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1951                         log_error("Failed to parse reply.");
1952                         r = -EIO;
1953                         goto finish;
1954                 }
1955
1956                 dbus_message_iter_recurse(&iter, &sub);
1957
1958                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1959                         log_error("Failed to parse reply.");
1960                         r = -EIO;
1961                         goto finish;
1962                 }
1963
1964                 dbus_message_iter_get_basic(&sub, &state);
1965
1966                 if (!arg_quiet)
1967                         puts(state);
1968
1969                 if (streq(state, "active") || streq(state, "reloading"))
1970                         r = 0;
1971
1972                 dbus_message_unref(m);
1973                 dbus_message_unref(reply);
1974                 m = reply = NULL;
1975         }
1976
1977 finish:
1978         if (m)
1979                 dbus_message_unref(m);
1980
1981         if (reply)
1982                 dbus_message_unref(reply);
1983
1984         dbus_error_free(&error);
1985
1986         return r;
1987 }
1988
1989 static int kill_unit(DBusConnection *bus, char **args) {
1990         DBusMessage *m = NULL;
1991         int r = 0;
1992         DBusError error;
1993         char **name;
1994
1995         assert(bus);
1996         assert(args);
1997
1998         dbus_error_init(&error);
1999
2000         if (!arg_kill_who)
2001                 arg_kill_who = "all";
2002
2003         if (!arg_kill_mode)
2004                 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
2005
2006         STRV_FOREACH(name, args+1) {
2007                 DBusMessage *reply;
2008
2009                 if (!(m = dbus_message_new_method_call(
2010                                       "org.freedesktop.systemd1",
2011                                       "/org/freedesktop/systemd1",
2012                                       "org.freedesktop.systemd1.Manager",
2013                                       "KillUnit"))) {
2014                         log_error("Could not allocate message.");
2015                         r = -ENOMEM;
2016                         goto finish;
2017                 }
2018
2019                 if (!dbus_message_append_args(m,
2020                                               DBUS_TYPE_STRING, name,
2021                                               DBUS_TYPE_STRING, &arg_kill_who,
2022                                               DBUS_TYPE_STRING, &arg_kill_mode,
2023                                               DBUS_TYPE_INT32, &arg_signal,
2024                                               DBUS_TYPE_INVALID)) {
2025                         log_error("Could not append arguments to message.");
2026                         r = -ENOMEM;
2027                         goto finish;
2028                 }
2029
2030                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2031                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2032                         dbus_error_free(&error);
2033                         r = -EIO;
2034                 }
2035
2036                 dbus_message_unref(m);
2037
2038                 if (reply)
2039                         dbus_message_unref(reply);
2040                 m = reply = NULL;
2041         }
2042
2043 finish:
2044         if (m)
2045                 dbus_message_unref(m);
2046
2047         dbus_error_free(&error);
2048
2049         return r;
2050 }
2051
2052 typedef struct ExecStatusInfo {
2053         char *name;
2054
2055         char *path;
2056         char **argv;
2057
2058         bool ignore;
2059
2060         usec_t start_timestamp;
2061         usec_t exit_timestamp;
2062         pid_t pid;
2063         int code;
2064         int status;
2065
2066         LIST_FIELDS(struct ExecStatusInfo, exec);
2067 } ExecStatusInfo;
2068
2069 static void exec_status_info_free(ExecStatusInfo *i) {
2070         assert(i);
2071
2072         free(i->name);
2073         free(i->path);
2074         strv_free(i->argv);
2075         free(i);
2076 }
2077
2078 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2079         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2080         DBusMessageIter sub2, sub3;
2081         const char*path;
2082         unsigned n;
2083         uint32_t pid;
2084         int32_t code, status;
2085         dbus_bool_t ignore;
2086
2087         assert(i);
2088         assert(i);
2089
2090         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2091                 return -EIO;
2092
2093         dbus_message_iter_recurse(sub, &sub2);
2094
2095         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2096                 return -EIO;
2097
2098         if (!(i->path = strdup(path)))
2099                 return -ENOMEM;
2100
2101         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2102             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2103                 return -EIO;
2104
2105         n = 0;
2106         dbus_message_iter_recurse(&sub2, &sub3);
2107         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2108                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2109                 dbus_message_iter_next(&sub3);
2110                 n++;
2111         }
2112
2113
2114         if (!(i->argv = new0(char*, n+1)))
2115                 return -ENOMEM;
2116
2117         n = 0;
2118         dbus_message_iter_recurse(&sub2, &sub3);
2119         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2120                 const char *s;
2121
2122                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2123                 dbus_message_iter_get_basic(&sub3, &s);
2124                 dbus_message_iter_next(&sub3);
2125
2126                 if (!(i->argv[n++] = strdup(s)))
2127                         return -ENOMEM;
2128         }
2129
2130         if (!dbus_message_iter_next(&sub2) ||
2131             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2132             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2133             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2134             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2135             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2136             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2137             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2138             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2139                 return -EIO;
2140
2141         i->ignore = ignore;
2142         i->start_timestamp = (usec_t) start_timestamp;
2143         i->exit_timestamp = (usec_t) exit_timestamp;
2144         i->pid = (pid_t) pid;
2145         i->code = code;
2146         i->status = status;
2147
2148         return 0;
2149 }
2150
2151 typedef struct UnitStatusInfo {
2152         const char *id;
2153         const char *load_state;
2154         const char *active_state;
2155         const char *sub_state;
2156         const char *unit_file_state;
2157
2158         const char *description;
2159         const char *following;
2160
2161         char **documentation;
2162
2163         const char *path;
2164         const char *default_control_group;
2165
2166         const char *load_error;
2167         const char *result;
2168
2169         usec_t inactive_exit_timestamp;
2170         usec_t inactive_exit_timestamp_monotonic;
2171         usec_t active_enter_timestamp;
2172         usec_t active_exit_timestamp;
2173         usec_t inactive_enter_timestamp;
2174
2175         bool need_daemon_reload;
2176
2177         /* Service */
2178         pid_t main_pid;
2179         pid_t control_pid;
2180         const char *status_text;
2181         bool running:1;
2182 #ifdef HAVE_SYSV_COMPAT
2183         bool is_sysv:1;
2184 #endif
2185
2186         usec_t start_timestamp;
2187         usec_t exit_timestamp;
2188
2189         int exit_code, exit_status;
2190
2191         usec_t condition_timestamp;
2192         bool condition_result;
2193
2194         /* Socket */
2195         unsigned n_accepted;
2196         unsigned n_connections;
2197         bool accept;
2198
2199         /* Device */
2200         const char *sysfs_path;
2201
2202         /* Mount, Automount */
2203         const char *where;
2204
2205         /* Swap */
2206         const char *what;
2207
2208         LIST_HEAD(ExecStatusInfo, exec);
2209 } UnitStatusInfo;
2210
2211 static void print_status_info(UnitStatusInfo *i) {
2212         ExecStatusInfo *p;
2213         const char *on, *off, *ss;
2214         usec_t timestamp;
2215         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2216         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2217
2218         assert(i);
2219
2220         /* This shows pretty information about a unit. See
2221          * print_property() for a low-level property printer */
2222
2223         printf("%s", strna(i->id));
2224
2225         if (i->description && !streq_ptr(i->id, i->description))
2226                 printf(" - %s", i->description);
2227
2228         printf("\n");
2229
2230         if (i->following)
2231                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2232
2233         if (streq_ptr(i->load_state, "error")) {
2234                 on = ansi_highlight_red(true);
2235                 off = ansi_highlight_red(false);
2236         } else
2237                 on = off = "";
2238
2239         if (i->load_error)
2240                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2241         else if (i->path && i->unit_file_state)
2242                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state);
2243         else if (i->path)
2244                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
2245         else
2246                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2247
2248         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2249
2250         if (streq_ptr(i->active_state, "failed")) {
2251                 on = ansi_highlight_red(true);
2252                 off = ansi_highlight_red(false);
2253         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2254                 on = ansi_highlight_green(true);
2255                 off = ansi_highlight_green(false);
2256         } else
2257                 on = off = "";
2258
2259         if (ss)
2260                 printf("\t  Active: %s%s (%s)%s",
2261                        on,
2262                        strna(i->active_state),
2263                        ss,
2264                        off);
2265         else
2266                 printf("\t  Active: %s%s%s",
2267                        on,
2268                        strna(i->active_state),
2269                        off);
2270
2271         if (!isempty(i->result) && !streq(i->result, "success"))
2272                 printf(" (Result: %s)", i->result);
2273
2274         timestamp = (streq_ptr(i->active_state, "active")      ||
2275                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2276                     (streq_ptr(i->active_state, "inactive")    ||
2277                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2278                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2279                                                                   i->active_exit_timestamp;
2280
2281         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2282         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2283
2284         if (s1)
2285                 printf(" since %s; %s\n", s2, s1);
2286         else if (s2)
2287                 printf(" since %s\n", s2);
2288         else
2289                 printf("\n");
2290
2291         if (!i->condition_result && i->condition_timestamp > 0) {
2292                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2293                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2294
2295                 if (s1)
2296                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2297                 else if (s2)
2298                         printf("\t          start condition failed at %s\n", s2);
2299         }
2300
2301         if (i->sysfs_path)
2302                 printf("\t  Device: %s\n", i->sysfs_path);
2303         if (i->where)
2304                 printf("\t   Where: %s\n", i->where);
2305         if (i->what)
2306                 printf("\t    What: %s\n", i->what);
2307
2308         if (!strv_isempty(i->documentation)) {
2309                 char **t;
2310                 bool first = true;
2311
2312                 STRV_FOREACH(t, i->documentation) {
2313                         if (first) {
2314                                 printf("\t    Docs: %s\n", *t);
2315                                 first = false;
2316                         } else
2317                                 printf("\t          %s\n", *t);
2318                 }
2319         }
2320
2321         if (i->accept)
2322                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2323
2324         LIST_FOREACH(exec, p, i->exec) {
2325                 char *t;
2326                 bool good;
2327
2328                 /* Only show exited processes here */
2329                 if (p->code == 0)
2330                         continue;
2331
2332                 t = strv_join(p->argv, " ");
2333                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2334                 free(t);
2335
2336 #ifdef HAVE_SYSV_COMPAT
2337                 if (i->is_sysv)
2338                         good = is_clean_exit_lsb(p->code, p->status);
2339                 else
2340 #endif
2341                         good = is_clean_exit(p->code, p->status);
2342
2343                 if (!good) {
2344                         on = ansi_highlight_red(true);
2345                         off = ansi_highlight_red(false);
2346                 } else
2347                         on = off = "";
2348
2349                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2350
2351                 if (p->code == CLD_EXITED) {
2352                         const char *c;
2353
2354                         printf("status=%i", p->status);
2355
2356 #ifdef HAVE_SYSV_COMPAT
2357                         if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2358 #else
2359                         if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
2360 #endif
2361                                 printf("/%s", c);
2362
2363                 } else
2364                         printf("signal=%s", signal_to_string(p->status));
2365
2366                 printf(")%s\n", off);
2367
2368                 if (i->main_pid == p->pid &&
2369                     i->start_timestamp == p->start_timestamp &&
2370                     i->exit_timestamp == p->start_timestamp)
2371                         /* Let's not show this twice */
2372                         i->main_pid = 0;
2373
2374                 if (p->pid == i->control_pid)
2375                         i->control_pid = 0;
2376         }
2377
2378         if (i->main_pid > 0 || i->control_pid > 0) {
2379                 printf("\t");
2380
2381                 if (i->main_pid > 0) {
2382                         printf("Main PID: %u", (unsigned) i->main_pid);
2383
2384                         if (i->running) {
2385                                 char *t = NULL;
2386                                 get_process_comm(i->main_pid, &t);
2387                                 if (t) {
2388                                         printf(" (%s)", t);
2389                                         free(t);
2390                                 }
2391                         } else if (i->exit_code > 0) {
2392                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2393
2394                                 if (i->exit_code == CLD_EXITED) {
2395                                         const char *c;
2396
2397                                         printf("status=%i", i->exit_status);
2398
2399 #ifdef HAVE_SYSV_COMPAT
2400                                         if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2401 #else
2402                                         if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
2403 #endif
2404                                                 printf("/%s", c);
2405
2406                                 } else
2407                                         printf("signal=%s", signal_to_string(i->exit_status));
2408                                 printf(")");
2409                         }
2410                 }
2411
2412                 if (i->main_pid > 0 && i->control_pid > 0)
2413                         printf(";");
2414
2415                 if (i->control_pid > 0) {
2416                         char *t = NULL;
2417
2418                         printf(" Control: %u", (unsigned) i->control_pid);
2419
2420                         get_process_comm(i->control_pid, &t);
2421                         if (t) {
2422                                 printf(" (%s)", t);
2423                                 free(t);
2424                         }
2425                 }
2426
2427                 printf("\n");
2428         }
2429
2430         if (i->status_text)
2431                 printf("\t  Status: \"%s\"\n", i->status_text);
2432
2433         if (i->default_control_group) {
2434                 unsigned c;
2435
2436                 printf("\t  CGroup: %s\n", i->default_control_group);
2437
2438                 if (arg_transport != TRANSPORT_SSH) {
2439                         unsigned k = 0;
2440                         pid_t extra[2];
2441
2442                         c = columns();
2443                         if (c > 18)
2444                                 c -= 18;
2445                         else
2446                                 c = 0;
2447
2448                         if (i->main_pid > 0)
2449                                 extra[k++] = i->main_pid;
2450
2451                         if (i->control_pid > 0)
2452                                 extra[k++] = i->control_pid;
2453
2454                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2455                 }
2456         }
2457
2458         if (i->id && arg_transport != TRANSPORT_SSH) {
2459                 printf("\n");
2460                 show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
2461         }
2462
2463         if (i->need_daemon_reload)
2464                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2465                        ansi_highlight_red(true),
2466                        ansi_highlight_red(false),
2467                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2468 }
2469
2470 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2471
2472         assert(name);
2473         assert(iter);
2474         assert(i);
2475
2476         switch (dbus_message_iter_get_arg_type(iter)) {
2477
2478         case DBUS_TYPE_STRING: {
2479                 const char *s;
2480
2481                 dbus_message_iter_get_basic(iter, &s);
2482
2483                 if (!isempty(s)) {
2484                         if (streq(name, "Id"))
2485                                 i->id = s;
2486                         else if (streq(name, "LoadState"))
2487                                 i->load_state = s;
2488                         else if (streq(name, "ActiveState"))
2489                                 i->active_state = s;
2490                         else if (streq(name, "SubState"))
2491                                 i->sub_state = s;
2492                         else if (streq(name, "Description"))
2493                                 i->description = s;
2494                         else if (streq(name, "FragmentPath"))
2495                                 i->path = s;
2496 #ifdef HAVE_SYSV_COMPAT
2497                         else if (streq(name, "SysVPath")) {
2498                                 i->is_sysv = true;
2499                                 i->path = s;
2500                         }
2501 #endif
2502                         else if (streq(name, "DefaultControlGroup"))
2503                                 i->default_control_group = s;
2504                         else if (streq(name, "StatusText"))
2505                                 i->status_text = s;
2506                         else if (streq(name, "SysFSPath"))
2507                                 i->sysfs_path = s;
2508                         else if (streq(name, "Where"))
2509                                 i->where = s;
2510                         else if (streq(name, "What"))
2511                                 i->what = s;
2512                         else if (streq(name, "Following"))
2513                                 i->following = s;
2514                         else if (streq(name, "UnitFileState"))
2515                                 i->unit_file_state = s;
2516                         else if (streq(name, "Result"))
2517                                 i->result = s;
2518                 }
2519
2520                 break;
2521         }
2522
2523         case DBUS_TYPE_BOOLEAN: {
2524                 dbus_bool_t b;
2525
2526                 dbus_message_iter_get_basic(iter, &b);
2527
2528                 if (streq(name, "Accept"))
2529                         i->accept = b;
2530                 else if (streq(name, "NeedDaemonReload"))
2531                         i->need_daemon_reload = b;
2532                 else if (streq(name, "ConditionResult"))
2533                         i->condition_result = b;
2534
2535                 break;
2536         }
2537
2538         case DBUS_TYPE_UINT32: {
2539                 uint32_t u;
2540
2541                 dbus_message_iter_get_basic(iter, &u);
2542
2543                 if (streq(name, "MainPID")) {
2544                         if (u > 0) {
2545                                 i->main_pid = (pid_t) u;
2546                                 i->running = true;
2547                         }
2548                 } else if (streq(name, "ControlPID"))
2549                         i->control_pid = (pid_t) u;
2550                 else if (streq(name, "ExecMainPID")) {
2551                         if (u > 0)
2552                                 i->main_pid = (pid_t) u;
2553                 } else if (streq(name, "NAccepted"))
2554                         i->n_accepted = u;
2555                 else if (streq(name, "NConnections"))
2556                         i->n_connections = u;
2557
2558                 break;
2559         }
2560
2561         case DBUS_TYPE_INT32: {
2562                 int32_t j;
2563
2564                 dbus_message_iter_get_basic(iter, &j);
2565
2566                 if (streq(name, "ExecMainCode"))
2567                         i->exit_code = (int) j;
2568                 else if (streq(name, "ExecMainStatus"))
2569                         i->exit_status = (int) j;
2570
2571                 break;
2572         }
2573
2574         case DBUS_TYPE_UINT64: {
2575                 uint64_t u;
2576
2577                 dbus_message_iter_get_basic(iter, &u);
2578
2579                 if (streq(name, "ExecMainStartTimestamp"))
2580                         i->start_timestamp = (usec_t) u;
2581                 else if (streq(name, "ExecMainExitTimestamp"))
2582                         i->exit_timestamp = (usec_t) u;
2583                 else if (streq(name, "ActiveEnterTimestamp"))
2584                         i->active_enter_timestamp = (usec_t) u;
2585                 else if (streq(name, "InactiveEnterTimestamp"))
2586                         i->inactive_enter_timestamp = (usec_t) u;
2587                 else if (streq(name, "InactiveExitTimestamp"))
2588                         i->inactive_exit_timestamp = (usec_t) u;
2589                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2590                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2591                 else if (streq(name, "ActiveExitTimestamp"))
2592                         i->active_exit_timestamp = (usec_t) u;
2593                 else if (streq(name, "ConditionTimestamp"))
2594                         i->condition_timestamp = (usec_t) u;
2595
2596                 break;
2597         }
2598
2599         case DBUS_TYPE_ARRAY: {
2600
2601                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2602                     startswith(name, "Exec")) {
2603                         DBusMessageIter sub;
2604
2605                         dbus_message_iter_recurse(iter, &sub);
2606                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2607                                 ExecStatusInfo *info;
2608                                 int r;
2609
2610                                 if (!(info = new0(ExecStatusInfo, 1)))
2611                                         return -ENOMEM;
2612
2613                                 if (!(info->name = strdup(name))) {
2614                                         free(info);
2615                                         return -ENOMEM;
2616                                 }
2617
2618                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2619                                         free(info);
2620                                         return r;
2621                                 }
2622
2623                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2624
2625                                 dbus_message_iter_next(&sub);
2626                         }
2627                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2628                            streq(name, "Documentation")) {
2629
2630                         DBusMessageIter sub;
2631
2632                         dbus_message_iter_recurse(iter, &sub);
2633                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2634                                 const char *s;
2635                                 char **l;
2636
2637                                 dbus_message_iter_get_basic(&sub, &s);
2638
2639                                 l = strv_append(i->documentation, s);
2640                                 if (!l)
2641                                         return -ENOMEM;
2642
2643                                 strv_free(i->documentation);
2644                                 i->documentation = l;
2645
2646                                 dbus_message_iter_next(&sub);
2647                         }
2648                 }
2649
2650                 break;
2651         }
2652
2653         case DBUS_TYPE_STRUCT: {
2654
2655                 if (streq(name, "LoadError")) {
2656                         DBusMessageIter sub;
2657                         const char *n, *message;
2658                         int r;
2659
2660                         dbus_message_iter_recurse(iter, &sub);
2661
2662                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2663                         if (r < 0)
2664                                 return r;
2665
2666                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2667                         if (r < 0)
2668                                 return r;
2669
2670                         if (!isempty(message))
2671                                 i->load_error = message;
2672                 }
2673
2674                 break;
2675         }
2676         }
2677
2678         return 0;
2679 }
2680
2681 static int print_property(const char *name, DBusMessageIter *iter) {
2682         assert(name);
2683         assert(iter);
2684
2685         /* This is a low-level property printer, see
2686          * print_status_info() for the nicer output */
2687
2688         if (arg_property && !strv_find(arg_property, name))
2689                 return 0;
2690
2691         switch (dbus_message_iter_get_arg_type(iter)) {
2692
2693         case DBUS_TYPE_STRUCT: {
2694                 DBusMessageIter sub;
2695                 dbus_message_iter_recurse(iter, &sub);
2696
2697                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2698                         uint32_t u;
2699
2700                         dbus_message_iter_get_basic(&sub, &u);
2701
2702                         if (u)
2703                                 printf("%s=%u\n", name, (unsigned) u);
2704                         else if (arg_all)
2705                                 printf("%s=\n", name);
2706
2707                         return 0;
2708                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2709                         const char *s;
2710
2711                         dbus_message_iter_get_basic(&sub, &s);
2712
2713                         if (arg_all || s[0])
2714                                 printf("%s=%s\n", name, s);
2715
2716                         return 0;
2717                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2718                         const char *a = NULL, *b = NULL;
2719
2720                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2721                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2722
2723                         if (arg_all || !isempty(a) || !isempty(b))
2724                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2725
2726                         return 0;
2727                 }
2728
2729                 break;
2730         }
2731
2732         case DBUS_TYPE_ARRAY:
2733
2734                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2735                         DBusMessageIter sub, sub2;
2736
2737                         dbus_message_iter_recurse(iter, &sub);
2738                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2739                                 const char *path;
2740                                 dbus_bool_t ignore;
2741
2742                                 dbus_message_iter_recurse(&sub, &sub2);
2743
2744                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2745                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2746                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2747
2748                                 dbus_message_iter_next(&sub);
2749                         }
2750
2751                         return 0;
2752
2753                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2754                         DBusMessageIter sub, sub2;
2755
2756                         dbus_message_iter_recurse(iter, &sub);
2757                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2758                                 const char *type, *path;
2759
2760                                 dbus_message_iter_recurse(&sub, &sub2);
2761
2762                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2763                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2764                                         printf("%s=%s\n", type, path);
2765
2766                                 dbus_message_iter_next(&sub);
2767                         }
2768
2769                         return 0;
2770
2771                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2772                         DBusMessageIter sub, sub2;
2773
2774                         dbus_message_iter_recurse(iter, &sub);
2775                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2776                                 const char *base;
2777                                 uint64_t value, next_elapse;
2778
2779                                 dbus_message_iter_recurse(&sub, &sub2);
2780
2781                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2782                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2783                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2784                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2785
2786                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2787                                                base,
2788                                                format_timespan(timespan1, sizeof(timespan1), value),
2789                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2790                                 }
2791
2792                                 dbus_message_iter_next(&sub);
2793                         }
2794
2795                         return 0;
2796
2797                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2798                         DBusMessageIter sub, sub2;
2799
2800                         dbus_message_iter_recurse(iter, &sub);
2801                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2802                                 const char *controller, *attr, *value;
2803
2804                                 dbus_message_iter_recurse(&sub, &sub2);
2805
2806                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2807                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2808                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2809
2810                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2811                                                controller,
2812                                                attr,
2813                                                value);
2814                                 }
2815
2816                                 dbus_message_iter_next(&sub);
2817                         }
2818
2819                         return 0;
2820
2821                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2822                         DBusMessageIter sub;
2823
2824                         dbus_message_iter_recurse(iter, &sub);
2825                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2826                                 ExecStatusInfo info;
2827
2828                                 zero(info);
2829                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2830                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2831                                         char *t;
2832
2833                                         t = strv_join(info.argv, " ");
2834
2835                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2836                                                name,
2837                                                strna(info.path),
2838                                                strna(t),
2839                                                yes_no(info.ignore),
2840                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2841                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2842                                                (unsigned) info. pid,
2843                                                sigchld_code_to_string(info.code),
2844                                                info.status,
2845                                                info.code == CLD_EXITED ? "" : "/",
2846                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2847
2848                                         free(t);
2849                                 }
2850
2851                                 free(info.path);
2852                                 strv_free(info.argv);
2853
2854                                 dbus_message_iter_next(&sub);
2855                         }
2856
2857                         return 0;
2858                 }
2859
2860                 break;
2861         }
2862
2863         if (generic_print_property(name, iter, arg_all) > 0)
2864                 return 0;
2865
2866         if (arg_all)
2867                 printf("%s=[unprintable]\n", name);
2868
2869         return 0;
2870 }
2871
2872 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2873         DBusMessage *m = NULL, *reply = NULL;
2874         const char *interface = "";
2875         int r;
2876         DBusError error;
2877         DBusMessageIter iter, sub, sub2, sub3;
2878         UnitStatusInfo info;
2879         ExecStatusInfo *p;
2880
2881         assert(bus);
2882         assert(path);
2883         assert(new_line);
2884
2885         zero(info);
2886         dbus_error_init(&error);
2887
2888         if (!(m = dbus_message_new_method_call(
2889                               "org.freedesktop.systemd1",
2890                               path,
2891                               "org.freedesktop.DBus.Properties",
2892                               "GetAll"))) {
2893                 log_error("Could not allocate message.");
2894                 r = -ENOMEM;
2895                 goto finish;
2896         }
2897
2898         if (!dbus_message_append_args(m,
2899                                       DBUS_TYPE_STRING, &interface,
2900                                       DBUS_TYPE_INVALID)) {
2901                 log_error("Could not append arguments to message.");
2902                 r = -ENOMEM;
2903                 goto finish;
2904         }
2905
2906         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2907                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2908                 r = -EIO;
2909                 goto finish;
2910         }
2911
2912         if (!dbus_message_iter_init(reply, &iter) ||
2913             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2914             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2915                 log_error("Failed to parse reply.");
2916                 r = -EIO;
2917                 goto finish;
2918         }
2919
2920         dbus_message_iter_recurse(&iter, &sub);
2921
2922         if (*new_line)
2923                 printf("\n");
2924
2925         *new_line = true;
2926
2927         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2928                 const char *name;
2929
2930                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2931                         log_error("Failed to parse reply.");
2932                         r = -EIO;
2933                         goto finish;
2934                 }
2935
2936                 dbus_message_iter_recurse(&sub, &sub2);
2937
2938                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2939                         log_error("Failed to parse reply.");
2940                         r = -EIO;
2941                         goto finish;
2942                 }
2943
2944                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2945                         log_error("Failed to parse reply.");
2946                         r = -EIO;
2947                         goto finish;
2948                 }
2949
2950                 dbus_message_iter_recurse(&sub2, &sub3);
2951
2952                 if (show_properties)
2953                         r = print_property(name, &sub3);
2954                 else
2955                         r = status_property(name, &sub3, &info);
2956
2957                 if (r < 0) {
2958                         log_error("Failed to parse reply.");
2959                         r = -EIO;
2960                         goto finish;
2961                 }
2962
2963                 dbus_message_iter_next(&sub);
2964         }
2965
2966         r = 0;
2967
2968         if (!show_properties)
2969                 print_status_info(&info);
2970
2971         strv_free(info.documentation);
2972
2973         if (!streq_ptr(info.active_state, "active") &&
2974             !streq_ptr(info.active_state, "reloading") &&
2975             streq(verb, "status"))
2976                 /* According to LSB: "program not running" */
2977                 r = 3;
2978
2979         while ((p = info.exec)) {
2980                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2981                 exec_status_info_free(p);
2982         }
2983
2984 finish:
2985         if (m)
2986                 dbus_message_unref(m);
2987
2988         if (reply)
2989                 dbus_message_unref(reply);
2990
2991         dbus_error_free(&error);
2992
2993         return r;
2994 }
2995
2996 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
2997         DBusMessage *m = NULL, *reply = NULL;
2998         const char *path = NULL;
2999         DBusError error;
3000         int r;
3001
3002         dbus_error_init(&error);
3003
3004         m = dbus_message_new_method_call(
3005                               "org.freedesktop.systemd1",
3006                               "/org/freedesktop/systemd1",
3007                               "org.freedesktop.systemd1.Manager",
3008                               "GetUnitByPID");
3009         if (!m) {
3010                 log_error("Could not allocate message.");
3011                 r = -ENOMEM;
3012                 goto finish;
3013         }
3014
3015         if (!dbus_message_append_args(m,
3016                                       DBUS_TYPE_UINT32, &pid,
3017                                       DBUS_TYPE_INVALID)) {
3018                 log_error("Could not append arguments to message.");
3019                 r = -ENOMEM;
3020                 goto finish;
3021         }
3022
3023         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3024         if (!reply) {
3025                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3026                 r = -EIO;
3027                 goto finish;
3028         }
3029
3030         if (!dbus_message_get_args(reply, &error,
3031                                    DBUS_TYPE_OBJECT_PATH, &path,
3032                                    DBUS_TYPE_INVALID)) {
3033                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3034                 r = -EIO;
3035                 goto finish;
3036         }
3037
3038         r = show_one(verb, bus, path, false, new_line);
3039
3040 finish:
3041         if (m)
3042                 dbus_message_unref(m);
3043
3044         if (reply)
3045                 dbus_message_unref(reply);
3046
3047         dbus_error_free(&error);
3048
3049         return r;
3050 }
3051
3052 static int show(DBusConnection *bus, char **args) {
3053         int r, ret = 0;
3054         bool show_properties, new_line = false;
3055         char **name;
3056
3057         assert(bus);
3058         assert(args);
3059
3060         show_properties = !streq(args[0], "status");
3061
3062         if (show_properties)
3063                 pager_open_if_enabled();
3064
3065         if (show_properties && strv_length(args) <= 1) {
3066                 /* If not argument is specified inspect the manager
3067                  * itself */
3068
3069                 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
3070         }
3071
3072         STRV_FOREACH(name, args+1) {
3073                 uint32_t id;
3074
3075                 if (safe_atou32(*name, &id) < 0) {
3076
3077                         /* Interpret as unit name */
3078
3079                         char *e, *p;
3080                         e = bus_path_escape(*name);
3081                         if (!e)
3082                                 return -ENOMEM;
3083                         p = strappend("/org/freedesktop/systemd1/unit/", e);
3084                         free(e);
3085                         if (!p)
3086                                 return -ENOMEM;
3087
3088                         r = show_one(args[0], bus, p, show_properties, &new_line);
3089                         free(p);
3090
3091                         if (r != 0)
3092                                 ret = r;
3093
3094                 } else if (show_properties) {
3095
3096                         /* Interpret as job id */
3097
3098                         char *p;
3099                         if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3100                                 return -ENOMEM;
3101
3102                         r = show_one(args[0], bus, p, show_properties, &new_line);
3103                         free(p);
3104
3105                         if (r != 0)
3106                                 ret = r;
3107
3108                 } else {
3109
3110                         /* Interpret as PID */
3111
3112                         r = show_one_by_pid(args[0], bus, id, &new_line);
3113                         if (r != 0)
3114                                 ret = r;
3115                 }
3116         }
3117
3118         return ret;
3119 }
3120
3121 static int dump(DBusConnection *bus, char **args) {
3122         DBusMessage *m = NULL, *reply = NULL;
3123         DBusError error;
3124         int r;
3125         const char *text;
3126
3127         dbus_error_init(&error);
3128
3129         pager_open_if_enabled();
3130
3131         if (!(m = dbus_message_new_method_call(
3132                               "org.freedesktop.systemd1",
3133                               "/org/freedesktop/systemd1",
3134                               "org.freedesktop.systemd1.Manager",
3135                               "Dump"))) {
3136                 log_error("Could not allocate message.");
3137                 return -ENOMEM;
3138         }
3139
3140         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3141                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3142                 r = -EIO;
3143                 goto finish;
3144         }
3145
3146         if (!dbus_message_get_args(reply, &error,
3147                                    DBUS_TYPE_STRING, &text,
3148                                    DBUS_TYPE_INVALID)) {
3149                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3150                 r = -EIO;
3151                 goto finish;
3152         }
3153
3154         fputs(text, stdout);
3155
3156         r = 0;
3157
3158 finish:
3159         if (m)
3160                 dbus_message_unref(m);
3161
3162         if (reply)
3163                 dbus_message_unref(reply);
3164
3165         dbus_error_free(&error);
3166
3167         return r;
3168 }
3169
3170 static int snapshot(DBusConnection *bus, char **args) {
3171         DBusMessage *m = NULL, *reply = NULL;
3172         DBusError error;
3173         int r;
3174         const char *name = "", *path, *id;
3175         dbus_bool_t cleanup = FALSE;
3176         DBusMessageIter iter, sub;
3177         const char
3178                 *interface = "org.freedesktop.systemd1.Unit",
3179                 *property = "Id";
3180
3181         dbus_error_init(&error);
3182
3183         if (!(m = dbus_message_new_method_call(
3184                               "org.freedesktop.systemd1",
3185                               "/org/freedesktop/systemd1",
3186                               "org.freedesktop.systemd1.Manager",
3187                               "CreateSnapshot"))) {
3188                 log_error("Could not allocate message.");
3189                 return -ENOMEM;
3190         }
3191
3192         if (strv_length(args) > 1)
3193                 name = args[1];
3194
3195         if (!dbus_message_append_args(m,
3196                                       DBUS_TYPE_STRING, &name,
3197                                       DBUS_TYPE_BOOLEAN, &cleanup,
3198                                       DBUS_TYPE_INVALID)) {
3199                 log_error("Could not append arguments to message.");
3200                 r = -ENOMEM;
3201                 goto finish;
3202         }
3203
3204         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3205                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3206                 r = -EIO;
3207                 goto finish;
3208         }
3209
3210         if (!dbus_message_get_args(reply, &error,
3211                                    DBUS_TYPE_OBJECT_PATH, &path,
3212                                    DBUS_TYPE_INVALID)) {
3213                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3214                 r = -EIO;
3215                 goto finish;
3216         }
3217
3218         dbus_message_unref(m);
3219         if (!(m = dbus_message_new_method_call(
3220                               "org.freedesktop.systemd1",
3221                               path,
3222                               "org.freedesktop.DBus.Properties",
3223                               "Get"))) {
3224                 log_error("Could not allocate message.");
3225                 return -ENOMEM;
3226         }
3227
3228         if (!dbus_message_append_args(m,
3229                                       DBUS_TYPE_STRING, &interface,
3230                                       DBUS_TYPE_STRING, &property,
3231                                       DBUS_TYPE_INVALID)) {
3232                 log_error("Could not append arguments to message.");
3233                 r = -ENOMEM;
3234                 goto finish;
3235         }
3236
3237         dbus_message_unref(reply);
3238         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3239                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3240                 r = -EIO;
3241                 goto finish;
3242         }
3243
3244         if (!dbus_message_iter_init(reply, &iter) ||
3245             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3246                 log_error("Failed to parse reply.");
3247                 r = -EIO;
3248                 goto finish;
3249         }
3250
3251         dbus_message_iter_recurse(&iter, &sub);
3252
3253         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3254                 log_error("Failed to parse reply.");
3255                 r = -EIO;
3256                 goto finish;
3257         }
3258
3259         dbus_message_iter_get_basic(&sub, &id);
3260
3261         if (!arg_quiet)
3262                 puts(id);
3263         r = 0;
3264
3265 finish:
3266         if (m)
3267                 dbus_message_unref(m);
3268
3269         if (reply)
3270                 dbus_message_unref(reply);
3271
3272         dbus_error_free(&error);
3273
3274         return r;
3275 }
3276
3277 static int delete_snapshot(DBusConnection *bus, char **args) {
3278         DBusMessage *m = NULL, *reply = NULL;
3279         int r;
3280         DBusError error;
3281         char **name;
3282
3283         assert(bus);
3284         assert(args);
3285
3286         dbus_error_init(&error);
3287
3288         STRV_FOREACH(name, args+1) {
3289                 const char *path = NULL;
3290
3291                 if (!(m = dbus_message_new_method_call(
3292                                       "org.freedesktop.systemd1",
3293                                       "/org/freedesktop/systemd1",
3294                                       "org.freedesktop.systemd1.Manager",
3295                                       "GetUnit"))) {
3296                         log_error("Could not allocate message.");
3297                         r = -ENOMEM;
3298                         goto finish;
3299                 }
3300
3301                 if (!dbus_message_append_args(m,
3302                                               DBUS_TYPE_STRING, name,
3303                                               DBUS_TYPE_INVALID)) {
3304                         log_error("Could not append arguments to message.");
3305                         r = -ENOMEM;
3306                         goto finish;
3307                 }
3308
3309                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3310                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3311                         r = -EIO;
3312                         goto finish;
3313                 }
3314
3315                 if (!dbus_message_get_args(reply, &error,
3316                                            DBUS_TYPE_OBJECT_PATH, &path,
3317                                            DBUS_TYPE_INVALID)) {
3318                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3319                         r = -EIO;
3320                         goto finish;
3321                 }
3322
3323                 dbus_message_unref(m);
3324                 if (!(m = dbus_message_new_method_call(
3325                                       "org.freedesktop.systemd1",
3326                                       path,
3327                                       "org.freedesktop.systemd1.Snapshot",
3328                                       "Remove"))) {
3329                         log_error("Could not allocate message.");
3330                         r = -ENOMEM;
3331                         goto finish;
3332                 }
3333
3334                 dbus_message_unref(reply);
3335                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3336                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3337                         r = -EIO;
3338                         goto finish;
3339                 }
3340
3341                 dbus_message_unref(m);
3342                 dbus_message_unref(reply);
3343                 m = reply = NULL;
3344         }
3345
3346         r = 0;
3347
3348 finish:
3349         if (m)
3350                 dbus_message_unref(m);
3351
3352         if (reply)
3353                 dbus_message_unref(reply);
3354
3355         dbus_error_free(&error);
3356
3357         return r;
3358 }
3359
3360 static int daemon_reload(DBusConnection *bus, char **args) {
3361         DBusMessage *m = NULL, *reply = NULL;
3362         DBusError error;
3363         int r;
3364         const char *method;
3365
3366         dbus_error_init(&error);
3367
3368         if (arg_action == ACTION_RELOAD)
3369                 method = "Reload";
3370         else if (arg_action == ACTION_REEXEC)
3371                 method = "Reexecute";
3372         else {
3373                 assert(arg_action == ACTION_SYSTEMCTL);
3374
3375                 method =
3376                         streq(args[0], "clear-jobs")    ||
3377                         streq(args[0], "cancel")        ? "ClearJobs" :
3378                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3379                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3380                         streq(args[0], "halt")          ? "Halt" :
3381                         streq(args[0], "poweroff")      ? "PowerOff" :
3382                         streq(args[0], "reboot")        ? "Reboot" :
3383                         streq(args[0], "kexec")         ? "KExec" :
3384                         streq(args[0], "exit")          ? "Exit" :
3385                                     /* "daemon-reload" */ "Reload";
3386         }
3387
3388         if (!(m = dbus_message_new_method_call(
3389                               "org.freedesktop.systemd1",
3390                               "/org/freedesktop/systemd1",
3391                               "org.freedesktop.systemd1.Manager",
3392                               method))) {
3393                 log_error("Could not allocate message.");
3394                 return -ENOMEM;
3395         }
3396
3397         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3398
3399                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3400                         /* There's always a fallback possible for
3401                          * legacy actions. */
3402                         r = -EADDRNOTAVAIL;
3403                         goto finish;
3404                 }
3405
3406                 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3407                         /* On reexecution, we expect a disconnect, not
3408                          * a reply */
3409                         r = 0;
3410                         goto finish;
3411                 }
3412
3413                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3414                 r = -EIO;
3415                 goto finish;
3416         }
3417
3418         r = 0;
3419
3420 finish:
3421         if (m)
3422                 dbus_message_unref(m);
3423
3424         if (reply)
3425                 dbus_message_unref(reply);
3426
3427         dbus_error_free(&error);
3428
3429         return r;
3430 }
3431
3432 static int reset_failed(DBusConnection *bus, char **args) {
3433         DBusMessage *m = NULL;
3434         int r;
3435         DBusError error;
3436         char **name;
3437
3438         assert(bus);
3439         dbus_error_init(&error);
3440
3441         if (strv_length(args) <= 1)
3442                 return daemon_reload(bus, args);
3443
3444         STRV_FOREACH(name, args+1) {
3445                 DBusMessage *reply;
3446
3447                 if (!(m = dbus_message_new_method_call(
3448                                       "org.freedesktop.systemd1",
3449                                       "/org/freedesktop/systemd1",
3450                                       "org.freedesktop.systemd1.Manager",
3451                                       "ResetFailedUnit"))) {
3452                         log_error("Could not allocate message.");
3453                         r = -ENOMEM;
3454                         goto finish;
3455                 }
3456
3457                 if (!dbus_message_append_args(m,
3458                                               DBUS_TYPE_STRING, name,
3459                                               DBUS_TYPE_INVALID)) {
3460                         log_error("Could not append arguments to message.");
3461                         r = -ENOMEM;
3462                         goto finish;
3463                 }
3464
3465                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3466                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3467                         r = -EIO;
3468                         goto finish;
3469                 }
3470
3471                 dbus_message_unref(m);
3472                 dbus_message_unref(reply);
3473                 m = reply = NULL;
3474         }
3475
3476         r = 0;
3477
3478 finish:
3479         if (m)
3480                 dbus_message_unref(m);
3481
3482         dbus_error_free(&error);
3483
3484         return r;
3485 }
3486
3487 static int show_enviroment(DBusConnection *bus, char **args) {
3488         DBusMessage *m = NULL, *reply = NULL;
3489         DBusError error;
3490         DBusMessageIter iter, sub, sub2;
3491         int r;
3492         const char
3493                 *interface = "org.freedesktop.systemd1.Manager",
3494                 *property = "Environment";
3495
3496         dbus_error_init(&error);
3497
3498         pager_open_if_enabled();
3499
3500         if (!(m = dbus_message_new_method_call(
3501                               "org.freedesktop.systemd1",
3502                               "/org/freedesktop/systemd1",
3503                               "org.freedesktop.DBus.Properties",
3504                               "Get"))) {
3505                 log_error("Could not allocate message.");
3506                 return -ENOMEM;
3507         }
3508
3509         if (!dbus_message_append_args(m,
3510                                       DBUS_TYPE_STRING, &interface,
3511                                       DBUS_TYPE_STRING, &property,
3512                                       DBUS_TYPE_INVALID)) {
3513                 log_error("Could not append arguments to message.");
3514                 r = -ENOMEM;
3515                 goto finish;
3516         }
3517
3518         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3519                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3520                 r = -EIO;
3521                 goto finish;
3522         }
3523
3524         if (!dbus_message_iter_init(reply, &iter) ||
3525             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3526                 log_error("Failed to parse reply.");
3527                 r = -EIO;
3528                 goto finish;
3529         }
3530
3531         dbus_message_iter_recurse(&iter, &sub);
3532
3533         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3534             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3535                 log_error("Failed to parse reply.");
3536                 r = -EIO;
3537                 goto finish;
3538         }
3539
3540         dbus_message_iter_recurse(&sub, &sub2);
3541
3542         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3543                 const char *text;
3544
3545                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3546                         log_error("Failed to parse reply.");
3547                         r = -EIO;
3548                         goto finish;
3549                 }
3550
3551                 dbus_message_iter_get_basic(&sub2, &text);
3552                 printf("%s\n", text);
3553
3554                 dbus_message_iter_next(&sub2);
3555         }
3556
3557         r = 0;
3558
3559 finish:
3560         if (m)
3561                 dbus_message_unref(m);
3562
3563         if (reply)
3564                 dbus_message_unref(reply);
3565
3566         dbus_error_free(&error);
3567
3568         return r;
3569 }
3570
3571 static int switch_root(DBusConnection *bus, char **args) {
3572         DBusMessage *m = NULL, *reply = NULL;
3573         unsigned l;
3574         const char *root, *init;
3575         DBusError error;
3576         int r;
3577
3578         dbus_error_init(&error);
3579
3580         l = strv_length(args);
3581         if (l < 2 || l > 3) {
3582                 log_error("Wrong number of arguments.");
3583                 return -EINVAL;
3584         }
3585
3586         root = args[1];
3587         init = l >= 3 ? args[2] : "";
3588
3589         m = dbus_message_new_method_call(
3590                         "org.freedesktop.systemd1",
3591                         "/org/freedesktop/systemd1",
3592                         "org.freedesktop.systemd1.Manager",
3593                         "SwitchRoot");
3594         if (!m) {
3595                 log_error("Could not allocate message.");
3596                 return -ENOMEM;
3597         }
3598
3599         if (!dbus_message_append_args(
3600                             m,
3601                             DBUS_TYPE_STRING, &root,
3602                             DBUS_TYPE_STRING, &init,
3603                             DBUS_TYPE_INVALID)) {
3604                 log_error("Could not append arguments to message.");
3605                 r = -ENOMEM;
3606                 goto finish;
3607         }
3608
3609         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3610         if (!reply) {
3611                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3612                 r = -EIO;
3613                 goto finish;
3614         }
3615
3616         r = 0;
3617
3618 finish:
3619         if (m)
3620                 dbus_message_unref(m);
3621
3622         if (reply)
3623                 dbus_message_unref(reply);
3624
3625         dbus_error_free(&error);
3626
3627         return r;
3628 }
3629
3630 static int set_environment(DBusConnection *bus, char **args) {
3631         DBusMessage *m = NULL, *reply = NULL;
3632         DBusError error;
3633         int r;
3634         const char *method;
3635         DBusMessageIter iter, sub;
3636         char **name;
3637
3638         dbus_error_init(&error);
3639
3640         method = streq(args[0], "set-environment")
3641                 ? "SetEnvironment"
3642                 : "UnsetEnvironment";
3643
3644         if (!(m = dbus_message_new_method_call(
3645                               "org.freedesktop.systemd1",
3646                               "/org/freedesktop/systemd1",
3647                               "org.freedesktop.systemd1.Manager",
3648                               method))) {
3649
3650                 log_error("Could not allocate message.");
3651                 return -ENOMEM;
3652         }
3653
3654         dbus_message_iter_init_append(m, &iter);
3655
3656         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3657                 log_error("Could not append arguments to message.");
3658                 r = -ENOMEM;
3659                 goto finish;
3660         }
3661
3662         STRV_FOREACH(name, args+1)
3663                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3664                         log_error("Could not append arguments to message.");
3665                         r = -ENOMEM;
3666                         goto finish;
3667                 }
3668
3669         if (!dbus_message_iter_close_container(&iter, &sub)) {
3670                 log_error("Could not append arguments to message.");
3671                 r = -ENOMEM;
3672                 goto finish;
3673         }
3674
3675         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3676                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3677                 r = -EIO;
3678                 goto finish;
3679         }
3680
3681         r = 0;
3682
3683 finish:
3684         if (m)
3685                 dbus_message_unref(m);
3686
3687         if (reply)
3688                 dbus_message_unref(reply);
3689
3690         dbus_error_free(&error);
3691
3692         return r;
3693 }
3694
3695 static int enable_sysv_units(char **args) {
3696         int r = 0;
3697
3698 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3699         const char *verb = args[0];
3700         unsigned f = 1, t = 1;
3701         LookupPaths paths;
3702
3703         if (arg_scope != UNIT_FILE_SYSTEM)
3704                 return 0;
3705
3706         if (!streq(verb, "enable") &&
3707             !streq(verb, "disable") &&
3708             !streq(verb, "is-enabled"))
3709                 return 0;
3710
3711         /* Processes all SysV units, and reshuffles the array so that
3712          * afterwards only the native units remain */
3713
3714         zero(paths);
3715         r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
3716         if (r < 0)
3717                 return r;
3718
3719         r = 0;
3720
3721         for (f = 1; args[f]; f++) {
3722                 const char *name;
3723                 char *p;
3724                 bool found_native = false, found_sysv;
3725                 unsigned c = 1;
3726                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3727                 char **k, *l, *q = NULL;
3728                 int j;
3729                 pid_t pid;
3730                 siginfo_t status;
3731
3732                 name = args[f];
3733
3734                 if (!endswith(name, ".service"))
3735                         continue;
3736
3737                 if (path_is_absolute(name))
3738                         continue;
3739
3740                 STRV_FOREACH(k, paths.unit_path) {
3741                         p = NULL;
3742
3743                         if (!isempty(arg_root))
3744                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3745                         else
3746                                 asprintf(&p, "%s/%s", *k, name);
3747
3748                         if (!p) {
3749                                 log_error("No memory");
3750                                 r = -ENOMEM;
3751                                 goto finish;
3752                         }
3753
3754                         found_native = access(p, F_OK) >= 0;
3755                         free(p);
3756
3757                         if (found_native)
3758                                 break;
3759                 }
3760
3761                 if (found_native)
3762                         continue;
3763
3764                 p = NULL;
3765                 if (!isempty(arg_root))
3766                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3767                 else
3768                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3769                 if (!p) {
3770                         log_error("No memory");
3771                         r = -ENOMEM;
3772                         goto finish;
3773                 }
3774
3775                 p[strlen(p) - sizeof(".service") + 1] = 0;
3776                 found_sysv = access(p, F_OK) >= 0;
3777
3778                 if (!found_sysv) {
3779                         free(p);
3780                         continue;
3781                 }
3782
3783                 /* Mark this entry, so that we don't try enabling it as native unit */
3784                 args[f] = (char*) "";
3785
3786                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3787
3788                 if (!isempty(arg_root))
3789                         argv[c++] = q = strappend("--root=", arg_root);
3790
3791                 argv[c++] = path_get_file_name(p);
3792                 argv[c++] =
3793                         streq(verb, "enable") ? "on" :
3794                         streq(verb, "disable") ? "off" : "--level=5";
3795                 argv[c] = NULL;
3796
3797                 l = strv_join((char**)argv, " ");
3798                 if (!l) {
3799                         log_error("No memory.");
3800                         free(q);
3801                         free(p);
3802                         r = -ENOMEM;
3803                         goto finish;
3804                 }
3805
3806                 log_info("Executing %s", l);
3807                 free(l);
3808
3809                 pid = fork();
3810                 if (pid < 0) {
3811                         log_error("Failed to fork: %m");
3812                         free(p);
3813                         free(q);
3814                         r = -errno;
3815                         goto finish;
3816                 } else if (pid == 0) {
3817                         /* Child */
3818
3819                         execv(argv[0], (char**) argv);
3820                         _exit(EXIT_FAILURE);
3821                 }
3822
3823                 free(p);
3824                 free(q);
3825
3826                 j = wait_for_terminate(pid, &status);
3827                 if (j < 0) {
3828                         log_error("Failed to wait for child: %s", strerror(-r));
3829                         r = j;
3830                         goto finish;
3831                 }
3832
3833                 if (status.si_code == CLD_EXITED) {
3834                         if (streq(verb, "is-enabled")) {
3835                                 if (status.si_status == 0) {
3836                                         if (!arg_quiet)
3837                                                 puts("enabled");
3838                                         r = 1;
3839                                 } else {
3840                                         if (!arg_quiet)
3841                                                 puts("disabled");
3842                                 }
3843
3844                         } else if (status.si_status != 0) {
3845                                 r = -EINVAL;
3846                                 goto finish;
3847                         }
3848                 } else {
3849                         r = -EPROTO;
3850                         goto finish;
3851                 }
3852         }
3853
3854 finish:
3855         lookup_paths_free(&paths);
3856
3857         /* Drop all SysV units */
3858         for (f = 1, t = 1; args[f]; f++) {
3859
3860                 if (isempty(args[f]))
3861                         continue;
3862
3863                 args[t++] = args[f];
3864         }
3865
3866         args[t] = NULL;
3867
3868 #endif
3869         return r;
3870 }
3871
3872 static int enable_unit(DBusConnection *bus, char **args) {
3873         const char *verb = args[0];
3874         UnitFileChange *changes = NULL;
3875         unsigned n_changes = 0, i;
3876         int carries_install_info = -1;
3877         DBusMessage *m = NULL, *reply = NULL;
3878         int r;
3879         DBusError error;
3880
3881         r = enable_sysv_units(args);
3882         if (r < 0)
3883                 return r;
3884
3885         if (!args[1])
3886                 return 0;
3887
3888         dbus_error_init(&error);
3889
3890         if (!bus || avoid_bus()) {
3891                 if (streq(verb, "enable")) {
3892                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3893                         carries_install_info = r;
3894                 } else if (streq(verb, "disable"))
3895                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3896                 else if (streq(verb, "reenable")) {
3897                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3898                         carries_install_info = r;
3899                 } else if (streq(verb, "link"))
3900                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3901                 else if (streq(verb, "preset")) {
3902                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3903                         carries_install_info = r;
3904                 } else if (streq(verb, "mask"))
3905                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3906                 else if (streq(verb, "unmask"))
3907                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3908                 else
3909                         assert_not_reached("Unknown verb");
3910
3911                 if (r < 0) {
3912                         log_error("Operation failed: %s", strerror(-r));
3913                         goto finish;
3914                 }
3915
3916                 if (!arg_quiet) {
3917                         for (i = 0; i < n_changes; i++) {
3918                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3919                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3920                                 else
3921                                         log_info("rm '%s'", changes[i].path);
3922                         }
3923                 }
3924
3925         } else {
3926                 const char *method;
3927                 bool send_force = true, expect_carries_install_info = false;
3928                 dbus_bool_t a, b;
3929                 DBusMessageIter iter, sub, sub2;
3930
3931                 if (streq(verb, "enable")) {
3932                         method = "EnableUnitFiles";
3933                         expect_carries_install_info = true;
3934                 } else if (streq(verb, "disable")) {
3935                         method = "DisableUnitFiles";
3936                         send_force = false;
3937                 } else if (streq(verb, "reenable")) {
3938                         method = "ReenableUnitFiles";
3939                         expect_carries_install_info = true;
3940                 } else if (streq(verb, "link"))
3941                         method = "LinkUnitFiles";
3942                 else if (streq(verb, "preset")) {
3943                         method = "PresetUnitFiles";
3944                         expect_carries_install_info = true;
3945                 } else if (streq(verb, "mask"))
3946                         method = "MaskUnitFiles";
3947                 else if (streq(verb, "unmask")) {
3948                         method = "UnmaskUnitFiles";
3949                         send_force = false;
3950                 } else
3951                         assert_not_reached("Unknown verb");
3952
3953                 m = dbus_message_new_method_call(
3954                                 "org.freedesktop.systemd1",
3955                                 "/org/freedesktop/systemd1",
3956                                 "org.freedesktop.systemd1.Manager",
3957                                 method);
3958                 if (!m) {
3959                         log_error("Out of memory");
3960                         r = -ENOMEM;
3961                         goto finish;
3962                 }
3963
3964                 dbus_message_iter_init_append(m, &iter);
3965
3966                 r = bus_append_strv_iter(&iter, args+1);
3967                 if (r < 0) {
3968                         log_error("Failed to append unit files.");
3969                         goto finish;
3970                 }
3971
3972                 a = arg_runtime;
3973                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3974                         log_error("Failed to append runtime boolean.");
3975                         r = -ENOMEM;
3976                         goto finish;
3977                 }
3978
3979                 if (send_force) {
3980                         b = arg_force;
3981
3982                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3983                                 log_error("Failed to append force boolean.");
3984                                 r = -ENOMEM;
3985                                 goto finish;
3986                         }
3987                 }
3988
3989                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3990                 if (!reply) {
3991                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3992                         r = -EIO;
3993                         goto finish;
3994                 }
3995
3996                 if (!dbus_message_iter_init(reply, &iter)) {
3997                         log_error("Failed to initialize iterator.");
3998                         goto finish;
3999                 }
4000
4001                 if (expect_carries_install_info) {
4002                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4003                         if (r < 0) {
4004                                 log_error("Failed to parse reply.");
4005                                 goto finish;
4006                         }
4007
4008                         carries_install_info = b;
4009                 }
4010
4011                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4012                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
4013                         log_error("Failed to parse reply.");
4014                         r = -EIO;
4015                         goto finish;
4016                 }
4017
4018                 dbus_message_iter_recurse(&iter, &sub);
4019                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4020                         const char *type, *path, *source;
4021
4022                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4023                                 log_error("Failed to parse reply.");
4024                                 r = -EIO;
4025                                 goto finish;
4026                         }
4027
4028                         dbus_message_iter_recurse(&sub, &sub2);
4029
4030                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4031                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4032                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4033                                 log_error("Failed to parse reply.");
4034                                 r = -EIO;
4035                                 goto finish;
4036                         }
4037
4038                         if (!arg_quiet) {
4039                                 if (streq(type, "symlink"))
4040                                         log_info("ln -s '%s' '%s'", source, path);
4041                                 else
4042                                         log_info("rm '%s'", path);
4043                         }
4044
4045                         dbus_message_iter_next(&sub);
4046                 }
4047
4048                 /* Try to reload if enabeld */
4049                 if (!arg_no_reload)
4050                         r = daemon_reload(bus, args);
4051         }
4052
4053         if (carries_install_info == 0)
4054                 log_warning("Warning: unit files do not carry install information. No operation executed.");
4055
4056 finish:
4057         if (m)
4058                 dbus_message_unref(m);
4059
4060         if (reply)
4061                 dbus_message_unref(reply);
4062
4063         unit_file_changes_free(changes, n_changes);
4064
4065         dbus_error_free(&error);
4066         return r;
4067 }
4068
4069 static int unit_is_enabled(DBusConnection *bus, char **args) {
4070         DBusError error;
4071         int r;
4072         DBusMessage *m = NULL, *reply = NULL;
4073         bool enabled;
4074         char **name;
4075
4076         dbus_error_init(&error);
4077
4078         r = enable_sysv_units(args);
4079         if (r < 0)
4080                 return r;
4081
4082         enabled = r > 0;
4083
4084         if (!bus || avoid_bus()) {
4085
4086                 STRV_FOREACH(name, args+1) {
4087                         UnitFileState state;
4088
4089                         state = unit_file_get_state(arg_scope, arg_root, *name);
4090                         if (state < 0) {
4091                                 r = state;
4092                                 goto finish;
4093                         }
4094
4095                         if (state == UNIT_FILE_ENABLED ||
4096                             state == UNIT_FILE_ENABLED_RUNTIME ||
4097                             state == UNIT_FILE_STATIC)
4098                                 enabled = true;
4099
4100                         if (!arg_quiet)
4101                                 puts(unit_file_state_to_string(state));
4102                 }
4103
4104         } else {
4105                 STRV_FOREACH(name, args+1) {
4106                         const char *s;
4107
4108                         m = dbus_message_new_method_call(
4109                                         "org.freedesktop.systemd1",
4110                                         "/org/freedesktop/systemd1",
4111                                         "org.freedesktop.systemd1.Manager",
4112                                         "GetUnitFileState");
4113                         if (!m) {
4114                                 log_error("Out of memory");
4115                                 r = -ENOMEM;
4116                                 goto finish;
4117                         }
4118
4119                         if (!dbus_message_append_args(m,
4120                                                       DBUS_TYPE_STRING, name,
4121                                                       DBUS_TYPE_INVALID)) {
4122                                 log_error("Could not append arguments to message.");
4123                                 r = -ENOMEM;
4124                                 goto finish;
4125                         }
4126
4127                         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4128                         if (!reply) {
4129                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4130                                 r = -EIO;
4131                                 goto finish;
4132                         }
4133
4134                         if (!dbus_message_get_args(reply, &error,
4135                                                    DBUS_TYPE_STRING, &s,
4136                                                    DBUS_TYPE_INVALID)) {
4137                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4138                                 r = -EIO;
4139                                 goto finish;
4140                         }
4141
4142                         dbus_message_unref(m);
4143                         dbus_message_unref(reply);
4144                         m = reply = NULL;
4145
4146                         if (streq(s, "enabled") ||
4147                             streq(s, "enabled-runtime") ||
4148                             streq(s, "static"))
4149                                 enabled = true;
4150
4151                         if (!arg_quiet)
4152                                 puts(s);
4153                 }
4154         }
4155
4156         r = enabled ? 0 : 1;
4157
4158 finish:
4159         if (m)
4160                 dbus_message_unref(m);
4161
4162         if (reply)
4163                 dbus_message_unref(reply);
4164
4165         dbus_error_free(&error);
4166         return r;
4167 }
4168
4169 static int systemctl_help(void) {
4170
4171         pager_open_if_enabled();
4172
4173         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4174                "Query or send control commands to the systemd manager.\n\n"
4175                "  -h --help           Show this help\n"
4176                "     --version        Show package version\n"
4177                "  -t --type=TYPE      List only units of a particular type\n"
4178                "  -p --property=NAME  Show only properties by this name\n"
4179                "  -a --all            Show all units/properties, including dead/empty ones\n"
4180                "     --failed         Show only failed units\n"
4181                "     --full           Don't ellipsize unit names on output\n"
4182                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4183                "                      pending\n"
4184                "     --ignore-dependencies\n"
4185                "                      When queueing a new job, ignore all its dependencies\n"
4186                "     --kill-who=WHO   Who to send signal to\n"
4187                "  -s --signal=SIGNAL  Which signal to send\n"
4188                "  -H --host=[USER@]HOST\n"
4189                "                      Show information for remote host\n"
4190                "  -P --privileged     Acquire privileges before execution\n"
4191                "  -q --quiet          Suppress output\n"
4192                "     --no-block       Do not wait until operation finished\n"
4193                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4194                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4195                "                      configuration\n"
4196                "     --no-legend      Do not print a legend (column headers and hints)\n"
4197                "     --no-pager       Do not pipe output into a pager\n"
4198                "     --no-ask-password\n"
4199                "                      Do not ask for system passwords\n"
4200                "     --order          When generating graph for dot, show only order\n"
4201                "     --require        When generating graph for dot, show only requirement\n"
4202                "     --system         Connect to system manager\n"
4203                "     --user           Connect to user service manager\n"
4204                "     --global         Enable/disable unit files globally\n"
4205                "  -f --force          When enabling unit files, override existing symlinks\n"
4206                "                      When shutting down, execute action immediately\n"
4207                "     --root=PATH      Enable unit files in the specified root directory\n"
4208                "     --runtime        Enable unit files only temporarily until next reboot\n"
4209                "  -n --lines=INTEGER  Journal entries to show\n"
4210                "     --follow         Follow journal\n"
4211                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4212                "                      verbose, export, json, cat)\n\n"
4213                "Unit Commands:\n"
4214                "  list-units                      List loaded units\n"
4215                "  start [NAME...]                 Start (activate) one or more units\n"
4216                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4217                "  reload [NAME...]                Reload one or more units\n"
4218                "  restart [NAME...]               Start or restart one or more units\n"
4219                "  try-restart [NAME...]           Restart one or more units if active\n"
4220                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
4221                "                                  otherwise start or restart\n"
4222                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4223                "                                  otherwise restart if active\n"
4224                "  isolate [NAME]                  Start one unit and stop all others\n"
4225                "  kill [NAME...]                  Send signal to processes of a unit\n"
4226                "  is-active [NAME...]             Check whether units are active\n"
4227                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4228                "  show [NAME...|JOB...]           Show properties of one or more\n"
4229                "                                  units/jobs or the manager\n"
4230                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4231                "                                  units\n"
4232                "  load [NAME...]                  Load one or more units\n\n"
4233                "Unit File Commands:\n"
4234                "  list-unit-files                 List installed unit files\n"
4235                "  enable [NAME...]                Enable one or more unit files\n"
4236                "  disable [NAME...]               Disable one or more unit files\n"
4237                "  reenable [NAME...]              Reenable one or more unit files\n"
4238                "  preset [NAME...]                Enable/disable one or more unit files\n"
4239                "                                  based on preset configuration\n"
4240                "  mask [NAME...]                  Mask one or more units\n"
4241                "  unmask [NAME...]                Unmask one or more units\n"
4242                "  link [PATH...]                  Link one or more units files into\n"
4243                "                                  the search path\n"
4244                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4245                "Job Commands:\n"
4246                "  list-jobs                       List jobs\n"
4247                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4248                "Status Commands:\n"
4249                "  dump                            Dump server status\n"
4250                "  dot                             Dump dependency graph for dot(1)\n\n"
4251                "Snapshot Commands:\n"
4252                "  snapshot [NAME]                 Create a snapshot\n"
4253                "  delete [NAME...]                Remove one or more snapshots\n\n"
4254                "Environment Commands:\n"
4255                "  show-environment                Dump environment\n"
4256                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4257                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4258                "Manager Lifecycle Commands:\n"
4259                "  daemon-reload                   Reload systemd manager configuration\n"
4260                "  daemon-reexec                   Reexecute systemd manager\n\n"
4261                "System Commands:\n"
4262                "  default                         Enter system default mode\n"
4263                "  rescue                          Enter system rescue mode\n"
4264                "  emergency                       Enter system emergency mode\n"
4265                "  halt                            Shut down and halt the system\n"
4266                "  poweroff                        Shut down and power-off the system\n"
4267                "  reboot                          Shut down and reboot the system\n"
4268                "  kexec                           Shut down and reboot the system with kexec\n"
4269                "  exit                            Request user instance exit\n"
4270                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
4271                "  suspend                         Suspend the system\n"
4272                "  hibernate                       Hibernate the system\n",
4273                program_invocation_short_name);
4274
4275         return 0;
4276 }
4277
4278 static int halt_help(void) {
4279
4280         printf("%s [OPTIONS...]\n\n"
4281                "%s the system.\n\n"
4282                "     --help      Show this help\n"
4283                "     --halt      Halt the machine\n"
4284                "  -p --poweroff  Switch off the machine\n"
4285                "     --reboot    Reboot the machine\n"
4286                "  -f --force     Force immediate halt/power-off/reboot\n"
4287                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4288                "  -d --no-wtmp   Don't write wtmp record\n"
4289                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
4290                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4291                program_invocation_short_name,
4292                arg_action == ACTION_REBOOT   ? "Reboot" :
4293                arg_action == ACTION_POWEROFF ? "Power off" :
4294                                                "Halt");
4295
4296         return 0;
4297 }
4298
4299 static int shutdown_help(void) {
4300
4301         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4302                "Shut down the system.\n\n"
4303                "     --help      Show this help\n"
4304                "  -H --halt      Halt the machine\n"
4305                "  -P --poweroff  Power-off the machine\n"
4306                "  -r --reboot    Reboot the machine\n"
4307                "  -h             Equivalent to --poweroff, overridden by --halt\n"
4308                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4309                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4310                "  -c             Cancel a pending shutdown\n",
4311                program_invocation_short_name);
4312
4313         return 0;
4314 }
4315
4316 static int telinit_help(void) {
4317
4318         printf("%s [OPTIONS...] {COMMAND}\n\n"
4319                "Send control commands to the init daemon.\n\n"
4320                "     --help      Show this help\n"
4321                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4322                "Commands:\n"
4323                "  0              Power-off the machine\n"
4324                "  6              Reboot the machine\n"
4325                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4326                "  1, s, S        Enter rescue mode\n"
4327                "  q, Q           Reload init daemon configuration\n"
4328                "  u, U           Reexecute init daemon\n",
4329                program_invocation_short_name);
4330
4331         return 0;
4332 }
4333
4334 static int runlevel_help(void) {
4335
4336         printf("%s [OPTIONS...]\n\n"
4337                "Prints the previous and current runlevel of the init system.\n\n"
4338                "     --help      Show this help\n",
4339                program_invocation_short_name);
4340
4341         return 0;
4342 }
4343
4344 static int systemctl_parse_argv(int argc, char *argv[]) {
4345
4346         enum {
4347                 ARG_FAIL = 0x100,
4348                 ARG_IGNORE_DEPENDENCIES,
4349                 ARG_VERSION,
4350                 ARG_USER,
4351                 ARG_SYSTEM,
4352                 ARG_GLOBAL,
4353                 ARG_NO_BLOCK,
4354                 ARG_NO_LEGEND,
4355                 ARG_NO_PAGER,
4356                 ARG_NO_WALL,
4357                 ARG_ORDER,
4358                 ARG_REQUIRE,
4359                 ARG_ROOT,
4360                 ARG_FULL,
4361                 ARG_NO_RELOAD,
4362                 ARG_KILL_MODE,
4363                 ARG_KILL_WHO,
4364                 ARG_NO_ASK_PASSWORD,
4365                 ARG_FAILED,
4366                 ARG_RUNTIME,
4367                 ARG_FOLLOW,
4368                 ARG_FORCE
4369         };
4370
4371         static const struct option options[] = {
4372                 { "help",      no_argument,       NULL, 'h'           },
4373                 { "version",   no_argument,       NULL, ARG_VERSION   },
4374                 { "type",      required_argument, NULL, 't'           },
4375                 { "property",  required_argument, NULL, 'p'           },
4376                 { "all",       no_argument,       NULL, 'a'           },
4377                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4378                 { "full",      no_argument,       NULL, ARG_FULL      },
4379                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4380                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4381                 { "user",      no_argument,       NULL, ARG_USER      },
4382                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4383                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4384                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4385                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4386                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4387                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4388                 { "quiet",     no_argument,       NULL, 'q'           },
4389                 { "order",     no_argument,       NULL, ARG_ORDER     },
4390                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4391                 { "root",      required_argument, NULL, ARG_ROOT      },
4392                 { "force",     no_argument,       NULL, ARG_FORCE     },
4393                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4394                 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
4395                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4396                 { "signal",    required_argument, NULL, 's'           },
4397                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4398                 { "host",      required_argument, NULL, 'H'           },
4399                 { "privileged",no_argument,       NULL, 'P'           },
4400                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4401                 { "lines",     required_argument, NULL, 'n'           },
4402                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4403                 { "output",    required_argument, NULL, 'o'           },
4404                 { NULL,        0,                 NULL, 0             }
4405         };
4406
4407         int c;
4408
4409         assert(argc >= 0);
4410         assert(argv);
4411
4412         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4413
4414                 switch (c) {
4415
4416                 case 'h':
4417                         systemctl_help();
4418                         return 0;
4419
4420                 case ARG_VERSION:
4421                         puts(PACKAGE_STRING);
4422                         puts(DISTRIBUTION);
4423                         puts(SYSTEMD_FEATURES);
4424                         return 0;
4425
4426                 case 't':
4427                         arg_type = optarg;
4428                         break;
4429
4430                 case 'p': {
4431                         char **l;
4432
4433                         if (!(l = strv_append(arg_property, optarg)))
4434                                 return -ENOMEM;
4435
4436                         strv_free(arg_property);
4437                         arg_property = l;
4438
4439                         /* If the user asked for a particular
4440                          * property, show it to him, even if it is
4441                          * empty. */
4442                         arg_all = true;
4443                         break;
4444                 }
4445
4446                 case 'a':
4447                         arg_all = true;
4448                         break;
4449
4450                 case ARG_FAIL:
4451                         arg_job_mode = "fail";
4452                         break;
4453
4454                 case ARG_IGNORE_DEPENDENCIES:
4455                         arg_job_mode = "ignore-dependencies";
4456                         break;
4457
4458                 case ARG_USER:
4459                         arg_scope = UNIT_FILE_USER;
4460                         break;
4461
4462                 case ARG_SYSTEM:
4463                         arg_scope = UNIT_FILE_SYSTEM;
4464                         break;
4465
4466                 case ARG_GLOBAL:
4467                         arg_scope = UNIT_FILE_GLOBAL;
4468                         break;
4469
4470                 case ARG_NO_BLOCK:
4471                         arg_no_block = true;
4472                         break;
4473
4474                 case ARG_NO_LEGEND:
4475                         arg_no_legend = true;
4476                         break;
4477
4478                 case ARG_NO_PAGER:
4479                         arg_no_pager = true;
4480                         break;
4481
4482                 case ARG_NO_WALL:
4483                         arg_no_wall = true;
4484                         break;
4485
4486                 case ARG_ORDER:
4487                         arg_dot = DOT_ORDER;
4488                         break;
4489
4490                 case ARG_REQUIRE:
4491                         arg_dot = DOT_REQUIRE;
4492                         break;
4493
4494                 case ARG_ROOT:
4495                         arg_root = optarg;
4496                         break;
4497
4498                 case ARG_FULL:
4499                         arg_full = true;
4500                         break;
4501
4502                 case ARG_FAILED:
4503                         arg_failed = true;
4504                         break;
4505
4506                 case 'q':
4507                         arg_quiet = true;
4508                         break;
4509
4510                 case ARG_FORCE:
4511                         arg_force ++;
4512                         break;
4513
4514                 case ARG_FOLLOW:
4515                         arg_follow = true;
4516                         break;
4517
4518                 case 'f':
4519                         /* -f is short for both --follow and --force! */
4520                         arg_force ++;
4521                         arg_follow = true;
4522                         break;
4523
4524                 case ARG_NO_RELOAD:
4525                         arg_no_reload = true;
4526                         break;
4527
4528                 case ARG_KILL_WHO:
4529                         arg_kill_who = optarg;
4530                         break;
4531
4532                 case ARG_KILL_MODE:
4533                         arg_kill_mode = optarg;
4534                         break;
4535
4536                 case 's':
4537                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4538                                 log_error("Failed to parse signal string %s.", optarg);
4539                                 return -EINVAL;
4540                         }
4541                         break;
4542
4543                 case ARG_NO_ASK_PASSWORD:
4544                         arg_ask_password = false;
4545                         break;
4546
4547                 case 'P':
4548                         arg_transport = TRANSPORT_POLKIT;
4549                         break;
4550
4551                 case 'H':
4552                         arg_transport = TRANSPORT_SSH;
4553                         arg_host = optarg;
4554                         break;
4555
4556                 case ARG_RUNTIME:
4557                         arg_runtime = true;
4558                         break;
4559
4560                 case 'n':
4561                         if (safe_atou(optarg, &arg_lines) < 0) {
4562                                 log_error("Failed to parse lines '%s'", optarg);
4563                                 return -EINVAL;
4564                         }
4565                         break;
4566
4567                 case 'o':
4568                         arg_output = output_mode_from_string(optarg);
4569                         if (arg_output < 0) {
4570                                 log_error("Unknown output '%s'.", optarg);
4571                                 return -EINVAL;
4572                         }
4573                         break;
4574
4575                 case '?':
4576                         return -EINVAL;
4577
4578                 default:
4579                         log_error("Unknown option code %c", c);
4580                         return -EINVAL;
4581                 }
4582         }
4583
4584         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4585                 log_error("Cannot access user instance remotely.");
4586                 return -EINVAL;
4587         }
4588
4589         return 1;
4590 }
4591
4592 static int halt_parse_argv(int argc, char *argv[]) {
4593
4594         enum {
4595                 ARG_HELP = 0x100,
4596                 ARG_HALT,
4597                 ARG_REBOOT,
4598                 ARG_NO_WALL
4599         };
4600
4601         static const struct option options[] = {
4602                 { "help",      no_argument,       NULL, ARG_HELP    },
4603                 { "halt",      no_argument,       NULL, ARG_HALT    },
4604                 { "poweroff",  no_argument,       NULL, 'p'         },
4605                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4606                 { "force",     no_argument,       NULL, 'f'         },
4607                 { "wtmp-only", no_argument,       NULL, 'w'         },
4608                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4609                 { "no-sync",   no_argument,       NULL, 'n'         },
4610                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4611                 { NULL,        0,                 NULL, 0           }
4612         };
4613
4614         int c, runlevel;
4615
4616         assert(argc >= 0);
4617         assert(argv);
4618
4619         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4620                 if (runlevel == '0' || runlevel == '6')
4621                         arg_force = 2;
4622
4623         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4624                 switch (c) {
4625
4626                 case ARG_HELP:
4627                         halt_help();
4628                         return 0;
4629
4630                 case ARG_HALT:
4631                         arg_action = ACTION_HALT;
4632                         break;
4633
4634                 case 'p':
4635                         if (arg_action != ACTION_REBOOT)
4636                                 arg_action = ACTION_POWEROFF;
4637                         break;
4638
4639                 case ARG_REBOOT:
4640                         arg_action = ACTION_REBOOT;
4641                         break;
4642
4643                 case 'f':
4644                         arg_force = 2;
4645                         break;
4646
4647                 case 'w':
4648                         arg_dry = true;
4649                         break;
4650
4651                 case 'd':
4652                         arg_no_wtmp = true;
4653                         break;
4654
4655                 case 'n':
4656                         arg_no_sync = true;
4657                         break;
4658
4659                 case ARG_NO_WALL:
4660                         arg_no_wall = true;
4661                         break;
4662
4663                 case 'i':
4664                 case 'h':
4665                         /* Compatibility nops */
4666                         break;
4667
4668                 case '?':
4669                         return -EINVAL;
4670
4671                 default:
4672                         log_error("Unknown option code %c", c);
4673                         return -EINVAL;
4674                 }
4675         }
4676
4677         if (optind < argc) {
4678                 log_error("Too many arguments.");
4679                 return -EINVAL;
4680         }
4681
4682         return 1;
4683 }
4684
4685 static int parse_time_spec(const char *t, usec_t *_u) {
4686         assert(t);
4687         assert(_u);
4688
4689         if (streq(t, "now"))
4690                 *_u = 0;
4691         else if (!strchr(t, ':')) {
4692                 uint64_t u;
4693
4694                 if (safe_atou64(t, &u) < 0)
4695                         return -EINVAL;
4696
4697                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4698         } else {
4699                 char *e = NULL;
4700                 long hour, minute;
4701                 struct tm tm;
4702                 time_t s;
4703                 usec_t n;
4704
4705                 errno = 0;
4706                 hour = strtol(t, &e, 10);
4707                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4708                         return -EINVAL;
4709
4710                 minute = strtol(e+1, &e, 10);
4711                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4712                         return -EINVAL;
4713
4714                 n = now(CLOCK_REALTIME);
4715                 s = (time_t) (n / USEC_PER_SEC);
4716
4717                 zero(tm);
4718                 assert_se(localtime_r(&s, &tm));
4719
4720                 tm.tm_hour = (int) hour;
4721                 tm.tm_min = (int) minute;
4722                 tm.tm_sec = 0;
4723
4724                 assert_se(s = mktime(&tm));
4725
4726                 *_u = (usec_t) s * USEC_PER_SEC;
4727
4728                 while (*_u <= n)
4729                         *_u += USEC_PER_DAY;
4730         }
4731
4732         return 0;
4733 }
4734
4735 static int shutdown_parse_argv(int argc, char *argv[]) {
4736
4737         enum {
4738                 ARG_HELP = 0x100,
4739                 ARG_NO_WALL
4740         };
4741
4742         static const struct option options[] = {
4743                 { "help",      no_argument,       NULL, ARG_HELP    },
4744                 { "halt",      no_argument,       NULL, 'H'         },
4745                 { "poweroff",  no_argument,       NULL, 'P'         },
4746                 { "reboot",    no_argument,       NULL, 'r'         },
4747                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4748                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4749                 { NULL,        0,                 NULL, 0           }
4750         };
4751
4752         int c, r;
4753
4754         assert(argc >= 0);
4755         assert(argv);
4756
4757         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4758                 switch (c) {
4759
4760                 case ARG_HELP:
4761                         shutdown_help();
4762                         return 0;
4763
4764                 case 'H':
4765                         arg_action = ACTION_HALT;
4766                         break;
4767
4768                 case 'P':
4769                         arg_action = ACTION_POWEROFF;
4770                         break;
4771
4772                 case 'r':
4773                         if (kexec_loaded())
4774                                 arg_action = ACTION_KEXEC;
4775                         else
4776                                 arg_action = ACTION_REBOOT;
4777                         break;
4778
4779                 case 'K':
4780                         arg_action = ACTION_KEXEC;
4781                         break;
4782
4783                 case 'h':
4784                         if (arg_action != ACTION_HALT)
4785                                 arg_action = ACTION_POWEROFF;
4786                         break;
4787
4788                 case 'k':
4789                         arg_dry = true;
4790                         break;
4791
4792                 case ARG_NO_WALL:
4793                         arg_no_wall = true;
4794                         break;
4795
4796                 case 't':
4797                 case 'a':
4798                         /* Compatibility nops */
4799                         break;
4800
4801                 case 'c':
4802                         arg_action = ACTION_CANCEL_SHUTDOWN;
4803                         break;
4804
4805                 case '?':
4806                         return -EINVAL;
4807
4808                 default:
4809                         log_error("Unknown option code %c", c);
4810                         return -EINVAL;
4811                 }
4812         }
4813
4814         if (argc > optind) {
4815                 r = parse_time_spec(argv[optind], &arg_when);
4816                 if (r < 0) {
4817                         log_error("Failed to parse time specification: %s", argv[optind]);
4818                         return r;
4819                 }
4820         } else
4821                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4822
4823         /* We skip the time argument */
4824         if (argc > optind + 1)
4825                 arg_wall = argv + optind + 1;
4826
4827         optind = argc;
4828
4829         return 1;
4830 }
4831
4832 static int telinit_parse_argv(int argc, char *argv[]) {
4833
4834         enum {
4835                 ARG_HELP = 0x100,
4836                 ARG_NO_WALL
4837         };
4838
4839         static const struct option options[] = {
4840                 { "help",      no_argument,       NULL, ARG_HELP    },
4841                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4842                 { NULL,        0,                 NULL, 0           }
4843         };
4844
4845         static const struct {
4846                 char from;
4847                 enum action to;
4848         } table[] = {
4849                 { '0', ACTION_POWEROFF },
4850                 { '6', ACTION_REBOOT },
4851                 { '1', ACTION_RESCUE },
4852                 { '2', ACTION_RUNLEVEL2 },
4853                 { '3', ACTION_RUNLEVEL3 },
4854                 { '4', ACTION_RUNLEVEL4 },
4855                 { '5', ACTION_RUNLEVEL5 },
4856                 { 's', ACTION_RESCUE },
4857                 { 'S', ACTION_RESCUE },
4858                 { 'q', ACTION_RELOAD },
4859                 { 'Q', ACTION_RELOAD },
4860                 { 'u', ACTION_REEXEC },
4861                 { 'U', ACTION_REEXEC }
4862         };
4863
4864         unsigned i;
4865         int c;
4866
4867         assert(argc >= 0);
4868         assert(argv);
4869
4870         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4871                 switch (c) {
4872
4873                 case ARG_HELP:
4874                         telinit_help();
4875                         return 0;
4876
4877                 case ARG_NO_WALL:
4878                         arg_no_wall = true;
4879                         break;
4880
4881                 case '?':
4882                         return -EINVAL;
4883
4884                 default:
4885                         log_error("Unknown option code %c", c);
4886                         return -EINVAL;
4887                 }
4888         }
4889
4890         if (optind >= argc) {
4891                 telinit_help();
4892                 return -EINVAL;
4893         }
4894
4895         if (optind + 1 < argc) {
4896                 log_error("Too many arguments.");
4897                 return -EINVAL;
4898         }
4899
4900         if (strlen(argv[optind]) != 1) {
4901                 log_error("Expected single character argument.");
4902                 return -EINVAL;
4903         }
4904
4905         for (i = 0; i < ELEMENTSOF(table); i++)
4906                 if (table[i].from == argv[optind][0])
4907                         break;
4908
4909         if (i >= ELEMENTSOF(table)) {
4910                 log_error("Unknown command %s.", argv[optind]);
4911                 return -EINVAL;
4912         }
4913
4914         arg_action = table[i].to;
4915
4916         optind ++;
4917
4918         return 1;
4919 }
4920
4921 static int runlevel_parse_argv(int argc, char *argv[]) {
4922
4923         enum {
4924                 ARG_HELP = 0x100,
4925         };
4926
4927         static const struct option options[] = {
4928                 { "help",      no_argument,       NULL, ARG_HELP    },
4929                 { NULL,        0,                 NULL, 0           }
4930         };
4931
4932         int c;
4933
4934         assert(argc >= 0);
4935         assert(argv);
4936
4937         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4938                 switch (c) {
4939
4940                 case ARG_HELP:
4941                         runlevel_help();
4942                         return 0;
4943
4944                 case '?':
4945                         return -EINVAL;
4946
4947                 default:
4948                         log_error("Unknown option code %c", c);
4949                         return -EINVAL;
4950                 }
4951         }
4952
4953         if (optind < argc) {
4954                 log_error("Too many arguments.");
4955                 return -EINVAL;
4956         }
4957
4958         return 1;
4959 }
4960
4961 static int parse_argv(int argc, char *argv[]) {
4962         assert(argc >= 0);
4963         assert(argv);
4964
4965         if (program_invocation_short_name) {
4966
4967                 if (strstr(program_invocation_short_name, "halt")) {
4968                         arg_action = ACTION_HALT;
4969                         return halt_parse_argv(argc, argv);
4970                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4971                         arg_action = ACTION_POWEROFF;
4972                         return halt_parse_argv(argc, argv);
4973                 } else if (strstr(program_invocation_short_name, "reboot")) {
4974                         if (kexec_loaded())
4975                                 arg_action = ACTION_KEXEC;
4976                         else
4977                                 arg_action = ACTION_REBOOT;
4978                         return halt_parse_argv(argc, argv);
4979                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4980                         arg_action = ACTION_POWEROFF;
4981                         return shutdown_parse_argv(argc, argv);
4982                 } else if (strstr(program_invocation_short_name, "init")) {
4983
4984                         if (sd_booted() > 0) {
4985                                 arg_action = ACTION_INVALID;
4986                                 return telinit_parse_argv(argc, argv);
4987                         } else {
4988                                 /* Hmm, so some other init system is
4989                                  * running, we need to forward this
4990                                  * request to it. For now we simply
4991                                  * guess that it is Upstart. */
4992
4993                                 execv("/lib/upstart/telinit", argv);
4994
4995                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4996                                 return -EIO;
4997                         }
4998
4999                 } else if (strstr(program_invocation_short_name, "runlevel")) {
5000                         arg_action = ACTION_RUNLEVEL;
5001                         return runlevel_parse_argv(argc, argv);
5002                 }
5003         }
5004
5005         arg_action = ACTION_SYSTEMCTL;
5006         return systemctl_parse_argv(argc, argv);
5007 }
5008
5009 static int action_to_runlevel(void) {
5010
5011         static const char table[_ACTION_MAX] = {
5012                 [ACTION_HALT] =      '0',
5013                 [ACTION_POWEROFF] =  '0',
5014                 [ACTION_REBOOT] =    '6',
5015                 [ACTION_RUNLEVEL2] = '2',
5016                 [ACTION_RUNLEVEL3] = '3',
5017                 [ACTION_RUNLEVEL4] = '4',
5018                 [ACTION_RUNLEVEL5] = '5',
5019                 [ACTION_RESCUE] =    '1'
5020         };
5021
5022         assert(arg_action < _ACTION_MAX);
5023
5024         return table[arg_action];
5025 }
5026
5027 static int talk_upstart(void) {
5028         DBusMessage *m = NULL, *reply = NULL;
5029         DBusError error;
5030         int previous, rl, r;
5031         char
5032                 env1_buf[] = "RUNLEVEL=X",
5033                 env2_buf[] = "PREVLEVEL=X";
5034         char *env1 = env1_buf, *env2 = env2_buf;
5035         const char *emit = "runlevel";
5036         dbus_bool_t b_false = FALSE;
5037         DBusMessageIter iter, sub;
5038         DBusConnection *bus;
5039
5040         dbus_error_init(&error);
5041
5042         if (!(rl = action_to_runlevel()))
5043                 return 0;
5044
5045         if (utmp_get_runlevel(&previous, NULL) < 0)
5046                 previous = 'N';
5047
5048         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
5049                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5050                         r = 0;
5051                         goto finish;
5052                 }
5053
5054                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
5055                 r = -EIO;
5056                 goto finish;
5057         }
5058
5059         if ((r = bus_check_peercred(bus)) < 0) {
5060                 log_error("Failed to verify owner of bus.");
5061                 goto finish;
5062         }
5063
5064         if (!(m = dbus_message_new_method_call(
5065                               "com.ubuntu.Upstart",
5066                               "/com/ubuntu/Upstart",
5067                               "com.ubuntu.Upstart0_6",
5068                               "EmitEvent"))) {
5069
5070                 log_error("Could not allocate message.");
5071                 r = -ENOMEM;
5072                 goto finish;
5073         }
5074
5075         dbus_message_iter_init_append(m, &iter);
5076
5077         env1_buf[sizeof(env1_buf)-2] = rl;
5078         env2_buf[sizeof(env2_buf)-2] = previous;
5079
5080         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5081             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5082             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5083             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5084             !dbus_message_iter_close_container(&iter, &sub) ||
5085             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5086                 log_error("Could not append arguments to message.");
5087                 r = -ENOMEM;
5088                 goto finish;
5089         }
5090
5091         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5092
5093                 if (error_is_no_service(&error)) {
5094                         r = -EADDRNOTAVAIL;
5095                         goto finish;
5096                 }
5097
5098                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5099                 r = -EIO;
5100                 goto finish;
5101         }
5102
5103         r = 1;
5104
5105 finish:
5106         if (m)
5107                 dbus_message_unref(m);
5108
5109         if (reply)
5110                 dbus_message_unref(reply);
5111
5112         if (bus) {
5113                 dbus_connection_flush(bus);
5114                 dbus_connection_close(bus);
5115                 dbus_connection_unref(bus);
5116         }
5117
5118         dbus_error_free(&error);
5119
5120         return r;
5121 }
5122
5123 static int talk_initctl(void) {
5124         struct init_request request;
5125         int r, fd;
5126         char rl;
5127
5128         if (!(rl = action_to_runlevel()))
5129                 return 0;
5130
5131         zero(request);
5132         request.magic = INIT_MAGIC;
5133         request.sleeptime = 0;
5134         request.cmd = INIT_CMD_RUNLVL;
5135         request.runlevel = rl;
5136
5137         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5138
5139                 if (errno == ENOENT)
5140                         return 0;
5141
5142                 log_error("Failed to open "INIT_FIFO": %m");
5143                 return -errno;
5144         }
5145
5146         errno = 0;
5147         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5148         close_nointr_nofail(fd);
5149
5150         if (r < 0) {
5151                 log_error("Failed to write to "INIT_FIFO": %m");
5152                 return errno ? -errno : -EIO;
5153         }
5154
5155         return 1;
5156 }
5157
5158 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5159
5160         static const struct {
5161                 const char* verb;
5162                 const enum {
5163                         MORE,
5164                         LESS,
5165                         EQUAL
5166                 } argc_cmp;
5167                 const int argc;
5168                 int (* const dispatch)(DBusConnection *bus, char **args);
5169         } verbs[] = {
5170                 { "list-units",            LESS,  1, list_units        },
5171                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5172                 { "list-jobs",             EQUAL, 1, list_jobs         },
5173                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5174                 { "load",                  MORE,  2, load_unit         },
5175                 { "cancel",                MORE,  2, cancel_job        },
5176                 { "start",                 MORE,  2, start_unit        },
5177                 { "stop",                  MORE,  2, start_unit        },
5178                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5179                 { "reload",                MORE,  2, start_unit        },
5180                 { "restart",               MORE,  2, start_unit        },
5181                 { "try-restart",           MORE,  2, start_unit        },
5182                 { "reload-or-restart",     MORE,  2, start_unit        },
5183                 { "reload-or-try-restart", MORE,  2, start_unit        },
5184                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5185                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5186                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5187                 { "isolate",               EQUAL, 2, start_unit        },
5188                 { "kill",                  MORE,  2, kill_unit         },
5189                 { "is-active",             MORE,  2, check_unit        },
5190                 { "check",                 MORE,  2, check_unit        },
5191                 { "show",                  MORE,  1, show              },
5192                 { "status",                MORE,  2, show              },
5193                 { "dump",                  EQUAL, 1, dump              },
5194                 { "dot",                   EQUAL, 1, dot               },
5195                 { "snapshot",              LESS,  2, snapshot          },
5196                 { "delete",                MORE,  2, delete_snapshot   },
5197                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5198                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5199                 { "show-environment",      EQUAL, 1, show_enviroment   },
5200                 { "set-environment",       MORE,  2, set_environment   },
5201                 { "unset-environment",     MORE,  2, set_environment   },
5202                 { "halt",                  EQUAL, 1, start_special     },
5203                 { "poweroff",              EQUAL, 1, start_special     },
5204                 { "reboot",                EQUAL, 1, start_special     },
5205                 { "kexec",                 EQUAL, 1, start_special     },
5206                 { "suspend",               EQUAL, 1, start_special     },
5207                 { "hibernate",             EQUAL, 1, start_special     },
5208                 { "default",               EQUAL, 1, start_special     },
5209                 { "rescue",                EQUAL, 1, start_special     },
5210                 { "emergency",             EQUAL, 1, start_special     },
5211                 { "exit",                  EQUAL, 1, start_special     },
5212                 { "reset-failed",          MORE,  1, reset_failed      },
5213                 { "enable",                MORE,  2, enable_unit       },
5214                 { "disable",               MORE,  2, enable_unit       },
5215                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5216                 { "reenable",              MORE,  2, enable_unit       },
5217                 { "preset",                MORE,  2, enable_unit       },
5218                 { "mask",                  MORE,  2, enable_unit       },
5219                 { "unmask",                MORE,  2, enable_unit       },
5220                 { "link",                  MORE,  2, enable_unit       },
5221                 { "switch-root",           MORE,  2, switch_root       },
5222         };
5223
5224         int left;
5225         unsigned i;
5226
5227         assert(argc >= 0);
5228         assert(argv);
5229         assert(error);
5230
5231         left = argc - optind;
5232
5233         if (left <= 0)
5234                 /* Special rule: no arguments means "list-units" */
5235                 i = 0;
5236         else {
5237                 if (streq(argv[optind], "help")) {
5238                         systemctl_help();
5239                         return 0;
5240                 }
5241
5242                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5243                         if (streq(argv[optind], verbs[i].verb))
5244                                 break;
5245
5246                 if (i >= ELEMENTSOF(verbs)) {
5247                         log_error("Unknown operation %s", argv[optind]);
5248                         return -EINVAL;
5249                 }
5250         }
5251
5252         switch (verbs[i].argc_cmp) {
5253
5254         case EQUAL:
5255                 if (left != verbs[i].argc) {
5256                         log_error("Invalid number of arguments.");
5257                         return -EINVAL;
5258                 }
5259
5260                 break;
5261
5262         case MORE:
5263                 if (left < verbs[i].argc) {
5264                         log_error("Too few arguments.");
5265                         return -EINVAL;
5266                 }
5267
5268                 break;
5269
5270         case LESS:
5271                 if (left > verbs[i].argc) {
5272                         log_error("Too many arguments.");
5273                         return -EINVAL;
5274                 }
5275
5276                 break;
5277
5278         default:
5279                 assert_not_reached("Unknown comparison operator.");
5280         }
5281
5282         /* Require a bus connection for all operations but
5283          * enable/disable */
5284         if (!streq(verbs[i].verb, "enable") &&
5285             !streq(verbs[i].verb, "disable") &&
5286             !streq(verbs[i].verb, "is-enabled") &&
5287             !streq(verbs[i].verb, "list-unit-files") &&
5288             !streq(verbs[i].verb, "reenable") &&
5289             !streq(verbs[i].verb, "preset") &&
5290             !streq(verbs[i].verb, "mask") &&
5291             !streq(verbs[i].verb, "unmask") &&
5292             !streq(verbs[i].verb, "link")) {
5293
5294                 if (running_in_chroot() > 0) {
5295                         log_info("Running in chroot, ignoring request.");
5296                         return 0;
5297                 }
5298
5299                 if (((!streq(verbs[i].verb, "reboot") &&
5300                       !streq(verbs[i].verb, "halt") &&
5301                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5302                         log_error("Failed to get D-Bus connection: %s",
5303                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5304                         return -EIO;
5305                 }
5306
5307         } else {
5308
5309                 if (!bus && !avoid_bus()) {
5310                         log_error("Failed to get D-Bus connection: %s",
5311                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5312                         return -EIO;
5313                 }
5314         }
5315
5316         return verbs[i].dispatch(bus, argv + optind);
5317 }
5318
5319 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5320         int fd;
5321         struct msghdr msghdr;
5322         struct iovec iovec[2];
5323         union sockaddr_union sockaddr;
5324         struct sd_shutdown_command c;
5325
5326         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5327         if (fd < 0)
5328                 return -errno;
5329
5330         zero(c);
5331         c.usec = t;
5332         c.mode = mode;
5333         c.dry_run = dry_run;
5334         c.warn_wall = warn;
5335
5336         zero(sockaddr);
5337         sockaddr.sa.sa_family = AF_UNIX;
5338         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5339
5340         zero(msghdr);
5341         msghdr.msg_name = &sockaddr;
5342         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5343
5344         zero(iovec);
5345         iovec[0].iov_base = (char*) &c;
5346         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5347
5348         if (isempty(message))
5349                 msghdr.msg_iovlen = 1;
5350         else {
5351                 iovec[1].iov_base = (char*) message;
5352                 iovec[1].iov_len = strlen(message);
5353                 msghdr.msg_iovlen = 2;
5354         }
5355         msghdr.msg_iov = iovec;
5356
5357         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5358                 close_nointr_nofail(fd);
5359                 return -errno;
5360         }
5361
5362         close_nointr_nofail(fd);
5363         return 0;
5364 }
5365
5366 static int reload_with_fallback(DBusConnection *bus) {
5367
5368         if (bus) {
5369                 /* First, try systemd via D-Bus. */
5370                 if (daemon_reload(bus, NULL) >= 0)
5371                         return 0;
5372         }
5373
5374         /* Nothing else worked, so let's try signals */
5375         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5376
5377         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5378                 log_error("kill() failed: %m");
5379                 return -errno;
5380         }
5381
5382         return 0;
5383 }
5384
5385 static int start_with_fallback(DBusConnection *bus) {
5386
5387         if (bus) {
5388                 /* First, try systemd via D-Bus. */
5389                 if (start_unit(bus, NULL) >= 0)
5390                         goto done;
5391         }
5392
5393         /* Hmm, talking to systemd via D-Bus didn't work. Then
5394          * let's try to talk to Upstart via D-Bus. */
5395         if (talk_upstart() > 0)
5396                 goto done;
5397
5398         /* Nothing else worked, so let's try
5399          * /dev/initctl */
5400         if (talk_initctl() > 0)
5401                 goto done;
5402
5403         log_error("Failed to talk to init daemon.");
5404         return -EIO;
5405
5406 done:
5407         warn_wall(arg_action);
5408         return 0;
5409 }
5410
5411 static void halt_now(enum action a) {
5412
5413        /* Make sure C-A-D is handled by the kernel from this
5414          * point on... */
5415         reboot(RB_ENABLE_CAD);
5416
5417         switch (a) {
5418
5419         case ACTION_HALT:
5420                 log_info("Halting.");
5421                 reboot(RB_HALT_SYSTEM);
5422                 break;
5423
5424         case ACTION_POWEROFF:
5425                 log_info("Powering off.");
5426                 reboot(RB_POWER_OFF);
5427                 break;
5428
5429         case ACTION_REBOOT:
5430                 log_info("Rebooting.");
5431                 reboot(RB_AUTOBOOT);
5432                 break;
5433
5434         default:
5435                 assert_not_reached("Unknown halt action.");
5436         }
5437
5438         assert_not_reached("Uh? This shouldn't happen.");
5439 }
5440
5441 static int halt_main(DBusConnection *bus) {
5442         int r;
5443
5444         if (geteuid() != 0) {
5445                 /* Try logind if we are a normal user and no special
5446                  * mode applies. Maybe PolicyKit allows us to shutdown
5447                  * the machine. */
5448
5449                 if (arg_when <= 0 &&
5450                     !arg_dry &&
5451                     !arg_force &&
5452                     (arg_action == ACTION_POWEROFF ||
5453                      arg_action == ACTION_REBOOT)) {
5454                         r = reboot_with_logind(bus, arg_action);
5455                         if (r >= 0)
5456                                 return r;
5457                 }
5458
5459                 log_error("Must be root.");
5460                 return -EPERM;
5461         }
5462
5463         if (arg_when > 0) {
5464                 char *m;
5465
5466                 m = strv_join(arg_wall, " ");
5467                 r = send_shutdownd(arg_when,
5468                                    arg_action == ACTION_HALT     ? 'H' :
5469                                    arg_action == ACTION_POWEROFF ? 'P' :
5470                                    arg_action == ACTION_KEXEC    ? 'K' :
5471                                                                    'r',
5472                                    arg_dry,
5473                                    !arg_no_wall,
5474                                    m);
5475                 free(m);
5476
5477                 if (r < 0)
5478                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5479                 else {
5480                         char date[FORMAT_TIMESTAMP_MAX];
5481
5482                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5483                                  format_timestamp(date, sizeof(date), arg_when));
5484                         return 0;
5485                 }
5486         }
5487
5488         if (!arg_dry && !arg_force)
5489                 return start_with_fallback(bus);
5490
5491         if (!arg_no_wtmp) {
5492                 if (sd_booted() > 0)
5493                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5494                 else {
5495                         r = utmp_put_shutdown();
5496                         if (r < 0)
5497                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5498                 }
5499         }
5500
5501         if (!arg_no_sync)
5502                 sync();
5503
5504         if (arg_dry)
5505                 return 0;
5506
5507         halt_now(arg_action);
5508         /* We should never reach this. */
5509         return -ENOSYS;
5510 }
5511
5512 static int runlevel_main(void) {
5513         int r, runlevel, previous;
5514
5515         r = utmp_get_runlevel(&runlevel, &previous);
5516         if (r < 0) {
5517                 puts("unknown");
5518                 return r;
5519         }
5520
5521         printf("%c %c\n",
5522                previous <= 0 ? 'N' : previous,
5523                runlevel <= 0 ? 'N' : runlevel);
5524
5525         return 0;
5526 }
5527
5528 int main(int argc, char*argv[]) {
5529         int r, retval = EXIT_FAILURE;
5530         DBusConnection *bus = NULL;
5531         DBusError error;
5532
5533         dbus_error_init(&error);
5534
5535         log_parse_environment();
5536         log_open();
5537
5538         r = parse_argv(argc, argv);
5539         if (r < 0)
5540                 goto finish;
5541         else if (r == 0) {
5542                 retval = EXIT_SUCCESS;
5543                 goto finish;
5544         }
5545
5546         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5547          * let's shortcut this */
5548         if (arg_action == ACTION_RUNLEVEL) {
5549                 r = runlevel_main();
5550                 retval = r < 0 ? EXIT_FAILURE : r;
5551                 goto finish;
5552         }
5553
5554         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5555                 log_info("Running in chroot, ignoring request.");
5556                 retval = 0;
5557                 goto finish;
5558         }
5559
5560         if (!avoid_bus()) {
5561                 if (arg_transport == TRANSPORT_NORMAL)
5562                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5563                 else if (arg_transport == TRANSPORT_POLKIT) {
5564                         bus_connect_system_polkit(&bus, &error);
5565                         private_bus = false;
5566                 } else if (arg_transport == TRANSPORT_SSH) {
5567                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5568                         private_bus = false;
5569                 } else
5570                         assert_not_reached("Uh, invalid transport...");
5571         }
5572
5573         switch (arg_action) {
5574
5575         case ACTION_SYSTEMCTL:
5576                 r = systemctl_main(bus, argc, argv, &error);
5577                 break;
5578
5579         case ACTION_HALT:
5580         case ACTION_POWEROFF:
5581         case ACTION_REBOOT:
5582         case ACTION_KEXEC:
5583                 r = halt_main(bus);
5584                 break;
5585
5586         case ACTION_RUNLEVEL2:
5587         case ACTION_RUNLEVEL3:
5588         case ACTION_RUNLEVEL4:
5589         case ACTION_RUNLEVEL5:
5590         case ACTION_RESCUE:
5591         case ACTION_EMERGENCY:
5592         case ACTION_DEFAULT:
5593                 r = start_with_fallback(bus);
5594                 break;
5595
5596         case ACTION_RELOAD:
5597         case ACTION_REEXEC:
5598                 r = reload_with_fallback(bus);
5599                 break;
5600
5601         case ACTION_CANCEL_SHUTDOWN:
5602                 r = send_shutdownd(0, 0, false, false, NULL);
5603                 break;
5604
5605         case ACTION_INVALID:
5606         case ACTION_RUNLEVEL:
5607         default:
5608                 assert_not_reached("Unknown action");
5609         }
5610
5611         retval = r < 0 ? EXIT_FAILURE : r;
5612
5613 finish:
5614         if (bus) {
5615                 dbus_connection_flush(bus);
5616                 dbus_connection_close(bus);
5617                 dbus_connection_unref(bus);
5618         }
5619
5620         dbus_error_free(&error);
5621
5622         dbus_shutdown();
5623
5624         strv_free(arg_property);
5625
5626         pager_close();
5627         ask_password_agent_close();
5628         polkit_agent_close();
5629
5630         return retval;
5631 }