chiark / gitweb /
cbe6848d0335faf3f73d022207db67b3210289bf
[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 && geteuid() != 0) {
1792                 log_error("Must be root.");
1793                 return -EPERM;
1794         }
1795
1796         if (arg_force >= 2 &&
1797             (a == ACTION_HALT ||
1798              a == ACTION_POWEROFF ||
1799              a == ACTION_REBOOT))
1800                 halt_now(a);
1801
1802         if (arg_force >= 1 &&
1803             (a == ACTION_HALT ||
1804              a == ACTION_POWEROFF ||
1805              a == ACTION_REBOOT ||
1806              a == ACTION_KEXEC ||
1807              a == ACTION_EXIT))
1808                 return daemon_reload(bus, args);
1809
1810         /* first try logind, to allow authentication with polkit */
1811         if (geteuid() != 0 &&
1812             (a == ACTION_POWEROFF ||
1813              a == ACTION_REBOOT)) {
1814                 r = reboot_with_logind(bus, a);
1815                 if (r >= 0)
1816                         return r;
1817         }
1818
1819         r = start_unit(bus, args);
1820         if (r >= 0)
1821                 warn_wall(a);
1822
1823         return r;
1824 }
1825
1826 static int check_unit(DBusConnection *bus, char **args) {
1827         DBusMessage *m = NULL, *reply = NULL;
1828         const char
1829                 *interface = "org.freedesktop.systemd1.Unit",
1830                 *property = "ActiveState";
1831         int r = 3; /* According to LSB: "program is not running" */
1832         DBusError error;
1833         char **name;
1834
1835         assert(bus);
1836         assert(args);
1837
1838         dbus_error_init(&error);
1839
1840         STRV_FOREACH(name, args+1) {
1841                 const char *path = NULL;
1842                 const char *state;
1843                 DBusMessageIter iter, sub;
1844
1845                 if (!(m = dbus_message_new_method_call(
1846                                       "org.freedesktop.systemd1",
1847                                       "/org/freedesktop/systemd1",
1848                                       "org.freedesktop.systemd1.Manager",
1849                                       "GetUnit"))) {
1850                         log_error("Could not allocate message.");
1851                         r = -ENOMEM;
1852                         goto finish;
1853                 }
1854
1855                 if (!dbus_message_append_args(m,
1856                                               DBUS_TYPE_STRING, name,
1857                                               DBUS_TYPE_INVALID)) {
1858                         log_error("Could not append arguments to message.");
1859                         r = -ENOMEM;
1860                         goto finish;
1861                 }
1862
1863                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1864
1865                         /* Hmm, cannot figure out anything about this unit... */
1866                         if (!arg_quiet)
1867                                 puts("unknown");
1868
1869                         dbus_error_free(&error);
1870                         dbus_message_unref(m);
1871                         m = NULL;
1872                         continue;
1873                 }
1874
1875                 if (!dbus_message_get_args(reply, &error,
1876                                            DBUS_TYPE_OBJECT_PATH, &path,
1877                                            DBUS_TYPE_INVALID)) {
1878                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1879                         r = -EIO;
1880                         goto finish;
1881                 }
1882
1883                 dbus_message_unref(m);
1884                 if (!(m = dbus_message_new_method_call(
1885                                       "org.freedesktop.systemd1",
1886                                       path,
1887                                       "org.freedesktop.DBus.Properties",
1888                                       "Get"))) {
1889                         log_error("Could not allocate message.");
1890                         r = -ENOMEM;
1891                         goto finish;
1892                 }
1893
1894                 if (!dbus_message_append_args(m,
1895                                               DBUS_TYPE_STRING, &interface,
1896                                               DBUS_TYPE_STRING, &property,
1897                                               DBUS_TYPE_INVALID)) {
1898                         log_error("Could not append arguments to message.");
1899                         r = -ENOMEM;
1900                         goto finish;
1901                 }
1902
1903                 dbus_message_unref(reply);
1904                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1905                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1906                         r = -EIO;
1907                         goto finish;
1908                 }
1909
1910                 if (!dbus_message_iter_init(reply, &iter) ||
1911                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1912                         log_error("Failed to parse reply.");
1913                         r = -EIO;
1914                         goto finish;
1915                 }
1916
1917                 dbus_message_iter_recurse(&iter, &sub);
1918
1919                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1920                         log_error("Failed to parse reply.");
1921                         r = -EIO;
1922                         goto finish;
1923                 }
1924
1925                 dbus_message_iter_get_basic(&sub, &state);
1926
1927                 if (!arg_quiet)
1928                         puts(state);
1929
1930                 if (streq(state, "active") || streq(state, "reloading"))
1931                         r = 0;
1932
1933                 dbus_message_unref(m);
1934                 dbus_message_unref(reply);
1935                 m = reply = NULL;
1936         }
1937
1938 finish:
1939         if (m)
1940                 dbus_message_unref(m);
1941
1942         if (reply)
1943                 dbus_message_unref(reply);
1944
1945         dbus_error_free(&error);
1946
1947         return r;
1948 }
1949
1950 static int kill_unit(DBusConnection *bus, char **args) {
1951         DBusMessage *m = NULL;
1952         int r = 0;
1953         DBusError error;
1954         char **name;
1955
1956         assert(bus);
1957         assert(args);
1958
1959         dbus_error_init(&error);
1960
1961         if (!arg_kill_who)
1962                 arg_kill_who = "all";
1963
1964         if (!arg_kill_mode)
1965                 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
1966
1967         STRV_FOREACH(name, args+1) {
1968                 DBusMessage *reply;
1969
1970                 if (!(m = dbus_message_new_method_call(
1971                                       "org.freedesktop.systemd1",
1972                                       "/org/freedesktop/systemd1",
1973                                       "org.freedesktop.systemd1.Manager",
1974                                       "KillUnit"))) {
1975                         log_error("Could not allocate message.");
1976                         r = -ENOMEM;
1977                         goto finish;
1978                 }
1979
1980                 if (!dbus_message_append_args(m,
1981                                               DBUS_TYPE_STRING, name,
1982                                               DBUS_TYPE_STRING, &arg_kill_who,
1983                                               DBUS_TYPE_STRING, &arg_kill_mode,
1984                                               DBUS_TYPE_INT32, &arg_signal,
1985                                               DBUS_TYPE_INVALID)) {
1986                         log_error("Could not append arguments to message.");
1987                         r = -ENOMEM;
1988                         goto finish;
1989                 }
1990
1991                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1992                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1993                         dbus_error_free(&error);
1994                         r = -EIO;
1995                 }
1996
1997                 dbus_message_unref(m);
1998
1999                 if (reply)
2000                         dbus_message_unref(reply);
2001                 m = reply = NULL;
2002         }
2003
2004 finish:
2005         if (m)
2006                 dbus_message_unref(m);
2007
2008         dbus_error_free(&error);
2009
2010         return r;
2011 }
2012
2013 typedef struct ExecStatusInfo {
2014         char *name;
2015
2016         char *path;
2017         char **argv;
2018
2019         bool ignore;
2020
2021         usec_t start_timestamp;
2022         usec_t exit_timestamp;
2023         pid_t pid;
2024         int code;
2025         int status;
2026
2027         LIST_FIELDS(struct ExecStatusInfo, exec);
2028 } ExecStatusInfo;
2029
2030 static void exec_status_info_free(ExecStatusInfo *i) {
2031         assert(i);
2032
2033         free(i->name);
2034         free(i->path);
2035         strv_free(i->argv);
2036         free(i);
2037 }
2038
2039 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
2040         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
2041         DBusMessageIter sub2, sub3;
2042         const char*path;
2043         unsigned n;
2044         uint32_t pid;
2045         int32_t code, status;
2046         dbus_bool_t ignore;
2047
2048         assert(i);
2049         assert(i);
2050
2051         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2052                 return -EIO;
2053
2054         dbus_message_iter_recurse(sub, &sub2);
2055
2056         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2057                 return -EIO;
2058
2059         if (!(i->path = strdup(path)))
2060                 return -ENOMEM;
2061
2062         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2063             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2064                 return -EIO;
2065
2066         n = 0;
2067         dbus_message_iter_recurse(&sub2, &sub3);
2068         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2069                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2070                 dbus_message_iter_next(&sub3);
2071                 n++;
2072         }
2073
2074
2075         if (!(i->argv = new0(char*, n+1)))
2076                 return -ENOMEM;
2077
2078         n = 0;
2079         dbus_message_iter_recurse(&sub2, &sub3);
2080         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2081                 const char *s;
2082
2083                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2084                 dbus_message_iter_get_basic(&sub3, &s);
2085                 dbus_message_iter_next(&sub3);
2086
2087                 if (!(i->argv[n++] = strdup(s)))
2088                         return -ENOMEM;
2089         }
2090
2091         if (!dbus_message_iter_next(&sub2) ||
2092             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
2093             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
2094             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
2095             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
2096             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
2097             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2098             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2099             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2100                 return -EIO;
2101
2102         i->ignore = ignore;
2103         i->start_timestamp = (usec_t) start_timestamp;
2104         i->exit_timestamp = (usec_t) exit_timestamp;
2105         i->pid = (pid_t) pid;
2106         i->code = code;
2107         i->status = status;
2108
2109         return 0;
2110 }
2111
2112 typedef struct UnitStatusInfo {
2113         const char *id;
2114         const char *load_state;
2115         const char *active_state;
2116         const char *sub_state;
2117         const char *unit_file_state;
2118
2119         const char *description;
2120         const char *following;
2121
2122         const char *path;
2123         const char *default_control_group;
2124
2125         const char *load_error;
2126         const char *result;
2127
2128         usec_t inactive_exit_timestamp;
2129         usec_t inactive_exit_timestamp_monotonic;
2130         usec_t active_enter_timestamp;
2131         usec_t active_exit_timestamp;
2132         usec_t inactive_enter_timestamp;
2133
2134         bool need_daemon_reload;
2135
2136         /* Service */
2137         pid_t main_pid;
2138         pid_t control_pid;
2139         const char *status_text;
2140         bool running:1;
2141 #ifdef HAVE_SYSV_COMPAT
2142         bool is_sysv:1;
2143 #endif
2144
2145         usec_t start_timestamp;
2146         usec_t exit_timestamp;
2147
2148         int exit_code, exit_status;
2149
2150         usec_t condition_timestamp;
2151         bool condition_result;
2152
2153         /* Socket */
2154         unsigned n_accepted;
2155         unsigned n_connections;
2156         bool accept;
2157
2158         /* Device */
2159         const char *sysfs_path;
2160
2161         /* Mount, Automount */
2162         const char *where;
2163
2164         /* Swap */
2165         const char *what;
2166
2167         LIST_HEAD(ExecStatusInfo, exec);
2168 } UnitStatusInfo;
2169
2170 static void print_status_info(UnitStatusInfo *i) {
2171         ExecStatusInfo *p;
2172         const char *on, *off, *ss;
2173         usec_t timestamp;
2174         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2175         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2176
2177         assert(i);
2178
2179         /* This shows pretty information about a unit. See
2180          * print_property() for a low-level property printer */
2181
2182         printf("%s", strna(i->id));
2183
2184         if (i->description && !streq_ptr(i->id, i->description))
2185                 printf(" - %s", i->description);
2186
2187         printf("\n");
2188
2189         if (i->following)
2190                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2191
2192         if (streq_ptr(i->load_state, "error")) {
2193                 on = ansi_highlight_red(true);
2194                 off = ansi_highlight_red(false);
2195         } else
2196                 on = off = "";
2197
2198         if (i->load_error)
2199                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2200         else if (i->path && i->unit_file_state)
2201                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state);
2202         else if (i->path)
2203                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
2204         else
2205                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2206
2207         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2208
2209         if (streq_ptr(i->active_state, "failed")) {
2210                 on = ansi_highlight_red(true);
2211                 off = ansi_highlight_red(false);
2212         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2213                 on = ansi_highlight_green(true);
2214                 off = ansi_highlight_green(false);
2215         } else
2216                 on = off = "";
2217
2218         if (ss)
2219                 printf("\t  Active: %s%s (%s)%s",
2220                        on,
2221                        strna(i->active_state),
2222                        ss,
2223                        off);
2224         else
2225                 printf("\t  Active: %s%s%s",
2226                        on,
2227                        strna(i->active_state),
2228                        off);
2229
2230         if (!isempty(i->result) && !streq(i->result, "success"))
2231                 printf(" (Result: %s)", i->result);
2232
2233         timestamp = (streq_ptr(i->active_state, "active")      ||
2234                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2235                     (streq_ptr(i->active_state, "inactive")    ||
2236                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2237                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2238                                                                   i->active_exit_timestamp;
2239
2240         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2241         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2242
2243         if (s1)
2244                 printf(" since %s; %s\n", s2, s1);
2245         else if (s2)
2246                 printf(" since %s\n", s2);
2247         else
2248                 printf("\n");
2249
2250         if (!i->condition_result && i->condition_timestamp > 0) {
2251                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2252                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2253
2254                 if (s1)
2255                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2256                 else if (s2)
2257                         printf("\t          start condition failed at %s\n", s2);
2258         }
2259
2260         if (i->sysfs_path)
2261                 printf("\t  Device: %s\n", i->sysfs_path);
2262         if (i->where)
2263                 printf("\t   Where: %s\n", i->where);
2264         if (i->what)
2265                 printf("\t    What: %s\n", i->what);
2266
2267         if (i->accept)
2268                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2269
2270         LIST_FOREACH(exec, p, i->exec) {
2271                 char *t;
2272                 bool good;
2273
2274                 /* Only show exited processes here */
2275                 if (p->code == 0)
2276                         continue;
2277
2278                 t = strv_join(p->argv, " ");
2279                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2280                 free(t);
2281
2282 #ifdef HAVE_SYSV_COMPAT
2283                 if (i->is_sysv)
2284                         good = is_clean_exit_lsb(p->code, p->status);
2285                 else
2286 #endif
2287                         good = is_clean_exit(p->code, p->status);
2288
2289                 if (!good) {
2290                         on = ansi_highlight_red(true);
2291                         off = ansi_highlight_red(false);
2292                 } else
2293                         on = off = "";
2294
2295                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2296
2297                 if (p->code == CLD_EXITED) {
2298                         const char *c;
2299
2300                         printf("status=%i", p->status);
2301
2302 #ifdef HAVE_SYSV_COMPAT
2303                         if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2304 #else
2305                         if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
2306 #endif
2307                                 printf("/%s", c);
2308
2309                 } else
2310                         printf("signal=%s", signal_to_string(p->status));
2311
2312                 printf(")%s\n", off);
2313
2314                 if (i->main_pid == p->pid &&
2315                     i->start_timestamp == p->start_timestamp &&
2316                     i->exit_timestamp == p->start_timestamp)
2317                         /* Let's not show this twice */
2318                         i->main_pid = 0;
2319
2320                 if (p->pid == i->control_pid)
2321                         i->control_pid = 0;
2322         }
2323
2324         if (i->main_pid > 0 || i->control_pid > 0) {
2325                 printf("\t");
2326
2327                 if (i->main_pid > 0) {
2328                         printf("Main PID: %u", (unsigned) i->main_pid);
2329
2330                         if (i->running) {
2331                                 char *t = NULL;
2332                                 get_process_comm(i->main_pid, &t);
2333                                 if (t) {
2334                                         printf(" (%s)", t);
2335                                         free(t);
2336                                 }
2337                         } else if (i->exit_code > 0) {
2338                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2339
2340                                 if (i->exit_code == CLD_EXITED) {
2341                                         const char *c;
2342
2343                                         printf("status=%i", i->exit_status);
2344
2345 #ifdef HAVE_SYSV_COMPAT
2346                                         if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2347 #else
2348                                         if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
2349 #endif
2350                                                 printf("/%s", c);
2351
2352                                 } else
2353                                         printf("signal=%s", signal_to_string(i->exit_status));
2354                                 printf(")");
2355                         }
2356                 }
2357
2358                 if (i->main_pid > 0 && i->control_pid > 0)
2359                         printf(";");
2360
2361                 if (i->control_pid > 0) {
2362                         char *t = NULL;
2363
2364                         printf(" Control: %u", (unsigned) i->control_pid);
2365
2366                         get_process_comm(i->control_pid, &t);
2367                         if (t) {
2368                                 printf(" (%s)", t);
2369                                 free(t);
2370                         }
2371                 }
2372
2373                 printf("\n");
2374         }
2375
2376         if (i->status_text)
2377                 printf("\t  Status: \"%s\"\n", i->status_text);
2378
2379         if (i->default_control_group) {
2380                 unsigned c;
2381
2382                 printf("\t  CGroup: %s\n", i->default_control_group);
2383
2384                 if (arg_transport != TRANSPORT_SSH) {
2385                         unsigned k = 0;
2386                         pid_t extra[2];
2387
2388                         c = columns();
2389                         if (c > 18)
2390                                 c -= 18;
2391                         else
2392                                 c = 0;
2393
2394                         if (i->main_pid > 0)
2395                                 extra[k++] = i->main_pid;
2396
2397                         if (i->control_pid > 0)
2398                                 extra[k++] = i->control_pid;
2399
2400                         show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, extra, k);
2401                 }
2402         }
2403
2404         if (i->id && arg_transport != TRANSPORT_SSH) {
2405                 printf("\n");
2406                 show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
2407         }
2408
2409         if (i->need_daemon_reload)
2410                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2411                        ansi_highlight_red(true),
2412                        ansi_highlight_red(false),
2413                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2414 }
2415
2416 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2417
2418         assert(name);
2419         assert(iter);
2420         assert(i);
2421
2422         switch (dbus_message_iter_get_arg_type(iter)) {
2423
2424         case DBUS_TYPE_STRING: {
2425                 const char *s;
2426
2427                 dbus_message_iter_get_basic(iter, &s);
2428
2429                 if (!isempty(s)) {
2430                         if (streq(name, "Id"))
2431                                 i->id = s;
2432                         else if (streq(name, "LoadState"))
2433                                 i->load_state = s;
2434                         else if (streq(name, "ActiveState"))
2435                                 i->active_state = s;
2436                         else if (streq(name, "SubState"))
2437                                 i->sub_state = s;
2438                         else if (streq(name, "Description"))
2439                                 i->description = s;
2440                         else if (streq(name, "FragmentPath"))
2441                                 i->path = s;
2442 #ifdef HAVE_SYSV_COMPAT
2443                         else if (streq(name, "SysVPath")) {
2444                                 i->is_sysv = true;
2445                                 i->path = s;
2446                         }
2447 #endif
2448                         else if (streq(name, "DefaultControlGroup"))
2449                                 i->default_control_group = s;
2450                         else if (streq(name, "StatusText"))
2451                                 i->status_text = s;
2452                         else if (streq(name, "SysFSPath"))
2453                                 i->sysfs_path = s;
2454                         else if (streq(name, "Where"))
2455                                 i->where = s;
2456                         else if (streq(name, "What"))
2457                                 i->what = s;
2458                         else if (streq(name, "Following"))
2459                                 i->following = s;
2460                         else if (streq(name, "UnitFileState"))
2461                                 i->unit_file_state = s;
2462                         else if (streq(name, "Result"))
2463                                 i->result = s;
2464                 }
2465
2466                 break;
2467         }
2468
2469         case DBUS_TYPE_BOOLEAN: {
2470                 dbus_bool_t b;
2471
2472                 dbus_message_iter_get_basic(iter, &b);
2473
2474                 if (streq(name, "Accept"))
2475                         i->accept = b;
2476                 else if (streq(name, "NeedDaemonReload"))
2477                         i->need_daemon_reload = b;
2478                 else if (streq(name, "ConditionResult"))
2479                         i->condition_result = b;
2480
2481                 break;
2482         }
2483
2484         case DBUS_TYPE_UINT32: {
2485                 uint32_t u;
2486
2487                 dbus_message_iter_get_basic(iter, &u);
2488
2489                 if (streq(name, "MainPID")) {
2490                         if (u > 0) {
2491                                 i->main_pid = (pid_t) u;
2492                                 i->running = true;
2493                         }
2494                 } else if (streq(name, "ControlPID"))
2495                         i->control_pid = (pid_t) u;
2496                 else if (streq(name, "ExecMainPID")) {
2497                         if (u > 0)
2498                                 i->main_pid = (pid_t) u;
2499                 } else if (streq(name, "NAccepted"))
2500                         i->n_accepted = u;
2501                 else if (streq(name, "NConnections"))
2502                         i->n_connections = u;
2503
2504                 break;
2505         }
2506
2507         case DBUS_TYPE_INT32: {
2508                 int32_t j;
2509
2510                 dbus_message_iter_get_basic(iter, &j);
2511
2512                 if (streq(name, "ExecMainCode"))
2513                         i->exit_code = (int) j;
2514                 else if (streq(name, "ExecMainStatus"))
2515                         i->exit_status = (int) j;
2516
2517                 break;
2518         }
2519
2520         case DBUS_TYPE_UINT64: {
2521                 uint64_t u;
2522
2523                 dbus_message_iter_get_basic(iter, &u);
2524
2525                 if (streq(name, "ExecMainStartTimestamp"))
2526                         i->start_timestamp = (usec_t) u;
2527                 else if (streq(name, "ExecMainExitTimestamp"))
2528                         i->exit_timestamp = (usec_t) u;
2529                 else if (streq(name, "ActiveEnterTimestamp"))
2530                         i->active_enter_timestamp = (usec_t) u;
2531                 else if (streq(name, "InactiveEnterTimestamp"))
2532                         i->inactive_enter_timestamp = (usec_t) u;
2533                 else if (streq(name, "InactiveExitTimestamp"))
2534                         i->inactive_exit_timestamp = (usec_t) u;
2535                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2536                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2537                 else if (streq(name, "ActiveExitTimestamp"))
2538                         i->active_exit_timestamp = (usec_t) u;
2539                 else if (streq(name, "ConditionTimestamp"))
2540                         i->condition_timestamp = (usec_t) u;
2541
2542                 break;
2543         }
2544
2545         case DBUS_TYPE_ARRAY: {
2546
2547                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2548                     startswith(name, "Exec")) {
2549                         DBusMessageIter sub;
2550
2551                         dbus_message_iter_recurse(iter, &sub);
2552                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2553                                 ExecStatusInfo *info;
2554                                 int r;
2555
2556                                 if (!(info = new0(ExecStatusInfo, 1)))
2557                                         return -ENOMEM;
2558
2559                                 if (!(info->name = strdup(name))) {
2560                                         free(info);
2561                                         return -ENOMEM;
2562                                 }
2563
2564                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2565                                         free(info);
2566                                         return r;
2567                                 }
2568
2569                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2570
2571                                 dbus_message_iter_next(&sub);
2572                         }
2573                 }
2574
2575                 break;
2576         }
2577
2578         case DBUS_TYPE_STRUCT: {
2579
2580                 if (streq(name, "LoadError")) {
2581                         DBusMessageIter sub;
2582                         const char *n, *message;
2583                         int r;
2584
2585                         dbus_message_iter_recurse(iter, &sub);
2586
2587                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2588                         if (r < 0)
2589                                 return r;
2590
2591                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2592                         if (r < 0)
2593                                 return r;
2594
2595                         if (!isempty(message))
2596                                 i->load_error = message;
2597                 }
2598
2599                 break;
2600         }
2601         }
2602
2603         return 0;
2604 }
2605
2606 static int print_property(const char *name, DBusMessageIter *iter) {
2607         assert(name);
2608         assert(iter);
2609
2610         /* This is a low-level property printer, see
2611          * print_status_info() for the nicer output */
2612
2613         if (arg_property && !strv_find(arg_property, name))
2614                 return 0;
2615
2616         switch (dbus_message_iter_get_arg_type(iter)) {
2617
2618         case DBUS_TYPE_STRUCT: {
2619                 DBusMessageIter sub;
2620                 dbus_message_iter_recurse(iter, &sub);
2621
2622                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2623                         uint32_t u;
2624
2625                         dbus_message_iter_get_basic(&sub, &u);
2626
2627                         if (u)
2628                                 printf("%s=%u\n", name, (unsigned) u);
2629                         else if (arg_all)
2630                                 printf("%s=\n", name);
2631
2632                         return 0;
2633                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2634                         const char *s;
2635
2636                         dbus_message_iter_get_basic(&sub, &s);
2637
2638                         if (arg_all || s[0])
2639                                 printf("%s=%s\n", name, s);
2640
2641                         return 0;
2642                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2643                         const char *a = NULL, *b = NULL;
2644
2645                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2646                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2647
2648                         if (arg_all || !isempty(a) || !isempty(b))
2649                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2650
2651                         return 0;
2652                 }
2653
2654                 break;
2655         }
2656
2657         case DBUS_TYPE_ARRAY:
2658
2659                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2660                         DBusMessageIter sub, sub2;
2661
2662                         dbus_message_iter_recurse(iter, &sub);
2663                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2664                                 const char *path;
2665                                 dbus_bool_t ignore;
2666
2667                                 dbus_message_iter_recurse(&sub, &sub2);
2668
2669                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2670                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2671                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2672
2673                                 dbus_message_iter_next(&sub);
2674                         }
2675
2676                         return 0;
2677
2678                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2679                         DBusMessageIter sub, sub2;
2680
2681                         dbus_message_iter_recurse(iter, &sub);
2682                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2683                                 const char *type, *path;
2684
2685                                 dbus_message_iter_recurse(&sub, &sub2);
2686
2687                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2688                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2689                                         printf("%s=%s\n", type, path);
2690
2691                                 dbus_message_iter_next(&sub);
2692                         }
2693
2694                         return 0;
2695
2696                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2697                         DBusMessageIter sub, sub2;
2698
2699                         dbus_message_iter_recurse(iter, &sub);
2700                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2701                                 const char *base;
2702                                 uint64_t value, next_elapse;
2703
2704                                 dbus_message_iter_recurse(&sub, &sub2);
2705
2706                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2707                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2708                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2709                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2710
2711                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2712                                                base,
2713                                                format_timespan(timespan1, sizeof(timespan1), value),
2714                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2715                                 }
2716
2717                                 dbus_message_iter_next(&sub);
2718                         }
2719
2720                         return 0;
2721
2722                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2723                         DBusMessageIter sub, sub2;
2724
2725                         dbus_message_iter_recurse(iter, &sub);
2726                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2727                                 const char *controller, *attr, *value;
2728
2729                                 dbus_message_iter_recurse(&sub, &sub2);
2730
2731                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2732                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2733                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2734
2735                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2736                                                controller,
2737                                                attr,
2738                                                value);
2739                                 }
2740
2741                                 dbus_message_iter_next(&sub);
2742                         }
2743
2744                         return 0;
2745
2746                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2747                         DBusMessageIter sub;
2748
2749                         dbus_message_iter_recurse(iter, &sub);
2750                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2751                                 ExecStatusInfo info;
2752
2753                                 zero(info);
2754                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2755                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2756                                         char *t;
2757
2758                                         t = strv_join(info.argv, " ");
2759
2760                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2761                                                name,
2762                                                strna(info.path),
2763                                                strna(t),
2764                                                yes_no(info.ignore),
2765                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2766                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2767                                                (unsigned) info. pid,
2768                                                sigchld_code_to_string(info.code),
2769                                                info.status,
2770                                                info.code == CLD_EXITED ? "" : "/",
2771                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2772
2773                                         free(t);
2774                                 }
2775
2776                                 free(info.path);
2777                                 strv_free(info.argv);
2778
2779                                 dbus_message_iter_next(&sub);
2780                         }
2781
2782                         return 0;
2783                 }
2784
2785                 break;
2786         }
2787
2788         if (generic_print_property(name, iter, arg_all) > 0)
2789                 return 0;
2790
2791         if (arg_all)
2792                 printf("%s=[unprintable]\n", name);
2793
2794         return 0;
2795 }
2796
2797 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2798         DBusMessage *m = NULL, *reply = NULL;
2799         const char *interface = "";
2800         int r;
2801         DBusError error;
2802         DBusMessageIter iter, sub, sub2, sub3;
2803         UnitStatusInfo info;
2804         ExecStatusInfo *p;
2805
2806         assert(bus);
2807         assert(path);
2808         assert(new_line);
2809
2810         zero(info);
2811         dbus_error_init(&error);
2812
2813         if (!(m = dbus_message_new_method_call(
2814                               "org.freedesktop.systemd1",
2815                               path,
2816                               "org.freedesktop.DBus.Properties",
2817                               "GetAll"))) {
2818                 log_error("Could not allocate message.");
2819                 r = -ENOMEM;
2820                 goto finish;
2821         }
2822
2823         if (!dbus_message_append_args(m,
2824                                       DBUS_TYPE_STRING, &interface,
2825                                       DBUS_TYPE_INVALID)) {
2826                 log_error("Could not append arguments to message.");
2827                 r = -ENOMEM;
2828                 goto finish;
2829         }
2830
2831         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2832                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2833                 r = -EIO;
2834                 goto finish;
2835         }
2836
2837         if (!dbus_message_iter_init(reply, &iter) ||
2838             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2839             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2840                 log_error("Failed to parse reply.");
2841                 r = -EIO;
2842                 goto finish;
2843         }
2844
2845         dbus_message_iter_recurse(&iter, &sub);
2846
2847         if (*new_line)
2848                 printf("\n");
2849
2850         *new_line = true;
2851
2852         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2853                 const char *name;
2854
2855                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2856                         log_error("Failed to parse reply.");
2857                         r = -EIO;
2858                         goto finish;
2859                 }
2860
2861                 dbus_message_iter_recurse(&sub, &sub2);
2862
2863                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2864                         log_error("Failed to parse reply.");
2865                         r = -EIO;
2866                         goto finish;
2867                 }
2868
2869                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2870                         log_error("Failed to parse reply.");
2871                         r = -EIO;
2872                         goto finish;
2873                 }
2874
2875                 dbus_message_iter_recurse(&sub2, &sub3);
2876
2877                 if (show_properties)
2878                         r = print_property(name, &sub3);
2879                 else
2880                         r = status_property(name, &sub3, &info);
2881
2882                 if (r < 0) {
2883                         log_error("Failed to parse reply.");
2884                         r = -EIO;
2885                         goto finish;
2886                 }
2887
2888                 dbus_message_iter_next(&sub);
2889         }
2890
2891         r = 0;
2892
2893         if (!show_properties)
2894                 print_status_info(&info);
2895
2896         if (!streq_ptr(info.active_state, "active") &&
2897             !streq_ptr(info.active_state, "reloading") &&
2898             streq(verb, "status"))
2899                 /* According to LSB: "program not running" */
2900                 r = 3;
2901
2902         while ((p = info.exec)) {
2903                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2904                 exec_status_info_free(p);
2905         }
2906
2907 finish:
2908         if (m)
2909                 dbus_message_unref(m);
2910
2911         if (reply)
2912                 dbus_message_unref(reply);
2913
2914         dbus_error_free(&error);
2915
2916         return r;
2917 }
2918
2919 static int show(DBusConnection *bus, char **args) {
2920         DBusMessage *m = NULL, *reply = NULL;
2921         int r, ret = 0;
2922         DBusError error;
2923         bool show_properties, new_line = false;
2924         char **name;
2925
2926         assert(bus);
2927         assert(args);
2928
2929         dbus_error_init(&error);
2930
2931         show_properties = !streq(args[0], "status");
2932
2933         if (show_properties)
2934                 pager_open_if_enabled();
2935
2936         if (show_properties && strv_length(args) <= 1) {
2937                 /* If not argument is specified inspect the manager
2938                  * itself */
2939
2940                 ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2941                 goto finish;
2942         }
2943
2944         STRV_FOREACH(name, args+1) {
2945                 const char *path = NULL;
2946                 uint32_t id;
2947
2948                 if (safe_atou32(*name, &id) < 0) {
2949
2950                         /* Interpret as unit name */
2951
2952                         if (!(m = dbus_message_new_method_call(
2953                                               "org.freedesktop.systemd1",
2954                                               "/org/freedesktop/systemd1",
2955                                               "org.freedesktop.systemd1.Manager",
2956                                               "LoadUnit"))) {
2957                                 log_error("Could not allocate message.");
2958                                 ret = -ENOMEM;
2959                                 goto finish;
2960                         }
2961
2962                         if (!dbus_message_append_args(m,
2963                                                       DBUS_TYPE_STRING, name,
2964                                                       DBUS_TYPE_INVALID)) {
2965                                 log_error("Could not append arguments to message.");
2966                                 ret = -ENOMEM;
2967                                 goto finish;
2968                         }
2969
2970                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2971
2972                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2973                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2974                                         ret = -EIO;
2975                                         goto finish;
2976                                 }
2977
2978                                 dbus_error_free(&error);
2979
2980                                 dbus_message_unref(m);
2981                                 if (!(m = dbus_message_new_method_call(
2982                                                       "org.freedesktop.systemd1",
2983                                                       "/org/freedesktop/systemd1",
2984                                                       "org.freedesktop.systemd1.Manager",
2985                                                       "GetUnit"))) {
2986                                         log_error("Could not allocate message.");
2987                                         ret = -ENOMEM;
2988                                         goto finish;
2989                                 }
2990
2991                                 if (!dbus_message_append_args(m,
2992                                                               DBUS_TYPE_STRING, name,
2993                                                               DBUS_TYPE_INVALID)) {
2994                                         log_error("Could not append arguments to message.");
2995                                         ret = -ENOMEM;
2996                                         goto finish;
2997                                 }
2998
2999                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3000                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3001
3002                                         if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
3003                                                 ret = 4; /* According to LSB: "program or service status is unknown" */
3004                                         else
3005                                                 ret = -EIO;
3006                                         goto finish;
3007                                 }
3008                         }
3009
3010                 } else if (show_properties) {
3011
3012                         /* Interpret as job id */
3013
3014                         if (!(m = dbus_message_new_method_call(
3015                                               "org.freedesktop.systemd1",
3016                                               "/org/freedesktop/systemd1",
3017                                               "org.freedesktop.systemd1.Manager",
3018                                               "GetJob"))) {
3019                                 log_error("Could not allocate message.");
3020                                 ret = -ENOMEM;
3021                                 goto finish;
3022                         }
3023
3024                         if (!dbus_message_append_args(m,
3025                                                       DBUS_TYPE_UINT32, &id,
3026                                                       DBUS_TYPE_INVALID)) {
3027                                 log_error("Could not append arguments to message.");
3028                                 ret = -ENOMEM;
3029                                 goto finish;
3030                         }
3031
3032                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3033                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3034                                 ret = -EIO;
3035                                 goto finish;
3036                         }
3037                 } else {
3038
3039                         /* Interpret as PID */
3040
3041                         if (!(m = dbus_message_new_method_call(
3042                                               "org.freedesktop.systemd1",
3043                                               "/org/freedesktop/systemd1",
3044                                               "org.freedesktop.systemd1.Manager",
3045                                               "GetUnitByPID"))) {
3046                                 log_error("Could not allocate message.");
3047                                 ret = -ENOMEM;
3048                                 goto finish;
3049                         }
3050
3051                         if (!dbus_message_append_args(m,
3052                                                       DBUS_TYPE_UINT32, &id,
3053                                                       DBUS_TYPE_INVALID)) {
3054                                 log_error("Could not append arguments to message.");
3055                                 ret = -ENOMEM;
3056                                 goto finish;
3057                         }
3058
3059                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3060                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3061                                 ret = -EIO;
3062                                 goto finish;
3063                         }
3064                 }
3065
3066                 if (!dbus_message_get_args(reply, &error,
3067                                            DBUS_TYPE_OBJECT_PATH, &path,
3068                                            DBUS_TYPE_INVALID)) {
3069                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3070                         ret = -EIO;
3071                         goto finish;
3072                 }
3073
3074                 if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
3075                         ret = r;
3076
3077                 dbus_message_unref(m);
3078                 dbus_message_unref(reply);
3079                 m = reply = NULL;
3080         }
3081
3082 finish:
3083         if (m)
3084                 dbus_message_unref(m);
3085
3086         if (reply)
3087                 dbus_message_unref(reply);
3088
3089         dbus_error_free(&error);
3090
3091         return ret;
3092 }
3093
3094 static int dump(DBusConnection *bus, char **args) {
3095         DBusMessage *m = NULL, *reply = NULL;
3096         DBusError error;
3097         int r;
3098         const char *text;
3099
3100         dbus_error_init(&error);
3101
3102         pager_open_if_enabled();
3103
3104         if (!(m = dbus_message_new_method_call(
3105                               "org.freedesktop.systemd1",
3106                               "/org/freedesktop/systemd1",
3107                               "org.freedesktop.systemd1.Manager",
3108                               "Dump"))) {
3109                 log_error("Could not allocate message.");
3110                 return -ENOMEM;
3111         }
3112
3113         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3114                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3115                 r = -EIO;
3116                 goto finish;
3117         }
3118
3119         if (!dbus_message_get_args(reply, &error,
3120                                    DBUS_TYPE_STRING, &text,
3121                                    DBUS_TYPE_INVALID)) {
3122                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3123                 r = -EIO;
3124                 goto finish;
3125         }
3126
3127         fputs(text, stdout);
3128
3129         r = 0;
3130
3131 finish:
3132         if (m)
3133                 dbus_message_unref(m);
3134
3135         if (reply)
3136                 dbus_message_unref(reply);
3137
3138         dbus_error_free(&error);
3139
3140         return r;
3141 }
3142
3143 static int snapshot(DBusConnection *bus, char **args) {
3144         DBusMessage *m = NULL, *reply = NULL;
3145         DBusError error;
3146         int r;
3147         const char *name = "", *path, *id;
3148         dbus_bool_t cleanup = FALSE;
3149         DBusMessageIter iter, sub;
3150         const char
3151                 *interface = "org.freedesktop.systemd1.Unit",
3152                 *property = "Id";
3153
3154         dbus_error_init(&error);
3155
3156         if (!(m = dbus_message_new_method_call(
3157                               "org.freedesktop.systemd1",
3158                               "/org/freedesktop/systemd1",
3159                               "org.freedesktop.systemd1.Manager",
3160                               "CreateSnapshot"))) {
3161                 log_error("Could not allocate message.");
3162                 return -ENOMEM;
3163         }
3164
3165         if (strv_length(args) > 1)
3166                 name = args[1];
3167
3168         if (!dbus_message_append_args(m,
3169                                       DBUS_TYPE_STRING, &name,
3170                                       DBUS_TYPE_BOOLEAN, &cleanup,
3171                                       DBUS_TYPE_INVALID)) {
3172                 log_error("Could not append arguments to message.");
3173                 r = -ENOMEM;
3174                 goto finish;
3175         }
3176
3177         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3178                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3179                 r = -EIO;
3180                 goto finish;
3181         }
3182
3183         if (!dbus_message_get_args(reply, &error,
3184                                    DBUS_TYPE_OBJECT_PATH, &path,
3185                                    DBUS_TYPE_INVALID)) {
3186                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3187                 r = -EIO;
3188                 goto finish;
3189         }
3190
3191         dbus_message_unref(m);
3192         if (!(m = dbus_message_new_method_call(
3193                               "org.freedesktop.systemd1",
3194                               path,
3195                               "org.freedesktop.DBus.Properties",
3196                               "Get"))) {
3197                 log_error("Could not allocate message.");
3198                 return -ENOMEM;
3199         }
3200
3201         if (!dbus_message_append_args(m,
3202                                       DBUS_TYPE_STRING, &interface,
3203                                       DBUS_TYPE_STRING, &property,
3204                                       DBUS_TYPE_INVALID)) {
3205                 log_error("Could not append arguments to message.");
3206                 r = -ENOMEM;
3207                 goto finish;
3208         }
3209
3210         dbus_message_unref(reply);
3211         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3212                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3213                 r = -EIO;
3214                 goto finish;
3215         }
3216
3217         if (!dbus_message_iter_init(reply, &iter) ||
3218             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3219                 log_error("Failed to parse reply.");
3220                 r = -EIO;
3221                 goto finish;
3222         }
3223
3224         dbus_message_iter_recurse(&iter, &sub);
3225
3226         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3227                 log_error("Failed to parse reply.");
3228                 r = -EIO;
3229                 goto finish;
3230         }
3231
3232         dbus_message_iter_get_basic(&sub, &id);
3233
3234         if (!arg_quiet)
3235                 puts(id);
3236         r = 0;
3237
3238 finish:
3239         if (m)
3240                 dbus_message_unref(m);
3241
3242         if (reply)
3243                 dbus_message_unref(reply);
3244
3245         dbus_error_free(&error);
3246
3247         return r;
3248 }
3249
3250 static int delete_snapshot(DBusConnection *bus, char **args) {
3251         DBusMessage *m = NULL, *reply = NULL;
3252         int r;
3253         DBusError error;
3254         char **name;
3255
3256         assert(bus);
3257         assert(args);
3258
3259         dbus_error_init(&error);
3260
3261         STRV_FOREACH(name, args+1) {
3262                 const char *path = NULL;
3263
3264                 if (!(m = dbus_message_new_method_call(
3265                                       "org.freedesktop.systemd1",
3266                                       "/org/freedesktop/systemd1",
3267                                       "org.freedesktop.systemd1.Manager",
3268                                       "GetUnit"))) {
3269                         log_error("Could not allocate message.");
3270                         r = -ENOMEM;
3271                         goto finish;
3272                 }
3273
3274                 if (!dbus_message_append_args(m,
3275                                               DBUS_TYPE_STRING, name,
3276                                               DBUS_TYPE_INVALID)) {
3277                         log_error("Could not append arguments to message.");
3278                         r = -ENOMEM;
3279                         goto finish;
3280                 }
3281
3282                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3283                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3284                         r = -EIO;
3285                         goto finish;
3286                 }
3287
3288                 if (!dbus_message_get_args(reply, &error,
3289                                            DBUS_TYPE_OBJECT_PATH, &path,
3290                                            DBUS_TYPE_INVALID)) {
3291                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3292                         r = -EIO;
3293                         goto finish;
3294                 }
3295
3296                 dbus_message_unref(m);
3297                 if (!(m = dbus_message_new_method_call(
3298                                       "org.freedesktop.systemd1",
3299                                       path,
3300                                       "org.freedesktop.systemd1.Snapshot",
3301                                       "Remove"))) {
3302                         log_error("Could not allocate message.");
3303                         r = -ENOMEM;
3304                         goto finish;
3305                 }
3306
3307                 dbus_message_unref(reply);
3308                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3309                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3310                         r = -EIO;
3311                         goto finish;
3312                 }
3313
3314                 dbus_message_unref(m);
3315                 dbus_message_unref(reply);
3316                 m = reply = NULL;
3317         }
3318
3319         r = 0;
3320
3321 finish:
3322         if (m)
3323                 dbus_message_unref(m);
3324
3325         if (reply)
3326                 dbus_message_unref(reply);
3327
3328         dbus_error_free(&error);
3329
3330         return r;
3331 }
3332
3333 static int daemon_reload(DBusConnection *bus, char **args) {
3334         DBusMessage *m = NULL, *reply = NULL;
3335         DBusError error;
3336         int r;
3337         const char *method;
3338
3339         dbus_error_init(&error);
3340
3341         if (arg_action == ACTION_RELOAD)
3342                 method = "Reload";
3343         else if (arg_action == ACTION_REEXEC)
3344                 method = "Reexecute";
3345         else {
3346                 assert(arg_action == ACTION_SYSTEMCTL);
3347
3348                 method =
3349                         streq(args[0], "clear-jobs")    ||
3350                         streq(args[0], "cancel")        ? "ClearJobs" :
3351                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3352                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3353                         streq(args[0], "halt")          ? "Halt" :
3354                         streq(args[0], "poweroff")      ? "PowerOff" :
3355                         streq(args[0], "reboot")        ? "Reboot" :
3356                         streq(args[0], "kexec")         ? "KExec" :
3357                         streq(args[0], "exit")          ? "Exit" :
3358                                     /* "daemon-reload" */ "Reload";
3359         }
3360
3361         if (!(m = dbus_message_new_method_call(
3362                               "org.freedesktop.systemd1",
3363                               "/org/freedesktop/systemd1",
3364                               "org.freedesktop.systemd1.Manager",
3365                               method))) {
3366                 log_error("Could not allocate message.");
3367                 return -ENOMEM;
3368         }
3369
3370         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3371
3372                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3373                         /* There's always a fallback possible for
3374                          * legacy actions. */
3375                         r = -EADDRNOTAVAIL;
3376                         goto finish;
3377                 }
3378
3379                 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3380                         /* On reexecution, we expect a disconnect, not
3381                          * a reply */
3382                         r = 0;
3383                         goto finish;
3384                 }
3385
3386                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3387                 r = -EIO;
3388                 goto finish;
3389         }
3390
3391         r = 0;
3392
3393 finish:
3394         if (m)
3395                 dbus_message_unref(m);
3396
3397         if (reply)
3398                 dbus_message_unref(reply);
3399
3400         dbus_error_free(&error);
3401
3402         return r;
3403 }
3404
3405 static int reset_failed(DBusConnection *bus, char **args) {
3406         DBusMessage *m = NULL;
3407         int r;
3408         DBusError error;
3409         char **name;
3410
3411         assert(bus);
3412         dbus_error_init(&error);
3413
3414         if (strv_length(args) <= 1)
3415                 return daemon_reload(bus, args);
3416
3417         STRV_FOREACH(name, args+1) {
3418                 DBusMessage *reply;
3419
3420                 if (!(m = dbus_message_new_method_call(
3421                                       "org.freedesktop.systemd1",
3422                                       "/org/freedesktop/systemd1",
3423                                       "org.freedesktop.systemd1.Manager",
3424                                       "ResetFailedUnit"))) {
3425                         log_error("Could not allocate message.");
3426                         r = -ENOMEM;
3427                         goto finish;
3428                 }
3429
3430                 if (!dbus_message_append_args(m,
3431                                               DBUS_TYPE_STRING, name,
3432                                               DBUS_TYPE_INVALID)) {
3433                         log_error("Could not append arguments to message.");
3434                         r = -ENOMEM;
3435                         goto finish;
3436                 }
3437
3438                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3439                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3440                         r = -EIO;
3441                         goto finish;
3442                 }
3443
3444                 dbus_message_unref(m);
3445                 dbus_message_unref(reply);
3446                 m = reply = NULL;
3447         }
3448
3449         r = 0;
3450
3451 finish:
3452         if (m)
3453                 dbus_message_unref(m);
3454
3455         dbus_error_free(&error);
3456
3457         return r;
3458 }
3459
3460 static int show_enviroment(DBusConnection *bus, char **args) {
3461         DBusMessage *m = NULL, *reply = NULL;
3462         DBusError error;
3463         DBusMessageIter iter, sub, sub2;
3464         int r;
3465         const char
3466                 *interface = "org.freedesktop.systemd1.Manager",
3467                 *property = "Environment";
3468
3469         dbus_error_init(&error);
3470
3471         pager_open_if_enabled();
3472
3473         if (!(m = dbus_message_new_method_call(
3474                               "org.freedesktop.systemd1",
3475                               "/org/freedesktop/systemd1",
3476                               "org.freedesktop.DBus.Properties",
3477                               "Get"))) {
3478                 log_error("Could not allocate message.");
3479                 return -ENOMEM;
3480         }
3481
3482         if (!dbus_message_append_args(m,
3483                                       DBUS_TYPE_STRING, &interface,
3484                                       DBUS_TYPE_STRING, &property,
3485                                       DBUS_TYPE_INVALID)) {
3486                 log_error("Could not append arguments to message.");
3487                 r = -ENOMEM;
3488                 goto finish;
3489         }
3490
3491         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3492                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3493                 r = -EIO;
3494                 goto finish;
3495         }
3496
3497         if (!dbus_message_iter_init(reply, &iter) ||
3498             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3499                 log_error("Failed to parse reply.");
3500                 r = -EIO;
3501                 goto finish;
3502         }
3503
3504         dbus_message_iter_recurse(&iter, &sub);
3505
3506         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3507             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3508                 log_error("Failed to parse reply.");
3509                 r = -EIO;
3510                 goto finish;
3511         }
3512
3513         dbus_message_iter_recurse(&sub, &sub2);
3514
3515         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3516                 const char *text;
3517
3518                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3519                         log_error("Failed to parse reply.");
3520                         r = -EIO;
3521                         goto finish;
3522                 }
3523
3524                 dbus_message_iter_get_basic(&sub2, &text);
3525                 printf("%s\n", text);
3526
3527                 dbus_message_iter_next(&sub2);
3528         }
3529
3530         r = 0;
3531
3532 finish:
3533         if (m)
3534                 dbus_message_unref(m);
3535
3536         if (reply)
3537                 dbus_message_unref(reply);
3538
3539         dbus_error_free(&error);
3540
3541         return r;
3542 }
3543
3544 static int set_environment(DBusConnection *bus, char **args) {
3545         DBusMessage *m = NULL, *reply = NULL;
3546         DBusError error;
3547         int r;
3548         const char *method;
3549         DBusMessageIter iter, sub;
3550         char **name;
3551
3552         dbus_error_init(&error);
3553
3554         method = streq(args[0], "set-environment")
3555                 ? "SetEnvironment"
3556                 : "UnsetEnvironment";
3557
3558         if (!(m = dbus_message_new_method_call(
3559                               "org.freedesktop.systemd1",
3560                               "/org/freedesktop/systemd1",
3561                               "org.freedesktop.systemd1.Manager",
3562                               method))) {
3563
3564                 log_error("Could not allocate message.");
3565                 return -ENOMEM;
3566         }
3567
3568         dbus_message_iter_init_append(m, &iter);
3569
3570         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3571                 log_error("Could not append arguments to message.");
3572                 r = -ENOMEM;
3573                 goto finish;
3574         }
3575
3576         STRV_FOREACH(name, args+1)
3577                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3578                         log_error("Could not append arguments to message.");
3579                         r = -ENOMEM;
3580                         goto finish;
3581                 }
3582
3583         if (!dbus_message_iter_close_container(&iter, &sub)) {
3584                 log_error("Could not append arguments to message.");
3585                 r = -ENOMEM;
3586                 goto finish;
3587         }
3588
3589         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3590                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3591                 r = -EIO;
3592                 goto finish;
3593         }
3594
3595         r = 0;
3596
3597 finish:
3598         if (m)
3599                 dbus_message_unref(m);
3600
3601         if (reply)
3602                 dbus_message_unref(reply);
3603
3604         dbus_error_free(&error);
3605
3606         return r;
3607 }
3608
3609 static int enable_sysv_units(char **args) {
3610         int r = 0;
3611
3612 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3613         const char *verb = args[0];
3614         unsigned f = 1, t = 1;
3615         LookupPaths paths;
3616
3617         if (arg_scope != UNIT_FILE_SYSTEM)
3618                 return 0;
3619
3620         if (!streq(verb, "enable") &&
3621             !streq(verb, "disable") &&
3622             !streq(verb, "is-enabled"))
3623                 return 0;
3624
3625         /* Processes all SysV units, and reshuffles the array so that
3626          * afterwards only the native units remain */
3627
3628         zero(paths);
3629         r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
3630         if (r < 0)
3631                 return r;
3632
3633         r = 0;
3634
3635         for (f = 1; args[f]; f++) {
3636                 const char *name;
3637                 char *p;
3638                 bool found_native = false, found_sysv;
3639                 unsigned c = 1;
3640                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3641                 char **k, *l, *q = NULL;
3642                 int j;
3643                 pid_t pid;
3644                 siginfo_t status;
3645
3646                 name = args[f];
3647
3648                 if (!endswith(name, ".service"))
3649                         continue;
3650
3651                 if (path_is_absolute(name))
3652                         continue;
3653
3654                 STRV_FOREACH(k, paths.unit_path) {
3655                         p = NULL;
3656
3657                         if (!isempty(arg_root))
3658                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3659                         else
3660                                 asprintf(&p, "%s/%s", *k, name);
3661
3662                         if (!p) {
3663                                 log_error("No memory");
3664                                 r = -ENOMEM;
3665                                 goto finish;
3666                         }
3667
3668                         found_native = access(p, F_OK) >= 0;
3669                         free(p);
3670
3671                         if (found_native)
3672                                 break;
3673                 }
3674
3675                 if (found_native)
3676                         continue;
3677
3678                 p = NULL;
3679                 if (!isempty(arg_root))
3680                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3681                 else
3682                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3683                 if (!p) {
3684                         log_error("No memory");
3685                         r = -ENOMEM;
3686                         goto finish;
3687                 }
3688
3689                 p[strlen(p) - sizeof(".service") + 1] = 0;
3690                 found_sysv = access(p, F_OK) >= 0;
3691
3692                 if (!found_sysv) {
3693                         free(p);
3694                         continue;
3695                 }
3696
3697                 /* Mark this entry, so that we don't try enabling it as native unit */
3698                 args[f] = (char*) "";
3699
3700                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3701
3702                 if (!isempty(arg_root))
3703                         argv[c++] = q = strappend("--root=", arg_root);
3704
3705                 argv[c++] = file_name_from_path(p);
3706                 argv[c++] =
3707                         streq(verb, "enable") ? "on" :
3708                         streq(verb, "disable") ? "off" : "--level=5";
3709                 argv[c] = NULL;
3710
3711                 l = strv_join((char**)argv, " ");
3712                 if (!l) {
3713                         log_error("No memory.");
3714                         free(q);
3715                         free(p);
3716                         r = -ENOMEM;
3717                         goto finish;
3718                 }
3719
3720                 log_info("Executing %s", l);
3721                 free(l);
3722
3723                 pid = fork();
3724                 if (pid < 0) {
3725                         log_error("Failed to fork: %m");
3726                         free(p);
3727                         free(q);
3728                         r = -errno;
3729                         goto finish;
3730                 } else if (pid == 0) {
3731                         /* Child */
3732
3733                         execv(argv[0], (char**) argv);
3734                         _exit(EXIT_FAILURE);
3735                 }
3736
3737                 free(p);
3738                 free(q);
3739
3740                 j = wait_for_terminate(pid, &status);
3741                 if (j < 0) {
3742                         log_error("Failed to wait for child: %s", strerror(-r));
3743                         r = j;
3744                         goto finish;
3745                 }
3746
3747                 if (status.si_code == CLD_EXITED) {
3748                         if (streq(verb, "is-enabled")) {
3749                                 if (status.si_status == 0) {
3750                                         if (!arg_quiet)
3751                                                 puts("enabled");
3752                                         r = 1;
3753                                 } else {
3754                                         if (!arg_quiet)
3755                                                 puts("disabled");
3756                                 }
3757
3758                         } else if (status.si_status != 0) {
3759                                 r = -EINVAL;
3760                                 goto finish;
3761                         }
3762                 } else {
3763                         r = -EPROTO;
3764                         goto finish;
3765                 }
3766         }
3767
3768 finish:
3769         lookup_paths_free(&paths);
3770
3771         /* Drop all SysV units */
3772         for (f = 1, t = 1; args[f]; f++) {
3773
3774                 if (isempty(args[f]))
3775                         continue;
3776
3777                 args[t++] = args[f];
3778         }
3779
3780         args[t] = NULL;
3781
3782 #endif
3783         return r;
3784 }
3785
3786 static int enable_unit(DBusConnection *bus, char **args) {
3787         const char *verb = args[0];
3788         UnitFileChange *changes = NULL;
3789         unsigned n_changes = 0, i;
3790         int carries_install_info = -1;
3791         DBusMessage *m = NULL, *reply = NULL;
3792         int r;
3793         DBusError error;
3794
3795         r = enable_sysv_units(args);
3796         if (r < 0)
3797                 return r;
3798
3799         if (!args[1])
3800                 return 0;
3801
3802         dbus_error_init(&error);
3803
3804         if (!bus || avoid_bus()) {
3805                 if (streq(verb, "enable")) {
3806                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3807                         carries_install_info = r;
3808                 } else if (streq(verb, "disable"))
3809                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3810                 else if (streq(verb, "reenable")) {
3811                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3812                         carries_install_info = r;
3813                 } else if (streq(verb, "link"))
3814                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3815                 else if (streq(verb, "preset")) {
3816                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3817                         carries_install_info = r;
3818                 } else if (streq(verb, "mask"))
3819                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3820                 else if (streq(verb, "unmask"))
3821                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3822                 else
3823                         assert_not_reached("Unknown verb");
3824
3825                 if (r < 0) {
3826                         log_error("Operation failed: %s", strerror(-r));
3827                         goto finish;
3828                 }
3829
3830                 if (!arg_quiet) {
3831                         for (i = 0; i < n_changes; i++) {
3832                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3833                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3834                                 else
3835                                         log_info("rm '%s'", changes[i].path);
3836                         }
3837                 }
3838
3839         } else {
3840                 const char *method;
3841                 bool send_force = true, expect_carries_install_info = false;
3842                 dbus_bool_t a, b;
3843                 DBusMessageIter iter, sub, sub2;
3844
3845                 if (streq(verb, "enable")) {
3846                         method = "EnableUnitFiles";
3847                         expect_carries_install_info = true;
3848                 } else if (streq(verb, "disable")) {
3849                         method = "DisableUnitFiles";
3850                         send_force = false;
3851                 } else if (streq(verb, "reenable")) {
3852                         method = "ReenableUnitFiles";
3853                         expect_carries_install_info = true;
3854                 } else if (streq(verb, "link"))
3855                         method = "LinkUnitFiles";
3856                 else if (streq(verb, "preset")) {
3857                         method = "PresetUnitFiles";
3858                         expect_carries_install_info = true;
3859                 } else if (streq(verb, "mask"))
3860                         method = "MaskUnitFiles";
3861                 else if (streq(verb, "unmask")) {
3862                         method = "UnmaskUnitFiles";
3863                         send_force = false;
3864                 } else
3865                         assert_not_reached("Unknown verb");
3866
3867                 m = dbus_message_new_method_call(
3868                                 "org.freedesktop.systemd1",
3869                                 "/org/freedesktop/systemd1",
3870                                 "org.freedesktop.systemd1.Manager",
3871                                 method);
3872                 if (!m) {
3873                         log_error("Out of memory");
3874                         r = -ENOMEM;
3875                         goto finish;
3876                 }
3877
3878                 dbus_message_iter_init_append(m, &iter);
3879
3880                 r = bus_append_strv_iter(&iter, args+1);
3881                 if (r < 0) {
3882                         log_error("Failed to append unit files.");
3883                         goto finish;
3884                 }
3885
3886                 a = arg_runtime;
3887                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3888                         log_error("Failed to append runtime boolean.");
3889                         r = -ENOMEM;
3890                         goto finish;
3891                 }
3892
3893                 if (send_force) {
3894                         b = arg_force;
3895
3896                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3897                                 log_error("Failed to append force boolean.");
3898                                 r = -ENOMEM;
3899                                 goto finish;
3900                         }
3901                 }
3902
3903                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3904                 if (!reply) {
3905                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3906                         r = -EIO;
3907                         goto finish;
3908                 }
3909
3910                 if (!dbus_message_iter_init(reply, &iter)) {
3911                         log_error("Failed to initialize iterator.");
3912                         goto finish;
3913                 }
3914
3915                 if (expect_carries_install_info) {
3916                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3917                         if (r < 0) {
3918                                 log_error("Failed to parse reply.");
3919                                 goto finish;
3920                         }
3921
3922                         carries_install_info = b;
3923                 }
3924
3925                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3926                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3927                         log_error("Failed to parse reply.");
3928                         r = -EIO;
3929                         goto finish;
3930                 }
3931
3932                 dbus_message_iter_recurse(&iter, &sub);
3933                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3934                         const char *type, *path, *source;
3935
3936                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3937                                 log_error("Failed to parse reply.");
3938                                 r = -EIO;
3939                                 goto finish;
3940                         }
3941
3942                         dbus_message_iter_recurse(&sub, &sub2);
3943
3944                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3945                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3946                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3947                                 log_error("Failed to parse reply.");
3948                                 r = -EIO;
3949                                 goto finish;
3950                         }
3951
3952                         if (!arg_quiet) {
3953                                 if (streq(type, "symlink"))
3954                                         log_info("ln -s '%s' '%s'", source, path);
3955                                 else
3956                                         log_info("rm '%s'", path);
3957                         }
3958
3959                         dbus_message_iter_next(&sub);
3960                 }
3961
3962                 /* Try to reload if enabeld */
3963                 if (!arg_no_reload)
3964                         r = daemon_reload(bus, args);
3965         }
3966
3967         if (carries_install_info == 0)
3968                 log_warning("Warning: unit files do not carry install information. No operation executed.");
3969
3970 finish:
3971         if (m)
3972                 dbus_message_unref(m);
3973
3974         if (reply)
3975                 dbus_message_unref(reply);
3976
3977         unit_file_changes_free(changes, n_changes);
3978
3979         dbus_error_free(&error);
3980         return r;
3981 }
3982
3983 static int unit_is_enabled(DBusConnection *bus, char **args) {
3984         DBusError error;
3985         int r;
3986         DBusMessage *m = NULL, *reply = NULL;
3987         bool enabled;
3988         char **name;
3989
3990         dbus_error_init(&error);
3991
3992         r = enable_sysv_units(args);
3993         if (r < 0)
3994                 return r;
3995
3996         enabled = r > 0;
3997
3998         if (!bus || avoid_bus()) {
3999
4000                 STRV_FOREACH(name, args+1) {
4001                         UnitFileState state;
4002
4003                         state = unit_file_get_state(arg_scope, arg_root, *name);
4004                         if (state < 0) {
4005                                 r = state;
4006                                 goto finish;
4007                         }
4008
4009                         if (state == UNIT_FILE_ENABLED ||
4010                             state == UNIT_FILE_ENABLED_RUNTIME ||
4011                             state == UNIT_FILE_STATIC)
4012                                 enabled = true;
4013
4014                         if (!arg_quiet)
4015                                 puts(unit_file_state_to_string(state));
4016                 }
4017
4018         } else {
4019                 STRV_FOREACH(name, args+1) {
4020                         const char *s;
4021
4022                         m = dbus_message_new_method_call(
4023                                         "org.freedesktop.systemd1",
4024                                         "/org/freedesktop/systemd1",
4025                                         "org.freedesktop.systemd1.Manager",
4026                                         "GetUnitFileState");
4027                         if (!m) {
4028                                 log_error("Out of memory");
4029                                 r = -ENOMEM;
4030                                 goto finish;
4031                         }
4032
4033                         if (!dbus_message_append_args(m,
4034                                                       DBUS_TYPE_STRING, name,
4035                                                       DBUS_TYPE_INVALID)) {
4036                                 log_error("Could not append arguments to message.");
4037                                 r = -ENOMEM;
4038                                 goto finish;
4039                         }
4040
4041                         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4042                         if (!reply) {
4043                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4044                                 r = -EIO;
4045                                 goto finish;
4046                         }
4047
4048                         if (!dbus_message_get_args(reply, &error,
4049                                                    DBUS_TYPE_STRING, &s,
4050                                                    DBUS_TYPE_INVALID)) {
4051                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
4052                                 r = -EIO;
4053                                 goto finish;
4054                         }
4055
4056                         dbus_message_unref(m);
4057                         dbus_message_unref(reply);
4058                         m = reply = NULL;
4059
4060                         if (streq(s, "enabled") ||
4061                             streq(s, "enabled-runtime") ||
4062                             streq(s, "static"))
4063                                 enabled = true;
4064
4065                         if (!arg_quiet)
4066                                 puts(s);
4067                 }
4068         }
4069
4070         r = enabled ? 0 : 1;
4071
4072 finish:
4073         if (m)
4074                 dbus_message_unref(m);
4075
4076         if (reply)
4077                 dbus_message_unref(reply);
4078
4079         dbus_error_free(&error);
4080         return r;
4081 }
4082
4083 static int systemctl_help(void) {
4084
4085         pager_open_if_enabled();
4086
4087         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
4088                "Query or send control commands to the systemd manager.\n\n"
4089                "  -h --help           Show this help\n"
4090                "     --version        Show package version\n"
4091                "  -t --type=TYPE      List only units of a particular type\n"
4092                "  -p --property=NAME  Show only properties by this name\n"
4093                "  -a --all            Show all units/properties, including dead/empty ones\n"
4094                "     --failed         Show only failed units\n"
4095                "     --full           Don't ellipsize unit names on output\n"
4096                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
4097                "                      pending\n"
4098                "     --ignore-dependencies\n"
4099                "                      When queueing a new job, ignore all its dependencies\n"
4100                "     --kill-who=WHO   Who to send signal to\n"
4101                "  -s --signal=SIGNAL  Which signal to send\n"
4102                "  -H --host=[USER@]HOST\n"
4103                "                      Show information for remote host\n"
4104                "  -P --privileged     Acquire privileges before execution\n"
4105                "  -q --quiet          Suppress output\n"
4106                "     --no-block       Do not wait until operation finished\n"
4107                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
4108                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
4109                "                      configuration\n"
4110                "     --no-legend      Do not print a legend (column headers and hints)\n"
4111                "     --no-pager       Do not pipe output into a pager\n"
4112                "     --no-ask-password\n"
4113                "                      Do not ask for system passwords\n"
4114                "     --order          When generating graph for dot, show only order\n"
4115                "     --require        When generating graph for dot, show only requirement\n"
4116                "     --system         Connect to system manager\n"
4117                "     --user           Connect to user service manager\n"
4118                "     --global         Enable/disable unit files globally\n"
4119                "  -f --force          When enabling unit files, override existing symlinks\n"
4120                "                      When shutting down, execute action immediately\n"
4121                "     --root=PATH      Enable unit files in the specified root directory\n"
4122                "     --runtime        Enable unit files only temporarily until next reboot\n"
4123                "  -n --lines=INTEGER  Journal entries to show\n"
4124                "     --follow         Follow journal\n"
4125                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
4126                "                      verbose, export, json, cat)\n\n"
4127                "Unit Commands:\n"
4128                "  list-units                      List loaded units\n"
4129                "  start [NAME...]                 Start (activate) one or more units\n"
4130                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4131                "  reload [NAME...]                Reload one or more units\n"
4132                "  restart [NAME...]               Start or restart one or more units\n"
4133                "  try-restart [NAME...]           Restart one or more units if active\n"
4134                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
4135                "                                  otherwise start or restart\n"
4136                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4137                "                                  otherwise restart if active\n"
4138                "  isolate [NAME]                  Start one unit and stop all others\n"
4139                "  kill [NAME...]                  Send signal to processes of a unit\n"
4140                "  is-active [NAME...]             Check whether units are active\n"
4141                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4142                "  show [NAME...|JOB...]           Show properties of one or more\n"
4143                "                                  units/jobs or the manager\n"
4144                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4145                "                                  units\n"
4146                "  load [NAME...]                  Load one or more units\n\n"
4147                "Unit File Commands:\n"
4148                "  list-unit-files                 List installed unit files\n"
4149                "  enable [NAME...]                Enable one or more unit files\n"
4150                "  disable [NAME...]               Disable one or more unit files\n"
4151                "  reenable [NAME...]              Reenable one or more unit files\n"
4152                "  preset [NAME...]                Enable/disable one or more unit files\n"
4153                "                                  based on preset configuration\n"
4154                "  mask [NAME...]                  Mask one or more units\n"
4155                "  unmask [NAME...]                Unmask one or more units\n"
4156                "  link [PATH...]                  Link one or more units files into\n"
4157                "                                  the search path\n"
4158                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4159                "Job Commands:\n"
4160                "  list-jobs                       List jobs\n"
4161                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4162                "Status Commands:\n"
4163                "  dump                            Dump server status\n"
4164                "  dot                             Dump dependency graph for dot(1)\n\n"
4165                "Snapshot Commands:\n"
4166                "  snapshot [NAME]                 Create a snapshot\n"
4167                "  delete [NAME...]                Remove one or more snapshots\n\n"
4168                "Environment Commands:\n"
4169                "  show-environment                Dump environment\n"
4170                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4171                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4172                "Manager Lifecycle Commands:\n"
4173                "  daemon-reload                   Reload systemd manager configuration\n"
4174                "  daemon-reexec                   Reexecute systemd manager\n\n"
4175                "System Commands:\n"
4176                "  default                         Enter system default mode\n"
4177                "  rescue                          Enter system rescue mode\n"
4178                "  emergency                       Enter system emergency mode\n"
4179                "  halt                            Shut down and halt the system\n"
4180                "  poweroff                        Shut down and power-off the system\n"
4181                "  reboot                          Shut down and reboot the system\n"
4182                "  kexec                           Shut down and reboot the system with kexec\n"
4183                "  exit                            Ask for user instance termination\n",
4184                program_invocation_short_name);
4185
4186         return 0;
4187 }
4188
4189 static int halt_help(void) {
4190
4191         printf("%s [OPTIONS...]\n\n"
4192                "%s the system.\n\n"
4193                "     --help      Show this help\n"
4194                "     --halt      Halt the machine\n"
4195                "  -p --poweroff  Switch off the machine\n"
4196                "     --reboot    Reboot the machine\n"
4197                "  -f --force     Force immediate halt/power-off/reboot\n"
4198                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4199                "  -d --no-wtmp   Don't write wtmp record\n"
4200                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
4201                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4202                program_invocation_short_name,
4203                arg_action == ACTION_REBOOT   ? "Reboot" :
4204                arg_action == ACTION_POWEROFF ? "Power off" :
4205                                                "Halt");
4206
4207         return 0;
4208 }
4209
4210 static int shutdown_help(void) {
4211
4212         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4213                "Shut down the system.\n\n"
4214                "     --help      Show this help\n"
4215                "  -H --halt      Halt the machine\n"
4216                "  -P --poweroff  Power-off the machine\n"
4217                "  -r --reboot    Reboot the machine\n"
4218                "  -h             Equivalent to --poweroff, overriden by --halt\n"
4219                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4220                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4221                "  -c             Cancel a pending shutdown\n",
4222                program_invocation_short_name);
4223
4224         return 0;
4225 }
4226
4227 static int telinit_help(void) {
4228
4229         printf("%s [OPTIONS...] {COMMAND}\n\n"
4230                "Send control commands to the init daemon.\n\n"
4231                "     --help      Show this help\n"
4232                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4233                "Commands:\n"
4234                "  0              Power-off the machine\n"
4235                "  6              Reboot the machine\n"
4236                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4237                "  1, s, S        Enter rescue mode\n"
4238                "  q, Q           Reload init daemon configuration\n"
4239                "  u, U           Reexecute init daemon\n",
4240                program_invocation_short_name);
4241
4242         return 0;
4243 }
4244
4245 static int runlevel_help(void) {
4246
4247         printf("%s [OPTIONS...]\n\n"
4248                "Prints the previous and current runlevel of the init system.\n\n"
4249                "     --help      Show this help\n",
4250                program_invocation_short_name);
4251
4252         return 0;
4253 }
4254
4255 static int systemctl_parse_argv(int argc, char *argv[]) {
4256
4257         enum {
4258                 ARG_FAIL = 0x100,
4259                 ARG_IGNORE_DEPENDENCIES,
4260                 ARG_VERSION,
4261                 ARG_USER,
4262                 ARG_SYSTEM,
4263                 ARG_GLOBAL,
4264                 ARG_NO_BLOCK,
4265                 ARG_NO_LEGEND,
4266                 ARG_NO_PAGER,
4267                 ARG_NO_WALL,
4268                 ARG_ORDER,
4269                 ARG_REQUIRE,
4270                 ARG_ROOT,
4271                 ARG_FULL,
4272                 ARG_NO_RELOAD,
4273                 ARG_KILL_MODE,
4274                 ARG_KILL_WHO,
4275                 ARG_NO_ASK_PASSWORD,
4276                 ARG_FAILED,
4277                 ARG_RUNTIME,
4278                 ARG_FOLLOW,
4279                 ARG_FORCE
4280         };
4281
4282         static const struct option options[] = {
4283                 { "help",      no_argument,       NULL, 'h'           },
4284                 { "version",   no_argument,       NULL, ARG_VERSION   },
4285                 { "type",      required_argument, NULL, 't'           },
4286                 { "property",  required_argument, NULL, 'p'           },
4287                 { "all",       no_argument,       NULL, 'a'           },
4288                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4289                 { "full",      no_argument,       NULL, ARG_FULL      },
4290                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4291                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4292                 { "user",      no_argument,       NULL, ARG_USER      },
4293                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4294                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4295                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4296                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4297                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4298                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4299                 { "quiet",     no_argument,       NULL, 'q'           },
4300                 { "order",     no_argument,       NULL, ARG_ORDER     },
4301                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4302                 { "root",      required_argument, NULL, ARG_ROOT      },
4303                 { "force",     no_argument,       NULL, ARG_FORCE     },
4304                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4305                 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
4306                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4307                 { "signal",    required_argument, NULL, 's'           },
4308                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4309                 { "host",      required_argument, NULL, 'H'           },
4310                 { "privileged",no_argument,       NULL, 'P'           },
4311                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4312                 { "lines",     required_argument, NULL, 'n'           },
4313                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4314                 { "output",    required_argument, NULL, 'o'           },
4315                 { NULL,        0,                 NULL, 0             }
4316         };
4317
4318         int c;
4319
4320         assert(argc >= 0);
4321         assert(argv);
4322
4323         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4324
4325                 switch (c) {
4326
4327                 case 'h':
4328                         systemctl_help();
4329                         return 0;
4330
4331                 case ARG_VERSION:
4332                         puts(PACKAGE_STRING);
4333                         puts(DISTRIBUTION);
4334                         puts(SYSTEMD_FEATURES);
4335                         return 0;
4336
4337                 case 't':
4338                         arg_type = optarg;
4339                         break;
4340
4341                 case 'p': {
4342                         char **l;
4343
4344                         if (!(l = strv_append(arg_property, optarg)))
4345                                 return -ENOMEM;
4346
4347                         strv_free(arg_property);
4348                         arg_property = l;
4349
4350                         /* If the user asked for a particular
4351                          * property, show it to him, even if it is
4352                          * empty. */
4353                         arg_all = true;
4354                         break;
4355                 }
4356
4357                 case 'a':
4358                         arg_all = true;
4359                         break;
4360
4361                 case ARG_FAIL:
4362                         arg_job_mode = "fail";
4363                         break;
4364
4365                 case ARG_IGNORE_DEPENDENCIES:
4366                         arg_job_mode = "ignore-dependencies";
4367                         break;
4368
4369                 case ARG_USER:
4370                         arg_scope = UNIT_FILE_USER;
4371                         break;
4372
4373                 case ARG_SYSTEM:
4374                         arg_scope = UNIT_FILE_SYSTEM;
4375                         break;
4376
4377                 case ARG_GLOBAL:
4378                         arg_scope = UNIT_FILE_GLOBAL;
4379                         break;
4380
4381                 case ARG_NO_BLOCK:
4382                         arg_no_block = true;
4383                         break;
4384
4385                 case ARG_NO_LEGEND:
4386                         arg_no_legend = true;
4387                         break;
4388
4389                 case ARG_NO_PAGER:
4390                         arg_no_pager = true;
4391                         break;
4392
4393                 case ARG_NO_WALL:
4394                         arg_no_wall = true;
4395                         break;
4396
4397                 case ARG_ORDER:
4398                         arg_dot = DOT_ORDER;
4399                         break;
4400
4401                 case ARG_REQUIRE:
4402                         arg_dot = DOT_REQUIRE;
4403                         break;
4404
4405                 case ARG_ROOT:
4406                         arg_root = optarg;
4407                         break;
4408
4409                 case ARG_FULL:
4410                         arg_full = true;
4411                         break;
4412
4413                 case ARG_FAILED:
4414                         arg_failed = true;
4415                         break;
4416
4417                 case 'q':
4418                         arg_quiet = true;
4419                         break;
4420
4421                 case ARG_FORCE:
4422                         arg_force ++;
4423                         break;
4424
4425                 case ARG_FOLLOW:
4426                         arg_follow = true;
4427                         break;
4428
4429                 case 'f':
4430                         /* -f is short for both --follow and --force! */
4431                         arg_force ++;
4432                         arg_follow = true;
4433                         break;
4434
4435                 case ARG_NO_RELOAD:
4436                         arg_no_reload = true;
4437                         break;
4438
4439                 case ARG_KILL_WHO:
4440                         arg_kill_who = optarg;
4441                         break;
4442
4443                 case ARG_KILL_MODE:
4444                         arg_kill_mode = optarg;
4445                         break;
4446
4447                 case 's':
4448                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4449                                 log_error("Failed to parse signal string %s.", optarg);
4450                                 return -EINVAL;
4451                         }
4452                         break;
4453
4454                 case ARG_NO_ASK_PASSWORD:
4455                         arg_ask_password = false;
4456                         break;
4457
4458                 case 'P':
4459                         arg_transport = TRANSPORT_POLKIT;
4460                         break;
4461
4462                 case 'H':
4463                         arg_transport = TRANSPORT_SSH;
4464                         arg_host = optarg;
4465                         break;
4466
4467                 case ARG_RUNTIME:
4468                         arg_runtime = true;
4469                         break;
4470
4471                 case 'n':
4472                         if (safe_atou(optarg, &arg_lines) < 0) {
4473                                 log_error("Failed to parse lines '%s'", optarg);
4474                                 return -EINVAL;
4475                         }
4476                         break;
4477
4478                 case 'o':
4479                         arg_output = output_mode_from_string(optarg);
4480                         if (arg_output < 0) {
4481                                 log_error("Unknown output '%s'.", optarg);
4482                                 return -EINVAL;
4483                         }
4484                         break;
4485
4486                 case '?':
4487                         return -EINVAL;
4488
4489                 default:
4490                         log_error("Unknown option code %c", c);
4491                         return -EINVAL;
4492                 }
4493         }
4494
4495         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4496                 log_error("Cannot access user instance remotely.");
4497                 return -EINVAL;
4498         }
4499
4500         return 1;
4501 }
4502
4503 static int halt_parse_argv(int argc, char *argv[]) {
4504
4505         enum {
4506                 ARG_HELP = 0x100,
4507                 ARG_HALT,
4508                 ARG_REBOOT,
4509                 ARG_NO_WALL
4510         };
4511
4512         static const struct option options[] = {
4513                 { "help",      no_argument,       NULL, ARG_HELP    },
4514                 { "halt",      no_argument,       NULL, ARG_HALT    },
4515                 { "poweroff",  no_argument,       NULL, 'p'         },
4516                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4517                 { "force",     no_argument,       NULL, 'f'         },
4518                 { "wtmp-only", no_argument,       NULL, 'w'         },
4519                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4520                 { "no-sync",   no_argument,       NULL, 'n'         },
4521                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4522                 { NULL,        0,                 NULL, 0           }
4523         };
4524
4525         int c, runlevel;
4526
4527         assert(argc >= 0);
4528         assert(argv);
4529
4530         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4531                 if (runlevel == '0' || runlevel == '6')
4532                         arg_force = 2;
4533
4534         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4535                 switch (c) {
4536
4537                 case ARG_HELP:
4538                         halt_help();
4539                         return 0;
4540
4541                 case ARG_HALT:
4542                         arg_action = ACTION_HALT;
4543                         break;
4544
4545                 case 'p':
4546                         if (arg_action != ACTION_REBOOT)
4547                                 arg_action = ACTION_POWEROFF;
4548                         break;
4549
4550                 case ARG_REBOOT:
4551                         arg_action = ACTION_REBOOT;
4552                         break;
4553
4554                 case 'f':
4555                         arg_force = 2;
4556                         break;
4557
4558                 case 'w':
4559                         arg_dry = true;
4560                         break;
4561
4562                 case 'd':
4563                         arg_no_wtmp = true;
4564                         break;
4565
4566                 case 'n':
4567                         arg_no_sync = true;
4568                         break;
4569
4570                 case ARG_NO_WALL:
4571                         arg_no_wall = true;
4572                         break;
4573
4574                 case 'i':
4575                 case 'h':
4576                         /* Compatibility nops */
4577                         break;
4578
4579                 case '?':
4580                         return -EINVAL;
4581
4582                 default:
4583                         log_error("Unknown option code %c", c);
4584                         return -EINVAL;
4585                 }
4586         }
4587
4588         if (optind < argc) {
4589                 log_error("Too many arguments.");
4590                 return -EINVAL;
4591         }
4592
4593         return 1;
4594 }
4595
4596 static int parse_time_spec(const char *t, usec_t *_u) {
4597         assert(t);
4598         assert(_u);
4599
4600         if (streq(t, "now"))
4601                 *_u = 0;
4602         else if (!strchr(t, ':')) {
4603                 uint64_t u;
4604
4605                 if (safe_atou64(t, &u) < 0)
4606                         return -EINVAL;
4607
4608                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4609         } else {
4610                 char *e = NULL;
4611                 long hour, minute;
4612                 struct tm tm;
4613                 time_t s;
4614                 usec_t n;
4615
4616                 errno = 0;
4617                 hour = strtol(t, &e, 10);
4618                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4619                         return -EINVAL;
4620
4621                 minute = strtol(e+1, &e, 10);
4622                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4623                         return -EINVAL;
4624
4625                 n = now(CLOCK_REALTIME);
4626                 s = (time_t) (n / USEC_PER_SEC);
4627
4628                 zero(tm);
4629                 assert_se(localtime_r(&s, &tm));
4630
4631                 tm.tm_hour = (int) hour;
4632                 tm.tm_min = (int) minute;
4633                 tm.tm_sec = 0;
4634
4635                 assert_se(s = mktime(&tm));
4636
4637                 *_u = (usec_t) s * USEC_PER_SEC;
4638
4639                 while (*_u <= n)
4640                         *_u += USEC_PER_DAY;
4641         }
4642
4643         return 0;
4644 }
4645
4646 static int shutdown_parse_argv(int argc, char *argv[]) {
4647
4648         enum {
4649                 ARG_HELP = 0x100,
4650                 ARG_NO_WALL
4651         };
4652
4653         static const struct option options[] = {
4654                 { "help",      no_argument,       NULL, ARG_HELP    },
4655                 { "halt",      no_argument,       NULL, 'H'         },
4656                 { "poweroff",  no_argument,       NULL, 'P'         },
4657                 { "reboot",    no_argument,       NULL, 'r'         },
4658                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
4659                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4660                 { NULL,        0,                 NULL, 0           }
4661         };
4662
4663         int c, r;
4664
4665         assert(argc >= 0);
4666         assert(argv);
4667
4668         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4669                 switch (c) {
4670
4671                 case ARG_HELP:
4672                         shutdown_help();
4673                         return 0;
4674
4675                 case 'H':
4676                         arg_action = ACTION_HALT;
4677                         break;
4678
4679                 case 'P':
4680                         arg_action = ACTION_POWEROFF;
4681                         break;
4682
4683                 case 'r':
4684                         if (kexec_loaded())
4685                                 arg_action = ACTION_KEXEC;
4686                         else
4687                                 arg_action = ACTION_REBOOT;
4688                         break;
4689
4690                 case 'K':
4691                         arg_action = ACTION_KEXEC;
4692                         break;
4693
4694                 case 'h':
4695                         if (arg_action != ACTION_HALT)
4696                                 arg_action = ACTION_POWEROFF;
4697                         break;
4698
4699                 case 'k':
4700                         arg_dry = true;
4701                         break;
4702
4703                 case ARG_NO_WALL:
4704                         arg_no_wall = true;
4705                         break;
4706
4707                 case 't':
4708                 case 'a':
4709                         /* Compatibility nops */
4710                         break;
4711
4712                 case 'c':
4713                         arg_action = ACTION_CANCEL_SHUTDOWN;
4714                         break;
4715
4716                 case '?':
4717                         return -EINVAL;
4718
4719                 default:
4720                         log_error("Unknown option code %c", c);
4721                         return -EINVAL;
4722                 }
4723         }
4724
4725         if (argc > optind) {
4726                 r = parse_time_spec(argv[optind], &arg_when);
4727                 if (r < 0) {
4728                         log_error("Failed to parse time specification: %s", argv[optind]);
4729                         return r;
4730                 }
4731         } else
4732                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4733
4734         /* We skip the time argument */
4735         if (argc > optind + 1)
4736                 arg_wall = argv + optind + 1;
4737
4738         optind = argc;
4739
4740         return 1;
4741 }
4742
4743 static int telinit_parse_argv(int argc, char *argv[]) {
4744
4745         enum {
4746                 ARG_HELP = 0x100,
4747                 ARG_NO_WALL
4748         };
4749
4750         static const struct option options[] = {
4751                 { "help",      no_argument,       NULL, ARG_HELP    },
4752                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4753                 { NULL,        0,                 NULL, 0           }
4754         };
4755
4756         static const struct {
4757                 char from;
4758                 enum action to;
4759         } table[] = {
4760                 { '0', ACTION_POWEROFF },
4761                 { '6', ACTION_REBOOT },
4762                 { '1', ACTION_RESCUE },
4763                 { '2', ACTION_RUNLEVEL2 },
4764                 { '3', ACTION_RUNLEVEL3 },
4765                 { '4', ACTION_RUNLEVEL4 },
4766                 { '5', ACTION_RUNLEVEL5 },
4767                 { 's', ACTION_RESCUE },
4768                 { 'S', ACTION_RESCUE },
4769                 { 'q', ACTION_RELOAD },
4770                 { 'Q', ACTION_RELOAD },
4771                 { 'u', ACTION_REEXEC },
4772                 { 'U', ACTION_REEXEC }
4773         };
4774
4775         unsigned i;
4776         int c;
4777
4778         assert(argc >= 0);
4779         assert(argv);
4780
4781         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4782                 switch (c) {
4783
4784                 case ARG_HELP:
4785                         telinit_help();
4786                         return 0;
4787
4788                 case ARG_NO_WALL:
4789                         arg_no_wall = true;
4790                         break;
4791
4792                 case '?':
4793                         return -EINVAL;
4794
4795                 default:
4796                         log_error("Unknown option code %c", c);
4797                         return -EINVAL;
4798                 }
4799         }
4800
4801         if (optind >= argc) {
4802                 telinit_help();
4803                 return -EINVAL;
4804         }
4805
4806         if (optind + 1 < argc) {
4807                 log_error("Too many arguments.");
4808                 return -EINVAL;
4809         }
4810
4811         if (strlen(argv[optind]) != 1) {
4812                 log_error("Expected single character argument.");
4813                 return -EINVAL;
4814         }
4815
4816         for (i = 0; i < ELEMENTSOF(table); i++)
4817                 if (table[i].from == argv[optind][0])
4818                         break;
4819
4820         if (i >= ELEMENTSOF(table)) {
4821                 log_error("Unknown command %s.", argv[optind]);
4822                 return -EINVAL;
4823         }
4824
4825         arg_action = table[i].to;
4826
4827         optind ++;
4828
4829         return 1;
4830 }
4831
4832 static int runlevel_parse_argv(int argc, char *argv[]) {
4833
4834         enum {
4835                 ARG_HELP = 0x100,
4836         };
4837
4838         static const struct option options[] = {
4839                 { "help",      no_argument,       NULL, ARG_HELP    },
4840                 { NULL,        0,                 NULL, 0           }
4841         };
4842
4843         int c;
4844
4845         assert(argc >= 0);
4846         assert(argv);
4847
4848         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4849                 switch (c) {
4850
4851                 case ARG_HELP:
4852                         runlevel_help();
4853                         return 0;
4854
4855                 case '?':
4856                         return -EINVAL;
4857
4858                 default:
4859                         log_error("Unknown option code %c", c);
4860                         return -EINVAL;
4861                 }
4862         }
4863
4864         if (optind < argc) {
4865                 log_error("Too many arguments.");
4866                 return -EINVAL;
4867         }
4868
4869         return 1;
4870 }
4871
4872 static int parse_argv(int argc, char *argv[]) {
4873         assert(argc >= 0);
4874         assert(argv);
4875
4876         if (program_invocation_short_name) {
4877
4878                 if (strstr(program_invocation_short_name, "halt")) {
4879                         arg_action = ACTION_HALT;
4880                         return halt_parse_argv(argc, argv);
4881                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4882                         arg_action = ACTION_POWEROFF;
4883                         return halt_parse_argv(argc, argv);
4884                 } else if (strstr(program_invocation_short_name, "reboot")) {
4885                         if (kexec_loaded())
4886                                 arg_action = ACTION_KEXEC;
4887                         else
4888                                 arg_action = ACTION_REBOOT;
4889                         return halt_parse_argv(argc, argv);
4890                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4891                         arg_action = ACTION_POWEROFF;
4892                         return shutdown_parse_argv(argc, argv);
4893                 } else if (strstr(program_invocation_short_name, "init")) {
4894
4895                         if (sd_booted() > 0) {
4896                                 arg_action = ACTION_INVALID;
4897                                 return telinit_parse_argv(argc, argv);
4898                         } else {
4899                                 /* Hmm, so some other init system is
4900                                  * running, we need to forward this
4901                                  * request to it. For now we simply
4902                                  * guess that it is Upstart. */
4903
4904                                 execv("/lib/upstart/telinit", argv);
4905
4906                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4907                                 return -EIO;
4908                         }
4909
4910                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4911                         arg_action = ACTION_RUNLEVEL;
4912                         return runlevel_parse_argv(argc, argv);
4913                 }
4914         }
4915
4916         arg_action = ACTION_SYSTEMCTL;
4917         return systemctl_parse_argv(argc, argv);
4918 }
4919
4920 static int action_to_runlevel(void) {
4921
4922         static const char table[_ACTION_MAX] = {
4923                 [ACTION_HALT] =      '0',
4924                 [ACTION_POWEROFF] =  '0',
4925                 [ACTION_REBOOT] =    '6',
4926                 [ACTION_RUNLEVEL2] = '2',
4927                 [ACTION_RUNLEVEL3] = '3',
4928                 [ACTION_RUNLEVEL4] = '4',
4929                 [ACTION_RUNLEVEL5] = '5',
4930                 [ACTION_RESCUE] =    '1'
4931         };
4932
4933         assert(arg_action < _ACTION_MAX);
4934
4935         return table[arg_action];
4936 }
4937
4938 static int talk_upstart(void) {
4939         DBusMessage *m = NULL, *reply = NULL;
4940         DBusError error;
4941         int previous, rl, r;
4942         char
4943                 env1_buf[] = "RUNLEVEL=X",
4944                 env2_buf[] = "PREVLEVEL=X";
4945         char *env1 = env1_buf, *env2 = env2_buf;
4946         const char *emit = "runlevel";
4947         dbus_bool_t b_false = FALSE;
4948         DBusMessageIter iter, sub;
4949         DBusConnection *bus;
4950
4951         dbus_error_init(&error);
4952
4953         if (!(rl = action_to_runlevel()))
4954                 return 0;
4955
4956         if (utmp_get_runlevel(&previous, NULL) < 0)
4957                 previous = 'N';
4958
4959         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4960                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4961                         r = 0;
4962                         goto finish;
4963                 }
4964
4965                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4966                 r = -EIO;
4967                 goto finish;
4968         }
4969
4970         if ((r = bus_check_peercred(bus)) < 0) {
4971                 log_error("Failed to verify owner of bus.");
4972                 goto finish;
4973         }
4974
4975         if (!(m = dbus_message_new_method_call(
4976                               "com.ubuntu.Upstart",
4977                               "/com/ubuntu/Upstart",
4978                               "com.ubuntu.Upstart0_6",
4979                               "EmitEvent"))) {
4980
4981                 log_error("Could not allocate message.");
4982                 r = -ENOMEM;
4983                 goto finish;
4984         }
4985
4986         dbus_message_iter_init_append(m, &iter);
4987
4988         env1_buf[sizeof(env1_buf)-2] = rl;
4989         env2_buf[sizeof(env2_buf)-2] = previous;
4990
4991         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4992             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4993             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4994             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4995             !dbus_message_iter_close_container(&iter, &sub) ||
4996             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4997                 log_error("Could not append arguments to message.");
4998                 r = -ENOMEM;
4999                 goto finish;
5000         }
5001
5002         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5003
5004                 if (error_is_no_service(&error)) {
5005                         r = -EADDRNOTAVAIL;
5006                         goto finish;
5007                 }
5008
5009                 log_error("Failed to issue method call: %s", bus_error_message(&error));
5010                 r = -EIO;
5011                 goto finish;
5012         }
5013
5014         r = 1;
5015
5016 finish:
5017         if (m)
5018                 dbus_message_unref(m);
5019
5020         if (reply)
5021                 dbus_message_unref(reply);
5022
5023         if (bus) {
5024                 dbus_connection_flush(bus);
5025                 dbus_connection_close(bus);
5026                 dbus_connection_unref(bus);
5027         }
5028
5029         dbus_error_free(&error);
5030
5031         return r;
5032 }
5033
5034 static int talk_initctl(void) {
5035         struct init_request request;
5036         int r, fd;
5037         char rl;
5038
5039         if (!(rl = action_to_runlevel()))
5040                 return 0;
5041
5042         zero(request);
5043         request.magic = INIT_MAGIC;
5044         request.sleeptime = 0;
5045         request.cmd = INIT_CMD_RUNLVL;
5046         request.runlevel = rl;
5047
5048         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5049
5050                 if (errno == ENOENT)
5051                         return 0;
5052
5053                 log_error("Failed to open "INIT_FIFO": %m");
5054                 return -errno;
5055         }
5056
5057         errno = 0;
5058         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5059         close_nointr_nofail(fd);
5060
5061         if (r < 0) {
5062                 log_error("Failed to write to "INIT_FIFO": %m");
5063                 return errno ? -errno : -EIO;
5064         }
5065
5066         return 1;
5067 }
5068
5069 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
5070
5071         static const struct {
5072                 const char* verb;
5073                 const enum {
5074                         MORE,
5075                         LESS,
5076                         EQUAL
5077                 } argc_cmp;
5078                 const int argc;
5079                 int (* const dispatch)(DBusConnection *bus, char **args);
5080         } verbs[] = {
5081                 { "list-units",            LESS,  1, list_units        },
5082                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
5083                 { "list-jobs",             EQUAL, 1, list_jobs         },
5084                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
5085                 { "load",                  MORE,  2, load_unit         },
5086                 { "cancel",                MORE,  2, cancel_job        },
5087                 { "start",                 MORE,  2, start_unit        },
5088                 { "stop",                  MORE,  2, start_unit        },
5089                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5090                 { "reload",                MORE,  2, start_unit        },
5091                 { "restart",               MORE,  2, start_unit        },
5092                 { "try-restart",           MORE,  2, start_unit        },
5093                 { "reload-or-restart",     MORE,  2, start_unit        },
5094                 { "reload-or-try-restart", MORE,  2, start_unit        },
5095                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
5096                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
5097                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
5098                 { "isolate",               EQUAL, 2, start_unit        },
5099                 { "kill",                  MORE,  2, kill_unit         },
5100                 { "is-active",             MORE,  2, check_unit        },
5101                 { "check",                 MORE,  2, check_unit        },
5102                 { "show",                  MORE,  1, show              },
5103                 { "status",                MORE,  2, show              },
5104                 { "dump",                  EQUAL, 1, dump              },
5105                 { "dot",                   EQUAL, 1, dot               },
5106                 { "snapshot",              LESS,  2, snapshot          },
5107                 { "delete",                MORE,  2, delete_snapshot   },
5108                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
5109                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
5110                 { "show-environment",      EQUAL, 1, show_enviroment   },
5111                 { "set-environment",       MORE,  2, set_environment   },
5112                 { "unset-environment",     MORE,  2, set_environment   },
5113                 { "halt",                  EQUAL, 1, start_special     },
5114                 { "poweroff",              EQUAL, 1, start_special     },
5115                 { "reboot",                EQUAL, 1, start_special     },
5116                 { "kexec",                 EQUAL, 1, start_special     },
5117                 { "default",               EQUAL, 1, start_special     },
5118                 { "rescue",                EQUAL, 1, start_special     },
5119                 { "emergency",             EQUAL, 1, start_special     },
5120                 { "exit",                  EQUAL, 1, start_special     },
5121                 { "reset-failed",          MORE,  1, reset_failed      },
5122                 { "enable",                MORE,  2, enable_unit       },
5123                 { "disable",               MORE,  2, enable_unit       },
5124                 { "is-enabled",            MORE,  2, unit_is_enabled   },
5125                 { "reenable",              MORE,  2, enable_unit       },
5126                 { "preset",                MORE,  2, enable_unit       },
5127                 { "mask",                  MORE,  2, enable_unit       },
5128                 { "unmask",                MORE,  2, enable_unit       },
5129                 { "link",                  MORE,  2, enable_unit       }
5130         };
5131
5132         int left;
5133         unsigned i;
5134
5135         assert(argc >= 0);
5136         assert(argv);
5137         assert(error);
5138
5139         left = argc - optind;
5140
5141         if (left <= 0)
5142                 /* Special rule: no arguments means "list-units" */
5143                 i = 0;
5144         else {
5145                 if (streq(argv[optind], "help")) {
5146                         systemctl_help();
5147                         return 0;
5148                 }
5149
5150                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5151                         if (streq(argv[optind], verbs[i].verb))
5152                                 break;
5153
5154                 if (i >= ELEMENTSOF(verbs)) {
5155                         log_error("Unknown operation %s", argv[optind]);
5156                         return -EINVAL;
5157                 }
5158         }
5159
5160         switch (verbs[i].argc_cmp) {
5161
5162         case EQUAL:
5163                 if (left != verbs[i].argc) {
5164                         log_error("Invalid number of arguments.");
5165                         return -EINVAL;
5166                 }
5167
5168                 break;
5169
5170         case MORE:
5171                 if (left < verbs[i].argc) {
5172                         log_error("Too few arguments.");
5173                         return -EINVAL;
5174                 }
5175
5176                 break;
5177
5178         case LESS:
5179                 if (left > verbs[i].argc) {
5180                         log_error("Too many arguments.");
5181                         return -EINVAL;
5182                 }
5183
5184                 break;
5185
5186         default:
5187                 assert_not_reached("Unknown comparison operator.");
5188         }
5189
5190         /* Require a bus connection for all operations but
5191          * enable/disable */
5192         if (!streq(verbs[i].verb, "enable") &&
5193             !streq(verbs[i].verb, "disable") &&
5194             !streq(verbs[i].verb, "is-enabled") &&
5195             !streq(verbs[i].verb, "list-unit-files") &&
5196             !streq(verbs[i].verb, "reenable") &&
5197             !streq(verbs[i].verb, "preset") &&
5198             !streq(verbs[i].verb, "mask") &&
5199             !streq(verbs[i].verb, "unmask") &&
5200             !streq(verbs[i].verb, "link")) {
5201
5202                 if (running_in_chroot() > 0) {
5203                         log_info("Running in chroot, ignoring request.");
5204                         return 0;
5205                 }
5206
5207                 if (!bus) {
5208                         log_error("Failed to get D-Bus connection: %s",
5209                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5210                         return -EIO;
5211                 }
5212
5213         } else {
5214
5215                 if (!bus && !avoid_bus()) {
5216                         log_error("Failed to get D-Bus connection: %s",
5217                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5218                         return -EIO;
5219                 }
5220         }
5221
5222         return verbs[i].dispatch(bus, argv + optind);
5223 }
5224
5225 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5226         int fd;
5227         struct msghdr msghdr;
5228         struct iovec iovec[2];
5229         union sockaddr_union sockaddr;
5230         struct sd_shutdown_command c;
5231
5232         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5233         if (fd < 0)
5234                 return -errno;
5235
5236         zero(c);
5237         c.usec = t;
5238         c.mode = mode;
5239         c.dry_run = dry_run;
5240         c.warn_wall = warn;
5241
5242         zero(sockaddr);
5243         sockaddr.sa.sa_family = AF_UNIX;
5244         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5245
5246         zero(msghdr);
5247         msghdr.msg_name = &sockaddr;
5248         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5249
5250         zero(iovec);
5251         iovec[0].iov_base = (char*) &c;
5252         iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5253
5254         if (isempty(message))
5255                 msghdr.msg_iovlen = 1;
5256         else {
5257                 iovec[1].iov_base = (char*) message;
5258                 iovec[1].iov_len = strlen(message);
5259                 msghdr.msg_iovlen = 2;
5260         }
5261         msghdr.msg_iov = iovec;
5262
5263         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5264                 close_nointr_nofail(fd);
5265                 return -errno;
5266         }
5267
5268         close_nointr_nofail(fd);
5269         return 0;
5270 }
5271
5272 static int reload_with_fallback(DBusConnection *bus) {
5273
5274         if (bus) {
5275                 /* First, try systemd via D-Bus. */
5276                 if (daemon_reload(bus, NULL) >= 0)
5277                         return 0;
5278         }
5279
5280         /* Nothing else worked, so let's try signals */
5281         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5282
5283         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5284                 log_error("kill() failed: %m");
5285                 return -errno;
5286         }
5287
5288         return 0;
5289 }
5290
5291 static int start_with_fallback(DBusConnection *bus) {
5292
5293         if (bus) {
5294                 /* First, try systemd via D-Bus. */
5295                 if (start_unit(bus, NULL) >= 0)
5296                         goto done;
5297         }
5298
5299         /* Hmm, talking to systemd via D-Bus didn't work. Then
5300          * let's try to talk to Upstart via D-Bus. */
5301         if (talk_upstart() > 0)
5302                 goto done;
5303
5304         /* Nothing else worked, so let's try
5305          * /dev/initctl */
5306         if (talk_initctl() > 0)
5307                 goto done;
5308
5309         log_error("Failed to talk to init daemon.");
5310         return -EIO;
5311
5312 done:
5313         warn_wall(arg_action);
5314         return 0;
5315 }
5316
5317 static void halt_now(enum action a) {
5318
5319        /* Make sure C-A-D is handled by the kernel from this
5320          * point on... */
5321         reboot(RB_ENABLE_CAD);
5322
5323         switch (a) {
5324
5325         case ACTION_HALT:
5326                 log_info("Halting.");
5327                 reboot(RB_HALT_SYSTEM);
5328                 break;
5329
5330         case ACTION_POWEROFF:
5331                 log_info("Powering off.");
5332                 reboot(RB_POWER_OFF);
5333                 break;
5334
5335         case ACTION_REBOOT:
5336                 log_info("Rebooting.");
5337                 reboot(RB_AUTOBOOT);
5338                 break;
5339
5340         default:
5341                 assert_not_reached("Unknown halt action.");
5342         }
5343
5344         assert_not_reached("Uh? This shouldn't happen.");
5345 }
5346
5347 static int halt_main(DBusConnection *bus) {
5348         int r;
5349
5350         if (geteuid() != 0) {
5351                 /* Try logind if we are a normal user and no special
5352                  * mode applies. Maybe PolicyKit allows us to shutdown
5353                  * the machine. */
5354
5355                 if (arg_when <= 0 &&
5356                     !arg_dry &&
5357                     !arg_force &&
5358                     (arg_action == ACTION_POWEROFF ||
5359                      arg_action == ACTION_REBOOT)) {
5360                         r = reboot_with_logind(bus, arg_action);
5361                         if (r >= 0)
5362                                 return r;
5363                 }
5364
5365                 log_error("Must be root.");
5366                 return -EPERM;
5367         }
5368
5369         if (arg_when > 0) {
5370                 char *m;
5371
5372                 m = strv_join(arg_wall, " ");
5373                 r = send_shutdownd(arg_when,
5374                                    arg_action == ACTION_HALT     ? 'H' :
5375                                    arg_action == ACTION_POWEROFF ? 'P' :
5376                                    arg_action == ACTION_KEXEC    ? 'K' :
5377                                                                    'r',
5378                                    arg_dry,
5379                                    !arg_no_wall,
5380                                    m);
5381                 free(m);
5382
5383                 if (r < 0)
5384                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5385                 else {
5386                         char date[FORMAT_TIMESTAMP_MAX];
5387
5388                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5389                                  format_timestamp(date, sizeof(date), arg_when));
5390                         return 0;
5391                 }
5392         }
5393
5394         if (!arg_dry && !arg_force)
5395                 return start_with_fallback(bus);
5396
5397         if (!arg_no_wtmp) {
5398                 if (sd_booted() > 0)
5399                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5400                 else {
5401                         r = utmp_put_shutdown();
5402                         if (r < 0)
5403                                 log_warning("Failed to write utmp record: %s", strerror(-r));
5404                 }
5405         }
5406
5407         if (!arg_no_sync)
5408                 sync();
5409
5410         if (arg_dry)
5411                 return 0;
5412
5413         halt_now(arg_action);
5414         /* We should never reach this. */
5415         return -ENOSYS;
5416 }
5417
5418 static int runlevel_main(void) {
5419         int r, runlevel, previous;
5420
5421         r = utmp_get_runlevel(&runlevel, &previous);
5422         if (r < 0) {
5423                 puts("unknown");
5424                 return r;
5425         }
5426
5427         printf("%c %c\n",
5428                previous <= 0 ? 'N' : previous,
5429                runlevel <= 0 ? 'N' : runlevel);
5430
5431         return 0;
5432 }
5433
5434 int main(int argc, char*argv[]) {
5435         int r, retval = EXIT_FAILURE;
5436         DBusConnection *bus = NULL;
5437         DBusError error;
5438
5439         dbus_error_init(&error);
5440
5441         log_parse_environment();
5442         log_open();
5443
5444         r = parse_argv(argc, argv);
5445         if (r < 0)
5446                 goto finish;
5447         else if (r == 0) {
5448                 retval = EXIT_SUCCESS;
5449                 goto finish;
5450         }
5451
5452         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5453          * let's shortcut this */
5454         if (arg_action == ACTION_RUNLEVEL) {
5455                 r = runlevel_main();
5456                 retval = r < 0 ? EXIT_FAILURE : r;
5457                 goto finish;
5458         }
5459
5460         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5461                 log_info("Running in chroot, ignoring request.");
5462                 retval = 0;
5463                 goto finish;
5464         }
5465
5466         if (!avoid_bus()) {
5467                 if (arg_transport == TRANSPORT_NORMAL)
5468                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5469                 else if (arg_transport == TRANSPORT_POLKIT) {
5470                         bus_connect_system_polkit(&bus, &error);
5471                         private_bus = false;
5472                 } else if (arg_transport == TRANSPORT_SSH) {
5473                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5474                         private_bus = false;
5475                 } else
5476                         assert_not_reached("Uh, invalid transport...");
5477         }
5478
5479         switch (arg_action) {
5480
5481         case ACTION_SYSTEMCTL:
5482                 r = systemctl_main(bus, argc, argv, &error);
5483                 break;
5484
5485         case ACTION_HALT:
5486         case ACTION_POWEROFF:
5487         case ACTION_REBOOT:
5488         case ACTION_KEXEC:
5489                 r = halt_main(bus);
5490                 break;
5491
5492         case ACTION_RUNLEVEL2:
5493         case ACTION_RUNLEVEL3:
5494         case ACTION_RUNLEVEL4:
5495         case ACTION_RUNLEVEL5:
5496         case ACTION_RESCUE:
5497         case ACTION_EMERGENCY:
5498         case ACTION_DEFAULT:
5499                 r = start_with_fallback(bus);
5500                 break;
5501
5502         case ACTION_RELOAD:
5503         case ACTION_REEXEC:
5504                 r = reload_with_fallback(bus);
5505                 break;
5506
5507         case ACTION_CANCEL_SHUTDOWN:
5508                 r = send_shutdownd(0, 0, false, false, NULL);
5509                 break;
5510
5511         case ACTION_INVALID:
5512         case ACTION_RUNLEVEL:
5513         default:
5514                 assert_not_reached("Unknown action");
5515         }
5516
5517         retval = r < 0 ? EXIT_FAILURE : r;
5518
5519 finish:
5520         if (bus) {
5521                 dbus_connection_flush(bus);
5522                 dbus_connection_close(bus);
5523                 dbus_connection_unref(bus);
5524         }
5525
5526         dbus_error_free(&error);
5527
5528         dbus_shutdown();
5529
5530         strv_free(arg_property);
5531
5532         pager_close();
5533         ask_password_agent_close();
5534         polkit_agent_close();
5535
5536         return retval;
5537 }