core: keep machine-id transient until first boot completes
Currently, a loss of power after the machine-id was written but before all units with ConditionFirstBoot=yes ran would lead to the next boot finding a valid machine-id, thus not being marked first boot and not re-running these units. To make the first boot mechanism more robust, instead of writing /etc/machine-id very early, fill it with a marker value "uninitialized" and overmount it with a transiently provisioned machine-id. Then, after the first boots completes (when systemd-machine-id-commit.service runs), write the real machine-id to disk. This mechanism is of course only invoked on first boot. If a first boot is not detected, the machine-id is handled as previously. Fixes: #4511
This commit is contained in:
parent
ab763cb2be
commit
3023f2fead
|
@ -11,6 +11,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
|
#include "io-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "machine-id-setup.h"
|
#include "machine-id-setup.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
@ -86,7 +87,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
|
int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_id, sd_id128_t *ret) {
|
||||||
const char *etc_machine_id, *run_machine_id;
|
const char *etc_machine_id, *run_machine_id;
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
bool writable;
|
bool writable;
|
||||||
|
@ -143,13 +144,31 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
|
||||||
if (ftruncate(fd, 0) < 0)
|
if (ftruncate(fd, 0) < 0)
|
||||||
return log_error_errno(errno, "Failed to truncate %s: %m", etc_machine_id);
|
return log_error_errno(errno, "Failed to truncate %s: %m", etc_machine_id);
|
||||||
|
|
||||||
if (id128_write_fd(fd, ID128_PLAIN, machine_id, true) >= 0)
|
/* If the caller requested a transient machine-id, write the string "uninitialized\n" to
|
||||||
goto finish;
|
* disk and overmount it with a transient file.
|
||||||
|
*
|
||||||
|
* Otherwise write the machine-id directly to disk. */
|
||||||
|
if (force_transient) {
|
||||||
|
r = loop_write(fd, "uninitialized\n", strlen("uninitialized\n"), false);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to write uninitialized %s: %m", etc_machine_id);
|
||||||
|
|
||||||
|
r = fsync_full(fd);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to sync %s: %m", etc_machine_id);
|
||||||
|
} else {
|
||||||
|
r = id128_write_fd(fd, ID128_PLAIN, machine_id, true);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to write %s: %m", etc_machine_id);
|
||||||
|
else
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = safe_close(fd);
|
fd = safe_close(fd);
|
||||||
|
|
||||||
/* Hmm, we couldn't write it? So let's write it to /run/machine-id as a replacement */
|
/* Hmm, we couldn't or shouldn't write the machine-id to /etc?
|
||||||
|
* So let's write it to /run/machine-id as a replacement */
|
||||||
|
|
||||||
run_machine_id = prefix_roota(root, "/run/machine-id");
|
run_machine_id = prefix_roota(root, "/run/machine-id");
|
||||||
|
|
||||||
|
@ -167,7 +186,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("Installed transient %s file.", etc_machine_id);
|
log_full(force_transient ? LOG_DEBUG : LOG_INFO, "Installed transient %s file.", etc_machine_id);
|
||||||
|
|
||||||
/* Mark the mount read-only */
|
/* Mark the mount read-only */
|
||||||
r = mount_follow_verbose(LOG_WARNING, NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
|
r = mount_follow_verbose(LOG_WARNING, NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
int machine_id_commit(const char *root);
|
int machine_id_commit(const char *root);
|
||||||
int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret);
|
int machine_id_setup(const char *root, bool force_transient, sd_id128_t requested, sd_id128_t *ret);
|
||||||
|
|
|
@ -2037,6 +2037,7 @@ static void log_execution_mode(bool *ret_first_boot) {
|
||||||
|
|
||||||
static int initialize_runtime(
|
static int initialize_runtime(
|
||||||
bool skip_setup,
|
bool skip_setup,
|
||||||
|
bool first_boot,
|
||||||
struct rlimit *saved_rlimit_nofile,
|
struct rlimit *saved_rlimit_nofile,
|
||||||
struct rlimit *saved_rlimit_memlock,
|
struct rlimit *saved_rlimit_memlock,
|
||||||
const char **ret_error_message) {
|
const char **ret_error_message) {
|
||||||
|
@ -2070,7 +2071,8 @@ static int initialize_runtime(
|
||||||
|
|
||||||
status_welcome();
|
status_welcome();
|
||||||
hostname_setup();
|
hostname_setup();
|
||||||
machine_id_setup(NULL, arg_machine_id, NULL);
|
/* Force transient machine-id on first boot. */
|
||||||
|
machine_id_setup(NULL, first_boot, arg_machine_id, NULL);
|
||||||
(void) loopback_setup();
|
(void) loopback_setup();
|
||||||
bump_unix_max_dgram_qlen();
|
bump_unix_max_dgram_qlen();
|
||||||
bump_file_max_and_nr_open();
|
bump_file_max_and_nr_open();
|
||||||
|
@ -2798,6 +2800,7 @@ int main(int argc, char *argv[]) {
|
||||||
log_execution_mode(&first_boot);
|
log_execution_mode(&first_boot);
|
||||||
|
|
||||||
r = initialize_runtime(skip_setup,
|
r = initialize_runtime(skip_setup,
|
||||||
|
first_boot,
|
||||||
&saved_rlimit_nofile,
|
&saved_rlimit_nofile,
|
||||||
&saved_rlimit_memlock,
|
&saved_rlimit_memlock,
|
||||||
&error_message);
|
&error_message);
|
||||||
|
|
|
@ -128,7 +128,7 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read machine ID back: %m");
|
return log_error_errno(r, "Failed to read machine ID back: %m");
|
||||||
} else {
|
} else {
|
||||||
r = machine_id_setup(arg_root, SD_ID128_NULL, &id);
|
r = machine_id_setup(arg_root, false, SD_ID128_NULL, &id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue