nixos/make-initrd-ng: Pass contents as JSON

This commit is contained in:
Will Fancher 2024-06-26 20:22:42 -04:00
parent 2328731ad0
commit e6c544270c
7 changed files with 112 additions and 49 deletions

View File

@ -45,12 +45,35 @@ let
inherit (lib.types)
attrsOf
coercedTo
lines
listOf
nullOr
oneOf
package
path
submodule
;
initrdStorePathModule = { config, ... }: {
options = {
enable = (mkEnableOption "copying of this file and symlinking it") // { default = true; };
target = mkOption {
type = nullOr path;
description = ''
Path of the symlink.
'';
default = null;
};
source = mkOption {
type = path;
description = "Path of the source file.";
};
};
};
in
{
@ -86,31 +109,23 @@ in
automounts = listOf (submodule [ stage2AutomountOptions unitConfig automountConfig ]);
initrdAutomounts = attrsOf (submodule [ stage1AutomountOptions unitConfig automountConfig ]);
initrdStorePath = listOf (coercedTo
(oneOf [ singleLineStr package ])
(source: { inherit source; })
(submodule initrdStorePathModule));
initrdContents = attrsOf (submodule ({ config, options, name, ... }: {
imports = [ initrdStorePathModule ];
options = {
enable = (mkEnableOption "copying of this file and symlinking it") // { default = true; };
target = mkOption {
type = path;
description = ''
Path of the symlink.
'';
default = name;
};
text = mkOption {
default = null;
type = nullOr lines;
description = "Text of the file.";
};
source = mkOption {
type = path;
description = "Path of the source file.";
};
};
config = {
target = mkDefault name;
source = mkIf (config.text != null) (
let name' = "initrd-" + baseNameOf name;
in mkDerivedConfig options.text (pkgs.writeText name')

View File

@ -112,8 +112,7 @@ let
inherit (config.boot.initrd) compressor compressorArgs prepend;
inherit (cfg) strip;
contents = map (path: { object = path; symlink = ""; }) (subtractLists cfg.suppressedStorePaths cfg.storePaths)
++ mapAttrsToList (_: v: { object = v.source; symlink = v.target; }) (filterAttrs (_: v: v.enable) cfg.contents);
contents = lib.filter ({ source, ... }: !lib.elem source cfg.suppressedStorePaths) cfg.storePaths;
};
in {
@ -172,7 +171,7 @@ in {
description = ''
Store paths to copy into the initrd as well.
'';
type = with types; listOf (oneOf [ singleLineStr package ]);
type = utils.systemdUtils.types.initrdStorePath;
default = [];
};
@ -491,7 +490,8 @@ in {
"${pkgs.libfido2}/lib/libfido2.so.1"
] ++ optionals cfg.package.withKmod [
"${pkgs.kmod.lib}/lib/libkmod.so.2"
] ++ jobScripts;
] ++ jobScripts
++ map (c: builtins.removeAttrs c ["text"]) (builtins.attrValues cfg.contents);
targets.initrd.aliases = ["default.target"];
units =

View File

@ -2,10 +2,7 @@
cfg = config.systemd.shutdownRamfs;
ramfsContents = let
storePaths = map (p: "${p}\n") cfg.storePaths;
contents = lib.mapAttrsToList (_: v: "${v.source}\n${v.target}") (lib.filterAttrs (_: v: v.enable) cfg.contents);
in pkgs.writeText "shutdown-ramfs-contents" (lib.concatStringsSep "\n" (storePaths ++ contents));
ramfsContents = pkgs.writeText "shutdown-ramfs-contents.json" (builtins.toJSON cfg.storePaths);
in {
options.systemd.shutdownRamfs = {
@ -24,7 +21,7 @@ in {
description = ''
Store paths to copy into the shutdown ramfs as well.
'';
type = lib.types.listOf lib.types.singleLineStr;
type = utils.systemdUtils.types.initrdStorePath;
default = [];
};
};
@ -35,7 +32,8 @@ in {
"/etc/initrd-release".source = config.environment.etc.os-release.source;
"/etc/os-release".source = config.environment.etc.os-release.source;
};
systemd.shutdownRamfs.storePaths = [pkgs.runtimeShell "${pkgs.coreutils}/bin"];
systemd.shutdownRamfs.storePaths = [pkgs.runtimeShell "${pkgs.coreutils}/bin"]
++ map (c: builtins.removeAttrs c ["text"]) (builtins.attrValues cfg.contents);
systemd.mounts = [{
what = "tmpfs";

View File

@ -72,7 +72,7 @@ in
${if makeUInitrd then "uInitrdCompression" else null} = uInitrdCompression;
passAsFile = ["contents"];
contents = lib.concatMapStringsSep "\n" ({ object, symlink, ... }: "${object}\n${lib.optionalString (symlink != null) symlink}") contents + "\n";
contents = builtins.toJSON contents;
nativeBuildInputs = [makeInitrdNGTool libarchive] ++ lib.optional makeUInitrd ubootTools ++ lib.optional strip binutils;

View File

@ -30,10 +30,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "log"
version = "0.4.20"
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "make-initrd-ng"
@ -41,6 +47,8 @@ version = "0.1.0"
dependencies = [
"eyre",
"goblin",
"serde",
"serde_json",
]
[[package]]
@ -57,22 +65,28 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "proc-macro2"
version = "1.0.78"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "scroll"
version = "0.11.0"
@ -94,10 +108,41 @@ dependencies = [
]
[[package]]
name = "syn"
version = "2.0.48"
name = "serde"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
dependencies = [
"proc-macro2",
"quote",

View File

@ -9,3 +9,5 @@ edition = "2018"
[dependencies]
eyre = "0.6.8"
goblin = "0.5.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

@ -3,7 +3,6 @@ use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::hash::Hash;
use std::io::{BufRead, BufReader};
use std::iter::FromIterator;
use std::os::unix;
use std::path::{Component, Path, PathBuf};
@ -11,6 +10,13 @@ use std::process::Command;
use eyre::Context;
use goblin::{elf::Elf, Object};
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct StoreInput {
source: String,
target: Option<String>,
}
struct NonRepeatingQueue<T> {
queue: VecDeque<T>,
@ -231,26 +237,23 @@ fn handle_path(
fn main() -> eyre::Result<()> {
let args: Vec<String> = env::args().collect();
let input =
fs::File::open(&args[1]).wrap_err_with(|| format!("failed to open file {:?}", &args[1]))?;
let contents =
fs::read(&args[1]).wrap_err_with(|| format!("failed to open file {:?}", &args[1]))?;
let input = serde_json::from_slice::<Vec<StoreInput>>(&contents)
.wrap_err_with(|| format!("failed to parse JSON in {:?}", &args[1]))?;
let output = &args[2];
let out_path = Path::new(output);
let mut queue = NonRepeatingQueue::<Box<Path>>::new();
let mut lines = BufReader::new(input).lines();
while let Some(obj) = lines.next() {
// Lines should always come in pairs
let obj = obj?;
let sym = lines.next().unwrap()?;
let obj_path = Path::new(&obj);
for sp in input {
let obj_path = Path::new(&sp.source);
queue.push_back(Box::from(obj_path));
if !sym.is_empty() {
println!("{} -> {}", &sym, &obj);
if let Some(target) = sp.target {
println!("{} -> {}", &target, &sp.source);
// We don't care about preserving symlink structure here
// nearly as much as for the actual objects.
let link_string = format!("{}/{}", output, sym);
let link_string = format!("{}/{}", output, target);
let link_path = Path::new(&link_string);
let mut link_parent = link_path.to_path_buf();
link_parent.pop();