Merge pull request #22778 from poettering/kernel-install-layout-rework
kernel-install/bootctl: layout fixes
This commit is contained in:
@@ -275,6 +275,28 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(target);
|
||||
assert(ret_file);
|
||||
assert(ret_path);
|
||||
|
||||
fd = open_tmpfile_linkable(target, flags, &path);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
f = take_fdopen(&fd, "w");
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = TAKE_PTR(path);
|
||||
*ret_file = TAKE_PTR(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_tmpfile(int fd, const char *path, const char *target) {
|
||||
assert(fd >= 0);
|
||||
assert(target);
|
||||
@@ -292,6 +314,23 @@ int link_tmpfile(int fd, const char *path, const char *target) {
|
||||
return RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW));
|
||||
}
|
||||
|
||||
int flink_tmpfile(FILE *f, const char *path, const char *target) {
|
||||
int fd, r;
|
||||
|
||||
assert(f);
|
||||
assert(target);
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd < 0) /* Not all FILE* objects encapsulate fds */
|
||||
return -EBADF;
|
||||
|
||||
r = fflush_sync_and_check(f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return link_tmpfile(fd, path, target);
|
||||
}
|
||||
|
||||
int mkdtemp_malloc(const char *template, char **ret) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
@@ -13,7 +13,9 @@ int tempfn_random_child(const char *p, const char *extra, char **ret);
|
||||
|
||||
int open_tmpfile_unlinkable(const char *directory, int flags);
|
||||
int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
|
||||
int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file);
|
||||
|
||||
int link_tmpfile(int fd, const char *path, const char *target);
|
||||
int flink_tmpfile(FILE *f, const char *path, const char *target);
|
||||
|
||||
int mkdtemp_malloc(const char *template, char **ret);
|
||||
|
||||
+102
-29
@@ -144,38 +144,70 @@ static int acquire_xbootldr(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int load_install_machine_id_and_layout(void) {
|
||||
/* Figure out the right machine-id for operations. If KERNEL_INSTALL_MACHINE_ID is configured in
|
||||
* /etc/machine-info, let's use that. Otherwise, just use the real machine-id.
|
||||
*
|
||||
* Also load KERNEL_INSTALL_LAYOUT.
|
||||
*/
|
||||
static int load_etc_machine_id(void) {
|
||||
int r;
|
||||
|
||||
r = sd_id128_get_machine(&arg_machine_id);
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM)) /* Not set or empty */
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get machine-id: %m");
|
||||
|
||||
log_debug("Loaded machine ID %s from /etc/machine-id.", SD_ID128_TO_STRING(arg_machine_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_etc_machine_info(void) {
|
||||
/* systemd v250 added support to store the kernel-install layout setting and the machine ID to use
|
||||
* for setting up the ESP in /etc/machine-info. The newer /etc/kernel/entry-token file, as well as
|
||||
* the $layout field in /etc/kernel/install.conf are better replacements for this though, hence this
|
||||
* has been deprecated and is only returned for compatibility. */
|
||||
_cleanup_free_ char *s = NULL, *layout = NULL;
|
||||
int r;
|
||||
|
||||
r = parse_env_file(NULL, "/etc/machine-info",
|
||||
"KERNEL_INSTALL_LAYOUT", &layout,
|
||||
"KERNEL_INSTALL_MACHINE_ID", &s);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse /etc/machine-info: %m");
|
||||
|
||||
if (isempty(s)) {
|
||||
r = sd_id128_get_machine(&arg_machine_id);
|
||||
if (r < 0 && !IN_SET(r, -ENOENT, -ENOMEDIUM))
|
||||
return log_error_errno(r, "Failed to get machine-id: %m");
|
||||
} else {
|
||||
if (!isempty(s)) {
|
||||
log_notice("Read $KERNEL_INSTALL_MACHINE_ID from /etc/machine-info. Please move it to /etc/kernel/entry-token.");
|
||||
|
||||
r = sd_id128_from_string(s, &arg_machine_id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse KERNEL_INSTALL_MACHINE_ID=%s in /etc/machine-info: %m", s);
|
||||
|
||||
log_debug("Loaded KERNEL_INSTALL_MACHINE_ID=%s from KERNEL_INSTALL_MACHINE_ID in /etc/machine-info.",
|
||||
SD_ID128_TO_STRING(arg_machine_id));
|
||||
}
|
||||
log_debug("Using KERNEL_INSTALL_MACHINE_ID=%s from %s.",
|
||||
SD_ID128_TO_STRING(arg_machine_id),
|
||||
isempty(s) ? "/etc/machine_id" : "KERNEL_INSTALL_MACHINE_ID in /etc/machine-info");
|
||||
|
||||
if (!isempty(layout)) {
|
||||
log_notice("Read $KERNEL_INSTALL_LAYOUT from /etc/machine-info. Please move it to the layout= setting of /etc/kernel/install.conf.");
|
||||
|
||||
log_debug("KERNEL_INSTALL_LAYOUT=%s is specified in /etc/machine-info.", layout);
|
||||
arg_install_layout = TAKE_PTR(layout);
|
||||
free_and_replace(arg_install_layout, layout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_etc_kernel_install_conf(void) {
|
||||
_cleanup_free_ char *layout = NULL;
|
||||
int r;
|
||||
|
||||
r = parse_env_file(NULL, "/etc/kernel/install.conf",
|
||||
"layout", &layout);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse /etc/kernel/install.conf: %m");
|
||||
|
||||
if (!isempty(layout)) {
|
||||
log_debug("layout=%s is specified in /etc/machine-info.", layout);
|
||||
free_and_replace(arg_install_layout, layout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -282,7 +314,15 @@ static bool use_boot_loader_spec_type1(void) {
|
||||
static int settle_make_entry_directory(void) {
|
||||
int r;
|
||||
|
||||
r = load_install_machine_id_and_layout();
|
||||
r = load_etc_machine_id();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = load_etc_machine_info();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = load_etc_kernel_install_conf();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1246,7 +1286,6 @@ static int remove_loader_variables(void) {
|
||||
static int install_loader_config(const char *esp_path) {
|
||||
_cleanup_(unlink_and_freep) char *t = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
@@ -1256,13 +1295,9 @@ static int install_loader_config(const char *esp_path) {
|
||||
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
|
||||
return 0;
|
||||
|
||||
fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p);
|
||||
|
||||
f = take_fdopen(&fd, "w");
|
||||
if (!f)
|
||||
return log_oom();
|
||||
r = fopen_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t, &f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open \"%s\" for writing: %m", p);
|
||||
|
||||
fprintf(f, "#timeout 3\n"
|
||||
"#console-mode keep\n");
|
||||
@@ -1272,11 +1307,36 @@ static int install_loader_config(const char *esp_path) {
|
||||
fprintf(f, "default %s-*\n", arg_entry_token);
|
||||
}
|
||||
|
||||
r = fflush_sync_and_check(f);
|
||||
r = flink_tmpfile(f, t, p);
|
||||
if (r == -EEXIST)
|
||||
return 0; /* Silently skip creation if the file exists now (recheck) */
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write \"%s\": %m", p);
|
||||
return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
|
||||
|
||||
r = link_tmpfile(fileno(f), t, p);
|
||||
t = mfree(t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int install_loader_specification(const char *root) {
|
||||
_cleanup_(unlink_and_freep) char *t = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
p = path_join(root, "/loader/entries.srel");
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
|
||||
return 0;
|
||||
|
||||
r = fopen_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t, &f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open \"%s\" for writing: %m", p);
|
||||
|
||||
fprintf(f, "type1\n");
|
||||
|
||||
r = flink_tmpfile(f, t, p);
|
||||
if (r == -EEXIST)
|
||||
return 0; /* Silently skip creation if the file exists now (recheck) */
|
||||
if (r < 0)
|
||||
@@ -1998,6 +2058,10 @@ static int verb_install(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = install_loader_specification(arg_dollar_boot_path());
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
(void) sync_everything();
|
||||
@@ -2037,6 +2101,10 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
q = remove_file(arg_esp_path, "/loader/entries.srel");
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
q = remove_subdirs(arg_esp_path, esp_subdirs);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
@@ -2050,7 +2118,12 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
r = q;
|
||||
|
||||
if (arg_xbootldr_path) {
|
||||
/* Remove the latter two also in the XBOOTLDR partition if it exists */
|
||||
/* Remove a subset of these also from the XBOOTLDR partition if it exists */
|
||||
|
||||
q = remove_file(arg_xbootldr_path, "/loader/entries.srel");
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
q = remove_subdirs(arg_xbootldr_path, dollar_boot_subdirs);
|
||||
if (q < 0 && r >= 0)
|
||||
r = q;
|
||||
|
||||
@@ -155,10 +155,29 @@ done
|
||||
[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
|
||||
|
||||
if [ -z "$layout" ]; then
|
||||
# Administrative decision: if not present, some scripts generate into /boot.
|
||||
if [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
|
||||
# No layout configured by the administrator. Let's try to figure it out
|
||||
# automatically from metadata already contained in $BOOT_ROOT.
|
||||
if [ -e "$BOOT_ROOT/loader/entries.srel" ]; then
|
||||
read -r ENTRIES_SREL <"$BOOT_ROOT/loader/entries.srel"
|
||||
if [ "$ENTRIES_SREL" = "type1" ]; then
|
||||
# The loader/entries.srel file clearly indicates that the installed
|
||||
# boot loader implements the proper standard upstream boot loader
|
||||
# spec for Type #1 entries. Let's default to that, then.
|
||||
layout="bls"
|
||||
else
|
||||
# The loader/entries.srel file indicates some other spec is
|
||||
# implemented and owns the /loader/entries/ directory. Since we
|
||||
# have no idea what that means, let's stay away from it by default.
|
||||
layout="other"
|
||||
fi
|
||||
elif [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
|
||||
# If the metadata in $BOOT_ROOT doesn't tell us anything, then check if
|
||||
# the entry token directory already exists. If so, let's assume it's
|
||||
# the standard boot loader spec, too.
|
||||
layout="bls"
|
||||
else
|
||||
# There's no metadata in $BOOT_ROOT, and apparently no entry token
|
||||
# directory installed? Then we really don't know anything.
|
||||
layout="other"
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user