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