#include "dirent-util.h"
#include "efi-loader.h"
#include "efivars.h"
+#include "env-file.h"
#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
#include "sync-util.h"
#include "terminal-util.h"
#include "tmpfile-util.h"
+#include "tmpfile-util-label.h"
#include "umask-util.h"
#include "utf8.h"
#include "util.h"
static PagerFlags arg_pager_flags = 0;
static bool arg_graceful = false;
static int arg_make_machine_id_directory = -1;
+static sd_id128_t arg_machine_id = SD_ID128_NULL;
+static char *arg_install_layout = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep);
static const char *arg_dollar_boot_path(void) {
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
return 1;
}
-static void settle_make_machine_id_directory(void) {
+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.
+ */
+ _cleanup_free_ char *s = NULL, *layout = NULL;
int r;
- if (arg_make_machine_id_directory >= 0)
- return;
+ r = parse_env_file(NULL, "/etc/machine-info",
+ "KERNEL_INSTALL_LAYOUT", &layout,
+ "KERNEL_INSTALL_MACHINE_ID", &s);
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "Failed to parse /etc/machine-info: %m");
- r = path_is_temporary_fs("/etc/machine-id");
+ if (isempty(s)) {
+ r = sd_id128_get_machine(&arg_machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine-id: %m");
+ } else {
+ 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("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_debug("KERNEL_INSTALL_LAYOUT=%s is specified in /etc/machine-info.", layout);
+ arg_install_layout = TAKE_PTR(layout);
+ }
+
+ return 0;
+}
+
+static int settle_install_machine_id(void) {
+ int r;
+
+ r = load_install_machine_id_and_layout();
if (r < 0)
- log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system, assuming so.");
+ return r;
+
+ bool layout_non_bls = arg_install_layout && !streq(arg_install_layout, "bls");
+ if (arg_make_machine_id_directory < 0) {
+ if (layout_non_bls)
+ arg_make_machine_id_directory = 0;
+ else {
+ r = path_is_temporary_fs("/etc/machine-id");
+ if (r < 0)
+ return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m");
+ arg_make_machine_id_directory = r == 0;
+ }
+ }
- arg_make_machine_id_directory = r == 0;
+ if (arg_make_machine_id_directory > 0 && layout_non_bls)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "KERNEL_INSTALL_LAYOUT=%s is configured, but bls directory creation was requested.",
+ arg_install_layout);
+
+ return 0;
}
/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
}
static int remove_machine_id_directory(const char *root) {
- sd_id128_t machine_id;
- int r;
-
assert(root);
assert(arg_make_machine_id_directory >= 0);
+ assert(!sd_id128_is_null(arg_machine_id));
if (!arg_make_machine_id_directory)
return 0;
- r = sd_id128_get_machine(&machine_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get machine id: %m");
-
- return rmdir_one(root, SD_ID128_TO_STRING(machine_id));
+ return rmdir_one(root, SD_ID128_TO_STRING(arg_machine_id));
}
static int remove_binaries(const char *esp_path) {
"#console-mode keep\n");
if (arg_make_machine_id_directory) {
- sd_id128_t machine_id;
-
- r = sd_id128_get_machine(&machine_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get machine id: %m");
-
- fprintf(f, "default %s-*\n", SD_ID128_TO_STRING(machine_id));
+ assert(!sd_id128_is_null(arg_machine_id));
+ fprintf(f, "default %s-*\n", SD_ID128_TO_STRING(arg_machine_id));
}
r = fflush_sync_and_check(f);
}
static int install_machine_id_directory(const char *root) {
- sd_id128_t machine_id;
- int r;
-
assert(root);
assert(arg_make_machine_id_directory >= 0);
if (!arg_make_machine_id_directory)
return 0;
- r = sd_id128_get_machine(&machine_id);
+ assert(!sd_id128_is_null(arg_machine_id));
+ return mkdir_one(root, SD_ID128_TO_STRING(arg_machine_id));
+}
+
+static int install_machine_info_config(void) {
+ _cleanup_free_ char *contents = NULL;
+ size_t length;
+ bool need_install_layout = true, need_machine_id;
+ int r;
+
+ assert(arg_make_machine_id_directory >= 0);
+
+ /* We only want to save the machine-id if we created any directories using it. */
+ need_machine_id = arg_make_machine_id_directory;
+
+ _cleanup_fclose_ FILE *orig = fopen("/etc/machine-info", "re");
+ if (!orig && errno != ENOENT)
+ return log_error_errno(errno, "Failed to open /etc/machine-info: %m");
+
+ if (orig) {
+ _cleanup_free_ char *install_layout = NULL, *machine_id = NULL;
+
+ r = parse_env_file(orig, "/etc/machine-info",
+ "KERNEL_INSTALL_LAYOUT", &install_layout,
+ "KERNEL_INSTALL_MACHINE_ID", &machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse /etc/machine-info: %m");
+
+ rewind(orig);
+
+ if (!isempty(install_layout))
+ need_install_layout = false;
+
+ if (!isempty(machine_id))
+ need_machine_id = false;
+
+ if (!need_install_layout && !need_machine_id) {
+ log_debug("/etc/machine-info already has KERNEL_INSTALL_MACHINE_ID=%s and KERNEL_INSTALL_LAYOUT=%s.",
+ machine_id, install_layout);
+ return 0;
+ }
+
+ r = read_full_stream(orig, &contents, &length);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read /etc/machine-info: %m");
+ }
+
+ _cleanup_(unlink_and_freep) char *dst_tmp = NULL;
+ _cleanup_fclose_ FILE *dst = NULL;
+ r = fopen_temporary_label("/etc/machine-info", /* The path for which to the look up the label */
+ "/etc/machine-info", /* Where we want the file actually to end up */
+ &dst, /* The temporary file we write to */
+ &dst_tmp);
if (r < 0)
- return log_error_errno(r, "Failed to get machine id: %m");
+ return log_debug_errno(r, "Failed to open temporary copy of /etc/machine-info: %m");
+
+ if (contents)
+ fwrite_unlocked(contents, 1, length, dst);
+
+ bool no_newline = !contents || contents[length - 1] == '\n';
- return mkdir_one(root, SD_ID128_TO_STRING(machine_id));
+ if (need_install_layout) {
+ const char *line = "\nKERNEL_INSTALL_LAYOUT=bls\n" + no_newline;
+ fwrite_unlocked(line, 1, strlen(line), dst);
+ no_newline = false;
+ }
+
+ const char *mid_string = SD_ID128_TO_STRING(arg_machine_id);
+ if (need_machine_id)
+ fprintf(dst, "%sKERNEL_INSTALL_MACHINE_ID=%s\n",
+ no_newline ? "" : "\n",
+ mid_string);
+
+ r = fflush_and_check(dst);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write temporary copy of /etc/machine-info: %m");
+ if (fchmod(fileno(dst), 0644) < 0)
+ return log_debug_errno(errno, "Failed to fchmod %s: %m", dst_tmp);
+
+ if (rename(dst_tmp, "/etc/machine-info") < 0)
+ return log_error_errno(errno, "Failed to replace /etc/machine-info: %m");
+
+ log_info("%s /etc/machine-info with%s%s%s",
+ orig ? "Updated" : "Created",
+ need_install_layout ? " KERNEL_INSTALL_LAYOUT=bls" : "",
+ need_machine_id ? " KERNEL_INSTALL_MACHINE_ID=" : "",
+ need_machine_id ? mid_string : "");
+ return 0;
}
static int help(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- settle_make_machine_id_directory();
+ r = settle_install_machine_id();
+ if (r < 0)
+ return r;
RUN_WITH_UMASK(0002) {
if (install) {
if (r < 0)
return r;
+ r = install_machine_info_config();
+ if (r < 0)
+ return r;
+
r = install_random_seed(arg_esp_path);
if (r < 0)
return r;
if (r < 0)
return r;
- settle_make_machine_id_directory();
+ r = settle_install_machine_id();
+ if (r < 0)
+ return r;
r = remove_binaries(arg_esp_path);