]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/sulogin-shell/sulogin-shell.c
tree-wide: introduce new safe_fork() helper and port everything over
[thirdparty/systemd.git] / src / sulogin-shell / sulogin-shell.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2017 Felipe Sateler
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <sys/prctl.h>
23
24 #include "bus-util.h"
25 #include "bus-error.h"
26 #include "def.h"
27 #include "log.h"
28 #include "process-util.h"
29 #include "sd-bus.h"
30 #include "signal-util.h"
31
32 static int reload_manager(sd_bus *bus) {
33 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
34 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
35 int r;
36
37 log_info("Reloading system manager configuration");
38
39 r = sd_bus_message_new_method_call(
40 bus,
41 &m,
42 "org.freedesktop.systemd1",
43 "/org/freedesktop/systemd1",
44 "org.freedesktop.systemd1.Manager",
45 "Reload");
46 if (r < 0)
47 return bus_log_create_error(r);
48
49 /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
50 * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
51 * their timeout, and for everything else there's the same time budget in place. */
52
53 r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
54 if (r < 0)
55 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
56
57 return 0;
58 }
59
60 static int start_default_target(sd_bus *bus) {
61 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
62 int r;
63
64 log_info("Starting default target");
65
66 /* Start these units only if we can replace base.target with it */
67 r = sd_bus_call_method(bus,
68 "org.freedesktop.systemd1",
69 "/org/freedesktop/systemd1",
70 "org.freedesktop.systemd1.Manager",
71 "StartUnit",
72 &error,
73 NULL,
74 "ss", "default.target", "isolate");
75
76 if (r < 0)
77 log_error("Failed to start default target: %s", bus_error_message(&error, r));
78
79 return r;
80 }
81
82 static int fork_wait(const char* const cmdline[]) {
83 pid_t pid;
84 int r;
85
86 r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
87 if (r < 0)
88 return log_error_errno(r, "fork(): %m");
89 if (r == 0) {
90 /* Child */
91 execv(cmdline[0], (char**) cmdline);
92 log_error_errno(errno, "Failed to execute %s: %m", cmdline[0]);
93 _exit(EXIT_FAILURE); /* Operational error */
94 }
95
96 return wait_for_terminate_and_warn(cmdline[0], pid, false);
97 }
98
99 static void print_mode(const char* mode) {
100 printf("You are in %s mode. After logging in, type \"journalctl -xb\" to view\n"
101 "system logs, \"systemctl reboot\" to reboot, \"systemctl default\" or \"exit\"\n"
102 "to boot into default mode.\n", mode);
103 fflush(stdout);
104 }
105
106 int main(int argc, char *argv[]) {
107 static const char* const sulogin_cmdline[] = {SULOGIN, NULL};
108 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
109 int r;
110
111 log_set_target(LOG_TARGET_AUTO);
112 log_parse_environment();
113 log_open();
114
115 print_mode(argc > 1 ? argv[1] : "");
116
117 (void) fork_wait(sulogin_cmdline);
118
119 r = bus_connect_system_systemd(&bus);
120 if (r < 0) {
121 log_warning_errno(r, "Failed to get D-Bus connection: %m");
122 r = 0;
123 } else {
124 (void) reload_manager(bus);
125
126 r = start_default_target(bus);
127 }
128
129 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
130 }