diff --git a/src/agent/src/mount.rs b/src/agent/src/mount.rs index 5b0d95c19c..b3cf101709 100644 --- a/src/agent/src/mount.rs +++ b/src/agent/src/mount.rs @@ -145,6 +145,11 @@ pub const STORAGE_HANDLER_LIST: &[&str] = &[ DRIVER_WATCHABLE_BIND_TYPE, ]; +#[instrument] +pub fn get_mounts() -> Result { + fs::read_to_string("/proc/mounts") +} + #[instrument] pub fn baremount( source: &Path, @@ -168,6 +173,31 @@ pub fn baremount( return Err(anyhow!("need mount FS type")); } + let destination_str = destination.to_string_lossy(); + let mounts = get_mounts().unwrap_or_else(|_| String::new()); + let already_mounted = mounts + .lines() + .map(|line| line.split_whitespace().collect::>()) + .filter(|parts| parts.len() >= 3) // ensure we have at least [source}, destination, and fs_type + .any(|parts| { + // Check if source, destination and fs_type match any entry in /proc/mounts + // minimal check is for destination an fstype since source can have different names like: + // udev /dev devtmpfs + // dev /dev devtmpfs + // depending on which entity is mounting the dev/fs/pseudo-fs + parts[1] == destination_str && parts[2] == fs_type + }); + + if already_mounted { + slog_info!( + logger, + "{:?} is already mounted at {:?}", + source, + destination + ); + return Ok(()); + } + info!( logger, "baremount source={:?}, dest={:?}, fs_type={:?}, options={:?}, flags={:?}", @@ -1112,6 +1142,42 @@ mod tests { skip_if_not_root, skip_loop_by_user, skip_loop_if_not_root, skip_loop_if_root, }; + // Shadow get_mounts during tests since this is only used in the test + // context, compiler will warn about dead-code. + #[allow(dead_code)] + fn get_mounts() -> Result { + Ok(String::from( + " + rootfs / rootfs rw,size=1694984k,nr_inodes=423746 0 0 + proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 + sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 + dev /dev devtmpfs rw,nosuid,relatime,size=1695000k,nr_inodes=423750,mode=755 0 0 + run /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0 + ", + )) + } + + #[test] + fn test_already_baremounted() { + let drain = slog::Discard; + let logger = slog::Logger::root(drain, o!()); + let test_cases = [ + ("dev", "/dev", "devtmpfs"), + ("udev", "/dev", "devtmpfs"), + ("proc", "/proc", "proc"), + ("sysfs", "/sys", "sysfs"), + ]; + + for &(source, destination, fs_type) in &test_cases { + let source = Path::new(source); + let destination = Path::new(destination); + let flags = MsFlags::MS_RDONLY; + let options = "mode=755"; + println!("baremount({:?} {:?} {:?}", source, destination, fs_type); + assert!(baremount(source, destination, fs_type, flags, options, &logger).is_ok()); + } + } + #[test] fn test_mount() { #[derive(Debug)]