1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #define __XEN_INTERFACE_VERSION__ 0x00040900
12 #include <xen/kexec.h>
13 #include <xen/sys/privcmd.h>
16 #include "alloc-util.h"
17 #include "errno-util.h"
21 #include "proc-cmdline.h"
22 #include "raw-reboot.h"
23 #include "reboot-util.h"
24 #include "string-util.h"
25 #include "umask-util.h"
28 int update_reboot_parameter_and_warn(const char *parameter
, bool keep
) {
31 if (isempty(parameter
)) {
35 if (unlink("/run/systemd/reboot-param") < 0) {
39 return log_warning_errno(errno
, "Failed to unlink reboot parameter file: %m");
46 r
= write_string_file("/run/systemd/reboot-param", parameter
,
47 WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_ATOMIC
);
49 return log_warning_errno(r
, "Failed to write reboot parameter file: %m");
55 int read_reboot_parameter(char **parameter
) {
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");
67 int reboot_with_parameter(RebootFlags flags
) {
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. */
77 if (detect_container() == 0) {
78 _cleanup_free_
char *parameter
= NULL
;
80 r
= read_one_line_file("/run/systemd/reboot-param", ¶meter
);
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");
85 if (!isempty(parameter
)) {
86 log_full(flags
& REBOOT_LOG
? LOG_INFO
: LOG_DEBUG
,
87 "Rebooting with argument '%s'.", parameter
);
89 if (flags
& REBOOT_DRY_RUN
)
92 (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2
, parameter
);
94 log_full_errno(flags
& REBOOT_LOG
? LOG_WARNING
: LOG_DEBUG
, errno
,
95 "Failed to reboot with parameter, retrying without: %m");
99 if (!(flags
& REBOOT_FALLBACK
))
102 log_full(flags
& REBOOT_LOG
? LOG_INFO
: LOG_DEBUG
, "Rebooting.");
104 if (flags
& REBOOT_DRY_RUN
)
107 (void) reboot(RB_AUTOBOOT
);
109 return log_full_errno(flags
& REBOOT_LOG
? LOG_ERR
: LOG_DEBUG
, errno
, "Failed to reboot: %m");
112 int shall_restore_state(void) {
116 r
= proc_cmdline_get_bool("systemd.restore_state", &ret
);
120 return r
> 0 ? ret
: true;
123 static int xen_kexec_loaded(void) {
125 _cleanup_close_
int privcmd_fd
= -1, buf_fd
= -1;
126 xen_kexec_status_t
*buffer
;
130 if (access("/proc/xen", F_OK
) < 0) {
133 return log_debug_errno(errno
, "Unable to test whether /proc/xen exists: %m");
137 if (sizeof(xen_kexec_status_t
) > size
)
138 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "page_size is too small for hypercall");
140 privcmd_fd
= open("/dev/xen/privcmd", O_RDWR
|O_CLOEXEC
);
142 return log_debug_errno(errno
, "Cannot access /dev/xen/privcmd: %m");
144 buf_fd
= open("/dev/xen/hypercall", O_RDWR
|O_CLOEXEC
);
146 return log_debug_errno(errno
, "Cannot access /dev/xen/hypercall: %m");
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");
152 *buffer
= (xen_kexec_status_t
) {
153 .type
= KEXEC_TYPE_DEFAULT
,
156 privcmd_hypercall_t call
= {
157 .op
= __HYPERVISOR_kexec_op
,
159 KEXEC_CMD_kexec_status
,
160 PTR_TO_UINT64(buffer
),
164 r
= RET_NERRNO(ioctl(privcmd_fd
, IOCTL_PRIVCMD_HYPERCALL
, &call
));
166 log_debug_errno(r
, "kexec_status failed: %m");
168 munmap(buffer
, size
);
176 bool kexec_loaded(void) {
177 _cleanup_free_
char *s
= NULL
;
180 r
= xen_kexec_loaded();
184 r
= read_one_line_file("/sys/kernel/kexec_loaded", &s
);
187 log_debug_errno(r
, "Unable to read /sys/kernel/kexec_loaded, ignoring: %m");