]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/reboot-util.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / shared / reboot-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
e3631d1c
LP
2
3#include <errno.h>
ede5a78f 4#include <stdint.h>
ede5a78f
ST
5#include <sys/ioctl.h>
6#include <sys/mman.h>
e3631d1c
LP
7#include <unistd.h>
8
ede5a78f
ST
9#if HAVE_XENCTRL
10#define __XEN_INTERFACE_VERSION__ 0x00040900
11#include <xen/xen.h>
12#include <xen/kexec.h>
13#include <xen/sys/privcmd.h>
14#endif
15
c01dcddf 16#include "alloc-util.h"
ede5a78f
ST
17#include "errno-util.h"
18#include "fd-util.h"
e3631d1c
LP
19#include "fileio.h"
20#include "log.h"
2bfa8466 21#include "proc-cmdline.h"
c01dcddf 22#include "raw-reboot.h"
e3631d1c
LP
23#include "reboot-util.h"
24#include "string-util.h"
25#include "umask-util.h"
c01dcddf 26#include "virt.h"
e3631d1c 27
77defcf5 28int update_reboot_parameter_and_warn(const char *parameter, bool keep) {
e3631d1c
LP
29 int r;
30
31 if (isempty(parameter)) {
77defcf5
VJ
32 if (keep)
33 return 0;
34
e3631d1c
LP
35 if (unlink("/run/systemd/reboot-param") < 0) {
36 if (errno == ENOENT)
37 return 0;
38
39 return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
40 }
41
42 return 0;
43 }
44
2053593f 45 WITH_UMASK(0022) {
e3631d1c
LP
46 r = write_string_file("/run/systemd/reboot-param", parameter,
47 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
48 if (r < 0)
49 return log_warning_errno(r, "Failed to write reboot parameter file: %m");
50 }
51
428b296a
VJ
52 return 0;
53}
54
55int read_reboot_parameter(char **parameter) {
56 int r;
57
58 assert(parameter);
59
60 r = read_one_line_file("/run/systemd/reboot-param", parameter);
61 if (r < 0 && r != -ENOENT)
62 return log_debug_errno(r, "Failed to read /run/systemd/reboot-param: %m");
63
e3631d1c
LP
64 return 0;
65}
c01dcddf
LP
66
67int reboot_with_parameter(RebootFlags flags) {
68 int r;
69
b9a1ee32
ZJS
70 /* Reboots the system with a parameter that is read from /run/systemd/reboot-param. Returns 0 if
71 * REBOOT_DRY_RUN was set and the actual reboot operation was hence skipped. If REBOOT_FALLBACK is
72 * set and the reboot with parameter doesn't work out a fallback to classic reboot() is attempted. If
73 * REBOOT_FALLBACK is not set, 0 is returned instead, which should be considered indication for the
74 * caller to fall back to reboot() on its own, or somehow else deal with this. If REBOOT_LOG is
75 * specified will log about what it is going to do, as well as all errors. */
c01dcddf
LP
76
77 if (detect_container() == 0) {
78 _cleanup_free_ char *parameter = NULL;
79
80 r = read_one_line_file("/run/systemd/reboot-param", &parameter);
81 if (r < 0 && r != -ENOENT)
82 log_full_errno(flags & REBOOT_LOG ? LOG_WARNING : LOG_DEBUG, r,
83 "Failed to read reboot parameter file, ignoring: %m");
84
85 if (!isempty(parameter)) {
c01dcddf
LP
86 log_full(flags & REBOOT_LOG ? LOG_INFO : LOG_DEBUG,
87 "Rebooting with argument '%s'.", parameter);
88
89 if (flags & REBOOT_DRY_RUN)
90 return 0;
91
92 (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, parameter);
93
94 log_full_errno(flags & REBOOT_LOG ? LOG_WARNING : LOG_DEBUG, errno,
95 "Failed to reboot with parameter, retrying without: %m");
96 }
97 }
98
99 if (!(flags & REBOOT_FALLBACK))
100 return 0;
101
102 log_full(flags & REBOOT_LOG ? LOG_INFO : LOG_DEBUG, "Rebooting.");
103
104 if (flags & REBOOT_DRY_RUN)
105 return 0;
106
107 (void) reboot(RB_AUTOBOOT);
108
109 return log_full_errno(flags & REBOOT_LOG ? LOG_ERR : LOG_DEBUG, errno, "Failed to reboot: %m");
110}
2bfa8466
ZJS
111
112int shall_restore_state(void) {
113 bool ret;
114 int r;
115
116 r = proc_cmdline_get_bool("systemd.restore_state", &ret);
117 if (r < 0)
118 return r;
119
120 return r > 0 ? ret : true;
121}
ede5a78f
ST
122
123static int xen_kexec_loaded(void) {
124#if HAVE_XENCTRL
254d1313 125 _cleanup_close_ int privcmd_fd = -EBADF, buf_fd = -EBADF;
6564918c
YW
126 xen_kexec_status_t *buffer;
127 size_t size;
ede5a78f
ST
128 int r;
129
130 if (access("/proc/xen", F_OK) < 0) {
131 if (errno == ENOENT)
132 return -EOPNOTSUPP;
133 return log_debug_errno(errno, "Unable to test whether /proc/xen exists: %m");
134 }
135
136 size = page_size();
137 if (sizeof(xen_kexec_status_t) > size)
138 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "page_size is too small for hypercall");
139
140 privcmd_fd = open("/dev/xen/privcmd", O_RDWR|O_CLOEXEC);
141 if (privcmd_fd < 0)
142 return log_debug_errno(errno, "Cannot access /dev/xen/privcmd: %m");
143
144 buf_fd = open("/dev/xen/hypercall", O_RDWR|O_CLOEXEC);
145 if (buf_fd < 0)
146 return log_debug_errno(errno, "Cannot access /dev/xen/hypercall: %m");
147
148 buffer = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, buf_fd, 0);
149 if (buffer == MAP_FAILED)
150 return log_debug_errno(errno, "Cannot allocate buffer for hypercall: %m");
151
6564918c 152 *buffer = (xen_kexec_status_t) {
ede5a78f
ST
153 .type = KEXEC_TYPE_DEFAULT,
154 };
155
156 privcmd_hypercall_t call = {
157 .op = __HYPERVISOR_kexec_op,
158 .arg = {
159 KEXEC_CMD_kexec_status,
160 PTR_TO_UINT64(buffer),
161 },
162 };
163
164 r = RET_NERRNO(ioctl(privcmd_fd, IOCTL_PRIVCMD_HYPERCALL, &call));
165 if (r < 0)
166 log_debug_errno(r, "kexec_status failed: %m");
167
168 munmap(buffer, size);
169
170 return r;
171#else
172 return -EOPNOTSUPP;
173#endif
174}
175
176bool kexec_loaded(void) {
177 _cleanup_free_ char *s = NULL;
178 int r;
179
180 r = xen_kexec_loaded();
181 if (r >= 0)
182 return r;
183
184 r = read_one_line_file("/sys/kernel/kexec_loaded", &s);
185 if (r < 0) {
186 if (r != -ENOENT)
187 log_debug_errno(r, "Unable to read /sys/kernel/kexec_loaded, ignoring: %m");
188 return false;
189 }
190
191 return s[0] == '1';
192}