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