#![allow(dead_code)]
use std::io::Error as IoError;
use std::ffi::CString;
use std::ptr::null;
use std::path::Path;
use libc::{c_ulong, c_int};
use super::itertools::{NextValue, NextStr, words};
use super::utils::cpath;
static MS_RDONLY: c_ulong = 1;
static MS_NOSUID: c_ulong = 2;
static MS_NODEV: c_ulong = 4;
static MS_NOEXEC: c_ulong = 8;
static MS_SYNCHRONOUS: c_ulong = 16;
static MS_REMOUNT: c_ulong = 32;
static MS_MANDLOCK: c_ulong = 64;
static MS_DIRSYNC: c_ulong = 128;
static MS_NOATIME: c_ulong = 1024;
static MS_NODIRATIME: c_ulong = 2048;
static MS_BIND: c_ulong = 4096;
static MS_MOVE: c_ulong = 8192;
static MS_REC: c_ulong = 16384;
static MS_SILENT: c_ulong = 32768;
static MS_POSIXACL: c_ulong = 1 << 16;
static MS_UNBINDABLE: c_ulong = 1 << 17;
static MS_PRIVATE: c_ulong = 1 << 18;
static MS_SLAVE: c_ulong = 1 << 19;
static MS_SHARED: c_ulong = 1 << 20;
static MS_RELATIME: c_ulong = 1 << 21;
static MS_KERNMOUNT: c_ulong = 1 << 22;
static MS_I_VERSION: c_ulong = 1 << 23;
static MS_STRICTATIME: c_ulong = 1 << 24;
static MS_ACTIVE: c_ulong = 1 << 30;
static MS_NOUSER: c_ulong = 1 << 31;
static MNT_FORCE: c_int = 1;
static MNT_DETACH: c_int = 2;
static MNT_EXPIRE: c_int = 4;
static UMOUNT_NOFOLLOW: c_int = 8;
extern {
fn mount(source: *const i8, target: *const i8,
filesystemtype: *const i8, flags: c_ulong,
data: *const i8) -> c_int;
fn umount(target: *const i8) -> c_int;
fn umount2(target: *const i8, flags: c_int) -> c_int;
}
pub struct MountRecord<'a> {
pub mount_id: usize,
pub parent_id: usize,
_device: &'a str, pub relative_root: &'a str,
pub mount_point: &'a str,
pub mount_options: &'a str,
pub tag_shared: Option<usize>,
pub tag_master: Option<usize>,
pub tag_propagate_from: Option<usize>,
pub tag_unbindable: Option<()>,
pub fstype: &'a str,
pub mount_source: &'a str,
pub super_options: &'a str,
}
impl<'a> MountRecord<'a> {
pub fn from_str<'x>(line: &'x str) -> Result<MountRecord<'x>, ()> {
let mut parts = words(line);
let mount_id = try!(parts.next_value());
let parent_id = try!(parts.next_value());
let device = try!(parts.next_str());
let relative_root = try!(parts.next_str());
let mount_point = try!(parts.next_str());
let mount_options = try!(parts.next_str());
let mut tag_shared = None;
let mut tag_master = None;
let mut tag_propagate_from = None;
let mut tag_unbindable = None;
for name in &mut parts {
if name == "-" { break; }
let mut pair = name.splitn(2, ':');
let key = pair.next();
match key {
Some("shared") => {
tag_shared = Some(try!(pair.next_value()));
}
Some("master") => {
tag_master = Some(try!(pair.next_value()));
}
Some("propagate_from") => {
tag_propagate_from = Some(try!(pair.next_value()));
}
Some("unbindable") => tag_unbindable = Some(()),
_ => {}
}
}
let fstype = try!(parts.next_str());
let mount_source = try!(parts.next_str());
let super_options = try!(parts.next_str());
return Ok(MountRecord {
mount_id: mount_id,
parent_id: parent_id,
_device: device,
relative_root: relative_root,
mount_point: mount_point,
mount_options: mount_options,
tag_shared: tag_shared,
tag_master: tag_master,
tag_propagate_from: tag_propagate_from,
tag_unbindable: tag_unbindable,
fstype: fstype,
mount_source: mount_source,
super_options: super_options,
});
}
pub fn is_private(&self) -> bool {
return self.tag_shared.is_none()
&& self.tag_master.is_none()
&& self.tag_propagate_from.is_none()
&& self.tag_unbindable.is_none();
}
}
pub fn mount_ro_recursive(target: &Path) -> Result<(), String> {
let none = CString::new("none").unwrap();
debug!("Remount readonly: {:?}", target);
let c_target = cpath(target);
let rc = unsafe { mount(
none.as_ptr(),
c_target.as_ptr(),
null(), MS_BIND|MS_REMOUNT|MS_RDONLY, null()) };
if rc != 0 {
let err = IoError::last_os_error();
return Err(format!("Remount readonly {}: {}", target.display(), err));
}
return Ok(());
}
pub fn mount_private(target: &Path) -> Result<(), String> {
let none = CString::new("none").unwrap();
let c_target = cpath(target);
debug!("Making private {:?}", target);
let rc = unsafe { mount(
none.as_ptr(),
c_target.as_ptr(),
null(), MS_REC|MS_PRIVATE, null()) };
if rc == 0 {
return Ok(());
} else {
let err = IoError::last_os_error();
return Err(format!("Can't make {} a slave: {}",
target.display(), err));
}
}
pub fn mount_pseudo(target: &Path, name: &str, options: &str, readonly: bool)
-> Result<(), String>
{
let c_name = CString::new(name).unwrap();
let c_target = cpath(target);
let c_opts = CString::new(options).unwrap();
let mut flags = MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_NOATIME;
if readonly {
flags |= MS_RDONLY;
}
debug!("Pseudofs mount {} {} {}", target.display(), name, options);
let rc = unsafe { mount(
c_name.as_ptr(),
c_target.as_ptr(),
c_name.as_ptr(),
flags,
c_opts.as_ptr()) };
if rc == 0 {
return Ok(());
} else {
let err = IoError::last_os_error();
return Err(format!("Can't mount pseudofs {} ({}, options: {}): {}",
target.display(), options, name, err));
}
}
pub fn mount_pts(target: &Path)
-> Result<(), String>
{
let c_name = CString::new("devpts").unwrap();
let c_target = cpath(target);
let opts = "newinstance,ptmxmode=0666";
let c_opts = CString::new(opts).unwrap();
let flags = MS_NOSUID | MS_NOEXEC | MS_NOATIME;
debug!("Pseudofs mount {} {} {}", target.display(), "devpts", opts);
let rc = unsafe { mount(
c_name.as_ptr(),
c_target.as_ptr(),
c_name.as_ptr(),
flags,
c_opts.as_ptr()) };
if rc == 0 {
return Ok(());
} else {
let err = IoError::last_os_error();
return Err(format!("Can't mount pseudofs {} ({}, options: {}): {}",
target.display(), opts, "devpts", err));
}
}
pub fn unmount(target: &Path) -> Result<(), String> {
let c_target = cpath(target);
let rc = unsafe { umount2(c_target.as_ptr(), MNT_DETACH) };
if rc == 0 {
return Ok(());
} else {
let err = IoError::last_os_error();
return Err(format!("Can't unmount {} : {}", target.display(), err));
}
}