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