Files
systemd/src/boot/bootctl-util.c
Mike Gilbert 7cd137e647 bootctl: avoid using __WORDSIZE macro
__WORDSIZE does not seem to be documented anywhere, and is probably
meant to be used internally by glibc headers.

In systemd, it was only being used in warning messages. We can avoid
using it by rewording the messages slightly.

Fixes a build error with musl libc.

Bug: https://bugs.gentoo.org/894430
2023-02-15 10:24:25 +09:00

212 lines
7.1 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/mman.h>
#include "bootctl.h"
#include "bootctl-util.h"
#include "fileio.h"
#include "os-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "sync-util.h"
#include "utf8.h"
int sync_everything(void) {
int ret = 0, k;
if (arg_esp_path) {
k = syncfs_path(AT_FDCWD, arg_esp_path);
if (k < 0)
ret = log_error_errno(k, "Failed to synchronize the ESP '%s': %m", arg_esp_path);
}
if (arg_xbootldr_path) {
k = syncfs_path(AT_FDCWD, arg_xbootldr_path);
if (k < 0)
ret = log_error_errno(k, "Failed to synchronize $BOOT '%s': %m", arg_xbootldr_path);
}
return ret;
}
const char *get_efi_arch(void) {
/* Detect EFI firmware architecture of the running system. On mixed mode systems, it could be 32bit
* while the kernel is running in 64bit. */
#ifdef __x86_64__
_cleanup_free_ char *platform_size = NULL;
int r;
r = read_one_line_file("/sys/firmware/efi/fw_platform_size", &platform_size);
if (r == -ENOENT)
return EFI_MACHINE_TYPE_NAME;
if (r < 0) {
log_warning_errno(r,
"Error reading EFI firmware word size, assuming machine type '%s': %m",
EFI_MACHINE_TYPE_NAME);
return EFI_MACHINE_TYPE_NAME;
}
if (streq(platform_size, "64"))
return EFI_MACHINE_TYPE_NAME;
if (streq(platform_size, "32"))
return "ia32";
log_warning(
"Unknown EFI firmware word size '%s', using machine type '%s'.",
platform_size,
EFI_MACHINE_TYPE_NAME);
#endif
return EFI_MACHINE_TYPE_NAME;
}
/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
int get_file_version(int fd, char **ret) {
struct stat st;
char *buf;
const char *s, *e;
char *x = NULL;
int r;
assert(fd >= 0);
assert(ret);
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat EFI binary: %m");
r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "EFI binary is not a regular file: %m");
if (st.st_size < 27 || file_offset_beyond_memory_size(st.st_size)) {
*ret = NULL;
return 0;
}
buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buf == MAP_FAILED)
return log_error_errno(errno, "Failed to memory map EFI binary: %m");
s = mempmem_safe(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
if (!s) {
r = -ESRCH;
goto finish;
}
e = memmem_safe(s, st.st_size - (s - buf), " ####", 5);
if (!e || e - s < 3) {
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
goto finish;
}
x = strndup(s, e - s);
if (!x) {
r = log_oom();
goto finish;
}
r = 1;
finish:
(void) munmap(buf, st.st_size);
if (r >= 0)
*ret = x;
return r;
}
int settle_entry_token(void) {
int r;
switch (arg_entry_token_type) {
case ARG_ENTRY_TOKEN_AUTO: {
_cleanup_free_ char *buf = NULL, *p = NULL;
p = path_join(arg_root, etc_kernel(), "entry-token");
if (!p)
return log_oom();
r = read_one_line_file(p, &buf);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to read %s: %m", p);
if (!isempty(buf)) {
free_and_replace(arg_entry_token, buf);
arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL;
} else if (sd_id128_is_null(arg_machine_id)) {
_cleanup_free_ char *id = NULL, *image_id = NULL;
r = parse_os_release(arg_root,
"IMAGE_ID", &image_id,
"ID", &id);
if (r < 0)
return log_error_errno(r, "Failed to load /etc/os-release: %m");
if (!isempty(image_id)) {
free_and_replace(arg_entry_token, image_id);
arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID;
} else if (!isempty(id)) {
free_and_replace(arg_entry_token, id);
arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
} else {
r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id));
if (r < 0)
return r;
arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID;
}
break;
}
case ARG_ENTRY_TOKEN_MACHINE_ID:
if (sd_id128_is_null(arg_machine_id))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set.");
r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id));
if (r < 0)
return r;
break;
case ARG_ENTRY_TOKEN_OS_IMAGE_ID: {
_cleanup_free_ char *buf = NULL;
r = parse_os_release(arg_root, "IMAGE_ID", &buf);
if (r < 0)
return log_error_errno(r, "Failed to load /etc/os-release: %m");
if (isempty(buf))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "IMAGE_ID= field not set in /etc/os-release.");
free_and_replace(arg_entry_token, buf);
break;
}
case ARG_ENTRY_TOKEN_OS_ID: {
_cleanup_free_ char *buf = NULL;
r = parse_os_release(arg_root, "ID", &buf);
if (r < 0)
return log_error_errno(r, "Failed to load /etc/os-release: %m");
if (isempty(buf))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "ID= field not set in /etc/os-release.");
free_and_replace(arg_entry_token, buf);
break;
}
case ARG_ENTRY_TOKEN_LITERAL:
assert(!isempty(arg_entry_token)); /* already filled in by command line parser */
break;
}
if (isempty(arg_entry_token) || !(utf8_is_valid(arg_entry_token) && string_is_safe(arg_entry_token)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token);
log_debug("Using entry token: %s", arg_entry_token);
return 0;
}