sys-util: support more mount flags in parse_mount_options()

Support more mount flags in parse_mount_options().

Signed-off-by: Jiang Liu <gerry@linux.alibaba.com>
This commit is contained in:
Jiang Liu 2023-08-07 10:26:12 +08:00
parent c00d8f3d48
commit 8392c71bf2
3 changed files with 40 additions and 128 deletions

View File

@ -15,7 +15,7 @@ use std::str::FromStr;
use std::sync::Arc;
use anyhow::{anyhow, Context, Result};
use kata_sys_util::mount::{create_mount_destination, get_linux_mount_info};
use kata_sys_util::mount::{create_mount_destination, get_linux_mount_info, parse_mount_options};
use kata_types::mount::{KATA_MOUNT_OPTION_FS_GID, KATA_SHAREDFS_GUEST_PREMOUNT_TAG};
use nix::mount::MsFlags;
use nix::unistd::{Gid, Uid};
@ -49,47 +49,6 @@ const RO_MASK: u32 = 0o440;
const EXEC_MASK: u32 = 0o110;
const MODE_SETGID: u32 = 0o2000;
#[rustfmt::skip]
lazy_static! {
pub static ref FLAGS: HashMap<&'static str, (bool, MsFlags)> = {
let mut m = HashMap::new();
m.insert("defaults", (false, MsFlags::empty()));
m.insert("ro", (false, MsFlags::MS_RDONLY));
m.insert("rw", (true, MsFlags::MS_RDONLY));
m.insert("suid", (true, MsFlags::MS_NOSUID));
m.insert("nosuid", (false, MsFlags::MS_NOSUID));
m.insert("dev", (true, MsFlags::MS_NODEV));
m.insert("nodev", (false, MsFlags::MS_NODEV));
m.insert("exec", (true, MsFlags::MS_NOEXEC));
m.insert("noexec", (false, MsFlags::MS_NOEXEC));
m.insert("sync", (false, MsFlags::MS_SYNCHRONOUS));
m.insert("async", (true, MsFlags::MS_SYNCHRONOUS));
m.insert("dirsync", (false, MsFlags::MS_DIRSYNC));
m.insert("remount", (false, MsFlags::MS_REMOUNT));
m.insert("mand", (false, MsFlags::MS_MANDLOCK));
m.insert("nomand", (true, MsFlags::MS_MANDLOCK));
m.insert("atime", (true, MsFlags::MS_NOATIME));
m.insert("noatime", (false, MsFlags::MS_NOATIME));
m.insert("diratime", (true, MsFlags::MS_NODIRATIME));
m.insert("nodiratime", (false, MsFlags::MS_NODIRATIME));
m.insert("bind", (false, MsFlags::MS_BIND));
m.insert("rbind", (false, MsFlags::MS_BIND | MsFlags::MS_REC));
m.insert("unbindable", (false, MsFlags::MS_UNBINDABLE));
m.insert("runbindable", (false, MsFlags::MS_UNBINDABLE | MsFlags::MS_REC));
m.insert("private", (false, MsFlags::MS_PRIVATE));
m.insert("rprivate", (false, MsFlags::MS_PRIVATE | MsFlags::MS_REC));
m.insert("shared", (false, MsFlags::MS_SHARED));
m.insert("rshared", (false, MsFlags::MS_SHARED | MsFlags::MS_REC));
m.insert("slave", (false, MsFlags::MS_SLAVE));
m.insert("rslave", (false, MsFlags::MS_SLAVE | MsFlags::MS_REC));
m.insert("relatime", (false, MsFlags::MS_RELATIME));
m.insert("norelatime", (true, MsFlags::MS_RELATIME));
m.insert("strictatime", (false, MsFlags::MS_STRICTATIME));
m.insert("nostrictatime", (true, MsFlags::MS_STRICTATIME));
m
};
}
#[derive(Debug, PartialEq)]
pub struct InitMount<'a> {
fstype: &'a str,
@ -168,16 +127,12 @@ pub fn baremount(
}
let destination_str = destination.to_string_lossy();
let mut already_mounted = false;
if let Ok(m) = get_linux_mount_info(destination_str.deref()) {
if m.fs_type == fs_type {
already_mounted = true;
slog_info!(logger, "{source:?} is already mounted at {destination:?}");
return Ok(());
}
}
if already_mounted {
slog_info!(logger, "{source:?} is already mounted at {destination:?}");
return Ok(());
}
info!(
logger,
@ -275,11 +230,12 @@ pub async fn update_ephemeral_mounts(
// assume that fsGid has already been set
let mount_path = Path::new(&storage.mount_point);
let src_path = Path::new(&storage.source);
let opts = storage
let opts: Vec<&String> = storage
.options
.iter()
.filter(|&opt| !opt.starts_with(FS_GID_EQ));
let (flags, options) = parse_mount_flags_and_options(opts);
.filter(|&opt| !opt.starts_with(FS_GID_EQ))
.collect();
let (flags, options) = parse_mount_options(&opts)?;
info!(logger, "mounting storage";
"mount-source" => src_path.display(),
@ -646,7 +602,7 @@ fn mount_storage(logger: &Logger, storage: &Storage) -> Result<()> {
return Ok(());
}
let (flags, options) = parse_mount_flags_and_options(&storage.options);
let (flags, options) = parse_mount_options(&storage.options)?;
let mount_path = Path::new(&storage.mount_point);
let src_path = Path::new(&storage.source);
create_mount_destination(src_path, mount_path, "", &storage.fstype)
@ -765,42 +721,6 @@ pub fn is_mounted(mount_point: &str) -> Result<bool> {
Ok(found)
}
#[instrument]
fn parse_mount_flags_and_options(
opts_iter: impl Iterator<Item = impl AsRef<str>> + Debug,
) -> (MsFlags, String) {
let mut flags = MsFlags::empty();
let mut options: String = "".to_string();
for opt in opts_iter {
let opt = opt.as_ref();
if !opt.is_empty() {
match FLAGS.get(opt) {
Some(x) => {
let (clear, f) = *x;
if clear {
flags &= !f;
} else {
flags |= f;
}
}
None => {
if opt.starts_with("io.katacontainers.") {
continue;
}
if !options.is_empty() {
options.push_str(format!(",{}", opt).as_str());
} else {
options.push_str(opt);
}
}
};
}
}
(flags, options)
}
// add_storages takes a list of storages passed by the caller, and perform the
// associated operations such as waiting for the device to show up, and mount
// it to a specific location, according to the type of handler chosen, and for
@ -878,27 +798,23 @@ pub async fn add_storages(
#[instrument]
fn mount_to_rootfs(logger: &Logger, m: &InitMount) -> Result<()> {
let (flags, options) = parse_mount_flags_and_options(m.options.iter());
fs::create_dir_all(m.dest).context("could not create directory")?;
let (flags, options) = parse_mount_options(&m.options)?;
let source = Path::new(m.src);
let dest = Path::new(m.dest);
baremount(source, dest, m.fstype, flags, &options, logger).or_else(|e| {
if m.src != "dev" {
return Err(e);
if m.src == "dev" {
error!(
logger,
"Could not mount filesystem from {} to {}", m.src, m.dest
);
Ok(())
} else {
Err(e)
}
error!(
logger,
"Could not mount filesystem from {} to {}", m.src, m.dest
);
Ok(())
})?;
Ok(())
})
}
#[instrument]
@ -932,13 +848,10 @@ pub fn get_mount_fs_type_from_file(mount_file: &str, mount_point: &str) -> Resul
// Read the file line by line using the lines() iterator from std::io::BufRead.
for (_index, line) in content.lines().enumerate() {
let capes = match re.captures(line) {
Some(c) => c,
None => continue,
};
if capes.len() > 1 {
return Ok(capes[1].to_string());
if let Some(capes) = re.captures(line) {
if capes.len() > 1 {
return Ok(capes[1].to_string());
}
}
}
@ -1971,7 +1884,7 @@ mod tests {
for (i, d) in tests.iter().enumerate() {
let msg = format!("test[{}]: {:?}", i, d);
let result = parse_mount_flags_and_options(d.options_vec.iter());
let result = parse_mount_options(&d.options_vec)?;
let msg = format!("{}: result: {:?}", msg, result);

View File

@ -7,14 +7,14 @@ use anyhow::{anyhow, Result};
use nix::mount::MsFlags;
use nix::sched::{unshare, CloneFlags};
use nix::unistd::{getpid, gettid};
use slog::Logger;
use std::fmt;
use std::fs;
use std::fs::File;
use std::path::{Path, PathBuf};
use tracing::instrument;
use crate::mount::{baremount, FLAGS};
use slog::Logger;
use crate::mount::baremount;
const PERSISTENT_NS_DIR: &str = "/var/run/sandbox-ns";
pub const NSTYPEIPC: &str = "ipc";
@ -116,15 +116,7 @@ impl Namespace {
// Bind mount the new namespace from the current thread onto the mount point to persist it.
let mut flags = MsFlags::empty();
if let Some(x) = FLAGS.get("rbind") {
let (clear, f) = *x;
if clear {
flags &= !f;
} else {
flags |= f;
}
};
flags |= MsFlags::MS_BIND | MsFlags::MS_REC;
baremount(source, destination, "none", flags, "", &logger).map_err(|e| {
anyhow!(

View File

@ -390,19 +390,17 @@ fn do_rebind_mount<P: AsRef<Path>>(path: P, readonly: bool, flags: MsFlags) -> R
}
/// Take fstab style mount options and parses them for use with a standard mount() syscall.
fn parse_mount_options(options: &[String]) -> Result<(MsFlags, String)> {
pub fn parse_mount_options<T: AsRef<str>>(options: &[T]) -> Result<(MsFlags, String)> {
let mut flags: MsFlags = MsFlags::empty();
let mut data: Vec<String> = Vec::new();
for opt in options.iter() {
if opt == "defaults" {
continue;
} else if opt == "loop" {
if opt.as_ref() == "loop" {
return Err(Error::InvalidMountOption("loop".to_string()));
} else if let Some(v) = parse_mount_flags(flags, opt) {
} else if let Some(v) = parse_mount_flags(flags, opt.as_ref()) {
flags = v;
} else {
data.push(opt.clone());
data.push(opt.as_ref().to_string());
}
}
@ -441,6 +439,7 @@ fn parse_mount_flags(mut flags: MsFlags, flag_str: &str) -> Option<MsFlags> {
// overridden by subsequent options, as in the option line users,exec,dev,suid).
match flag_str {
// Clear flags
"defaults" => {}
"async" => flags &= !MsFlags::MS_SYNCHRONOUS,
"atime" => flags &= !MsFlags::MS_NOATIME,
"dev" => flags &= !MsFlags::MS_NODEV,
@ -464,6 +463,14 @@ fn parse_mount_flags(mut flags: MsFlags, flag_str: &str) -> Option<MsFlags> {
"noexec" => flags |= MsFlags::MS_NOEXEC,
"nosuid" => flags |= MsFlags::MS_NOSUID,
"rbind" => flags |= MsFlags::MS_BIND | MsFlags::MS_REC,
"unbindable" => flags |= MsFlags::MS_UNBINDABLE,
"runbindable" => flags |= MsFlags::MS_UNBINDABLE | MsFlags::MS_REC,
"private" => flags |= MsFlags::MS_PRIVATE,
"rprivate" => flags |= MsFlags::MS_PRIVATE | MsFlags::MS_REC,
"shared" => flags |= MsFlags::MS_SHARED,
"rshared" => flags |= MsFlags::MS_SHARED | MsFlags::MS_REC,
"slave" => flags |= MsFlags::MS_SLAVE,
"rslave" => flags |= MsFlags::MS_SLAVE | MsFlags::MS_REC,
"relatime" => flags |= MsFlags::MS_RELATIME,
"remount" => flags |= MsFlags::MS_REMOUNT,
"ro" => flags |= MsFlags::MS_RDONLY,
@ -1030,7 +1037,7 @@ mod tests {
#[test]
fn test_parse_mount_options() {
let options = vec![];
let options: Vec<&str> = vec![];
let (flags, data) = parse_mount_options(&options).unwrap();
assert!(flags.is_empty());
assert!(data.is_empty());