Repository: bottlerocket-os/bottlerocket
File: sources/api/prairiedog/src/bootconfig.rs (Rust)

Code before:
        None => {
            // If we don't have any boot settings, write out an initrd with default boot config contents
            trace!("Serializing boot config string: {}", DEFAULT_BOOTCONFIG_STR);
            DEFAULT_BOOTCONFIG_STR.to_string().into_bytes()
        }
    };
    let initrd = generate_initrd(&bootconfig_bytes)?;
    trace!("Writing initrd image file: {:?}", initrd);
    fs::write(BOOTCONFIG_INITRD_PATH, &initrd).context(error::WriteInitrdSnafu)?;
    Ok(())
}

/// Retrieves boot config related Bottlerocket settings. If they don't exist in the settings model,
/// we return `None` instead.
fn get_boot_config_settings<P>(config_path: P) -> Result<Option<BootSettings>>
where
    P: AsRef<Path>,
{
    let config_path = config_path.as_ref();
    if !config_path.try_exists().context(error::ReadFileSnafu {
        path: config_path.to_path_buf(),
    })? {
        return Ok(None);
    }
    let config_str = fs::read_to_string(config_path).context(error::ReadFileSnafu {
        path: config_path.to_path_buf(),
    })?;
    toml::from_str(config_str.as_str()).context(error::InputTomlSnafu)
}

/// Reads `/proc/bootconfig`. Not having any boot config is ignored.
fn read_proc_bootconfig() -> Result<Option<String>> {
    match fs::read_to_string(PROC_BOOTCONFIG) {
        Ok(s) => Ok(Some(s)),
        Err(e) => {
            // If there's no `/proc/bootconfig`, then the user hasn't provisioned any kernel boot configuration.
            if e.kind() == io::ErrorKind::NotFound {
                Ok(None)
            } else {
                Err(e).context(error::ReadFileSnafu {
                    path: PROC_BOOTCONFIG,
                })
            }
        }
    }
}

/// Reads `/proc/bootconfig` and populates the Bottlerocket boot settings based on the existing boot config data
pub(crate) fn generate_boot_settings() -> Result<()> {
    if let Some(proc_bootconfig) = read_proc_bootconfig()? {
        debug!(

Review comment (bug):
Commit message could be reworded, it's a bit hard to parse right now.

There's a TOCTOU issue here where `fs::read_to_string` could fail if the file is removed before it runs and after the `try_exists` check. To avoid this, and the redundant check, it might be better not to use `fs::read_to_string` at all.

Code after:
        }
        None => {
            // If we don't have any boot settings, write out an initrd with default boot config contents
            trace!("Serializing boot config string: {}", DEFAULT_BOOTCONFIG_STR);
            DEFAULT_BOOTCONFIG_STR.to_string().into_bytes()
        }
    };
    let initrd = generate_initrd(&bootconfig_bytes)?;
    trace!("Writing initrd image file: {:?}", initrd);
    fs::write(BOOTCONFIG_INITRD_PATH, &initrd).context(error::WriteInitrdSnafu)?;
    Ok(())
}

/// Retrieves boot config related Bottlerocket settings. If they don't exist in the settings model,
/// we return `None` instead.
fn get_boot_config_settings<P>(config_path: P) -> Result<Option<BootSettings>>
where
    P: AsRef<Path>,
{
    let config_path = config_path.as_ref();
    match fs::read_to_string(config_path) {
        Ok(config_str) => toml::from_str(config_str.as_str()).context(error::InputTomlSnafu),
        Err(e) => {
            if e.kind() == ErrorKind::NotFound {
                Ok(None)
            } else {
                Err(error::Error::ReadFile {
                    source: e,
                    path: config_path.to_path_buf(),
                })
            }
        }
    }
}

/// Reads `/proc/bootconfig`. Not having any boot config is ignored.
fn read_proc_bootconfig() -> Result<Option<String>> {
    match fs::read_to_string(PROC_BOOTCONFIG) {
        Ok(s) => Ok(Some(s)),
        Err(e) => {
            // If there's no `/proc/bootconfig`, then the user hasn't provisioned any kernel boot configuration.
            if e.kind() == io::ErrorKind::NotFound {
                Ok(None)
            } else {
                Err(e).context(error::ReadFileSnafu {
                    path: PROC_BOOTCONFIG,
                })
            }
        }
    }
}