1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// This file is part of dpdk. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/dpdk/master/COPYRIGHT. No part of dpdk, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
// Copyright © 2016-2017 The developers of dpdk. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/dpdk/master/COPYRIGHT.


#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Mounts(*mut FILE, bool);

impl Drop for Mounts
{
	#[inline(always)]
	fn drop(&mut self)
	{
		match unsafe { endmntent(self.0) }
		{
			1 => (),
			illegal @ _ => panic!("endmntent() returned '{}'; it should never return anything other than 1", illegal),
		}
	}
}

impl Mounts
{
	const_cstr!
	{
		ReadOnlyFlag = "r";
		ReadWriteFlag = "ra";
	}
	
	// Ought to be a constant: &Path, but Rust makes this nearly impossible
	#[inline(always)]
	pub fn ProcSelfMounts() -> PathBuf
	{
		PathBuf::from("/proc/self/mounts")
	}
	
	#[inline(always)]
	pub fn ProcMounts() -> PathBuf
	{
		PathBuf::from("/proc/mounts")
	}
	
	#[inline(always)]
	pub fn readOnly(&self) -> bool
	{
		self.1
	}
		
	pub fn parse(procPath: &Path) -> Result<HashMap<PathBuf, Mount>, io::Error>
	{
		let mut mountsFilePath = PathBuf::from(procPath);
		mountsFilePath.push("self/mounts");
		let mounts = try!(Self::new(&mountsFilePath, true));
		
		let mut map = HashMap::with_capacity(64);
		
		try!(mounts.useMounts(|mount|
		{
			let key = mount.mountPoint.clone();
			if let Some(previous) = map.insert(key, mount)
			{
				Err(io::Error::new(ErrorKind::InvalidData, format!("Duplicate mount for mount point '{:?}'", previous.mountPoint)))
			}
			else
			{
				Ok(())
			}
		}));
		
		Ok(map)
	}
		
	pub fn procSelfMountsReadOnly() -> Result<Self, io::Error>
	{
		Self::new(&Self::ProcSelfMounts(), true)
	}
	
	fn new(mountsFilePath: &Path, readOnly: bool) -> Result<Self, io::Error>
	{
		let mountsFilePath = pathToCString(mountsFilePath);
		
		let flag = match readOnly
		{
			false => Self::ReadOnlyFlag,
			true => Self::ReadWriteFlag,
		};
		
		let mountsHandle = unsafe { setmntent(mountsFilePath.as_ptr(), flag.as_ptr()) };
		if unlikely(mountsHandle.is_null())
		{
			Err(io::Error::new(ErrorKind::NotFound, "setmntent() returned NULL - not found or couldn't open or readOnly was false and file permissions prevent writing"))
		}
		else
		{
			Ok(Mounts(mountsHandle, readOnly))
		}
	}
	
	pub fn useMounts<F>(&self, mut calledForEachMount: F) -> Result<(), io::Error>
	where F: FnMut(Mount) -> Result<(), io::Error>
	{
		loop
		{
			let mountEntryPointer = unsafe { getmntent(self.0) };
			if unlikely(mountEntryPointer.is_null())
			{
				break;
			}
			let result = calledForEachMount(Mount::from_mntent(mountEntryPointer));
			if unlikely(result.is_err())
			{
				return result;
			}
		}
		Ok(())
	}
}