Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct CmdlineOptions {
pub nfsroot: Option<String>,
pub init: String,
pub cleanup: bool,
pub bind_mount: Vec<String>,
}

const SBIN_INIT: &str = "/sbin/init";
Expand All @@ -28,6 +29,7 @@ impl Default for CmdlineOptions {
nfsroot: None,
init: SBIN_INIT.into(),
cleanup: true,
bind_mount: Vec::new(),
}
}
}
Expand All @@ -45,6 +47,9 @@ fn parse_option(key: &str, value: Option<&str>, options: &mut CmdlineOptions) ->
"rw" => options.rootfsflags.remove(MsFlags::MS_RDONLY),
"nfsroot" => options.nfsroot = Some(ensure_value(key, value)?.to_string()),
"init" => options.init = ensure_value(key, value)?.into(),
"rsinit.bind" => options
.bind_mount
.push(ensure_value(key, value)?.to_string()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this will obviously not work like this from a separate crate. What would be a good way in rust to make the parser extendable? I'm looking for something where a custom function would be called for any unknown command-line option.

For the bind-mount case in particular, I think it makes sense to configure the mounts in the initramfs (some kind of config file?) since that's where the directories that are mounted come from anyways.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I had a stab at implementing callbacks at various stages of the rsinit binary, which allows implementing the functionality of this PR e.g. parsing the necessary command line options and running custom commands e.g. after the rootfs was setup. I opened a RFC PR for that #22

_ => (),
}
Ok(())
Expand Down Expand Up @@ -236,4 +241,19 @@ mod tests {

assert_eq!(options, expected);
}

#[test]
fn test_rsinit_bind() {
let cmdline = "root=/dev/root rsinit.bind=/lib/modules rsinit.bind=/usr/lib/modules\n";

let expected = CmdlineOptions {
root: Some("/dev/root".into()),
bind_mount: vec!["/lib/modules".into(), "/usr/lib/modules".into()],
..Default::default()
};

let options = parse_cmdline(cmdline).expect("failed");

assert_eq!(options, expected);
}
}
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ use systemd::{mount_systemd, shutdown};
#[cfg(feature = "usb9pfs")]
use usbg_9pfs::prepare_9pfs_gadget;

use crate::mount::mount_binds;

mod cmdline;
#[cfg(feature = "dmverity")]
mod dmverity;
Expand Down Expand Up @@ -96,6 +98,7 @@ fn start_root(options: &mut CmdlineOptions) -> Result<()> {
unlink(exe.as_path())?;
}

mount_binds(options)?;
mount_move_special(options)?;

chdir("/root")?;
Expand Down
19 changes: 18 additions & 1 deletion src/mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use std::fs::remove_dir;
use std::path::Path;

use log::debug;
use log::{debug, error};
use nix::mount::{mount, MsFlags};

use crate::cmdline::CmdlineOptions;
Expand Down Expand Up @@ -105,3 +105,20 @@ pub fn mount_move_special(options: &CmdlineOptions) -> Result<()> {
mount_move("/proc", "/root/proc", options.cleanup)?;
Ok(())
}

pub fn mount_binds(options: &CmdlineOptions) -> Result<()> {
for src in &options.bind_mount {
if !Path::new(src).exists() {
error!("Can't bind mount {} as it doesn't exist", src);
continue;
}

let dst = format!("/root{src}");

debug!("Bind mounting {src} to {dst}");

do_mount(Some(src), &dst, None, MsFlags::MS_BIND, None)?;
}

Ok(())
}