use anyhow::Result;
use arcbox_constants::virtiofs::{
MOUNT_ARCBOX, MOUNT_PRIVATE, MOUNT_USERS, TAG_ARCBOX, TAG_PRIVATE, TAG_USERS,
};
#[cfg(target_os = "linux")]
pub fn mount_fs(source: &str, target: &str, fstype: &str, options: &[String]) -> Result<()> {
use nix::mount::{MsFlags, mount};
use std::path::Path;
tracing::info!("Mounting {} on {} (type: {})", source, target, fstype);
std::fs::create_dir_all(target)?;
let data: Option<String> = if options.is_empty() {
None
} else {
Some(options.join(","))
};
mount(
Some(source),
Path::new(target),
Some(fstype),
MsFlags::empty(),
data.as_deref(),
)?;
Ok(())
}
#[cfg(not(target_os = "linux"))]
pub fn mount_fs(source: &str, target: &str, fstype: &str, _options: &[String]) -> Result<()> {
tracing::warn!(
"mount_fs is only supported on Linux (called with source={}, target={}, fstype={})",
source,
target,
fstype
);
anyhow::bail!("mount_fs is only supported on Linux")
}
#[cfg(target_os = "linux")]
pub fn unmount_fs(target: &str) -> Result<()> {
tracing::info!("Unmounting {}", target);
nix::mount::umount(target)?;
Ok(())
}
#[cfg(not(target_os = "linux"))]
pub fn unmount_fs(target: &str) -> Result<()> {
tracing::warn!("unmount_fs is only supported on Linux (target={})", target);
anyhow::bail!("unmount_fs is only supported on Linux")
}
pub fn mount_virtiofs(tag: &str, mountpoint: &str) -> Result<()> {
mount_fs(tag, mountpoint, "virtiofs", &[])
}
pub fn mount_virtiofs_cached(tag: &str, mountpoint: &str) -> Result<()> {
mount_fs(tag, mountpoint, "virtiofs", &["dax=always".to_string()])
}
#[cfg(target_os = "linux")]
pub fn is_mounted(path: &str) -> bool {
use std::fs;
if let Ok(content) = fs::read_to_string("/proc/mounts") {
content.lines().any(|line| {
let parts: Vec<&str> = line.split_whitespace().collect();
parts.get(1).is_some_and(|&p| p == path)
})
} else {
false
}
}
#[cfg(not(target_os = "linux"))]
pub fn is_mounted(_path: &str) -> bool {
false
}
pub fn mount_standard_shares() {
if is_mounted(MOUNT_ARCBOX) {
remount_with_cache(MOUNT_ARCBOX);
} else if let Err(e) = mount_virtiofs_cached(TAG_ARCBOX, MOUNT_ARCBOX) {
tracing::warn!("Failed to mount arcbox share: {}", e);
} else {
tracing::info!("Mounted arcbox share at {} (dax=always)", MOUNT_ARCBOX);
}
if !is_mounted(MOUNT_PRIVATE) {
if let Err(e) = mount_virtiofs(TAG_PRIVATE, MOUNT_PRIVATE) {
tracing::debug!("Private share not available: {}", e);
} else {
tracing::info!("Mounted private share at {}", MOUNT_PRIVATE);
}
}
if !is_mounted(MOUNT_USERS) {
if let Err(e) = mount_virtiofs(TAG_USERS, MOUNT_USERS) {
tracing::debug!("Users share not available: {}", e);
} else {
tracing::info!("Mounted users share at {}", MOUNT_USERS);
}
}
}
#[cfg(target_os = "linux")]
fn remount_with_cache(mountpoint: &str) {
use nix::mount::{MsFlags, mount};
use std::path::Path;
match mount(
None::<&str>,
Path::new(mountpoint),
None::<&str>,
MsFlags::MS_REMOUNT,
Some("dax=always"),
) {
Ok(()) => {
tracing::info!(mountpoint, "remounted with dax=always");
}
Err(e) => {
tracing::debug!(mountpoint, error = %e, "remount with dax=always failed (non-fatal)");
}
}
}
#[cfg(not(target_os = "linux"))]
fn remount_with_cache(_mountpoint: &str) {}