Finish mountpoint applet
This commit is contained in:
parent
6b6cc314e8
commit
84ede35190
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -162,9 +162,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.138"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
@ -222,6 +222,7 @@ dependencies = [
|
||||
"clap_mangen",
|
||||
"data-encoding",
|
||||
"hostname",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"termcolor",
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ clap_complete_nushell = "0.1.8"
|
||||
clap_mangen = "0.2.5"
|
||||
data-encoding = "2.3.3"
|
||||
hostname = { version = "0.3", features = ["set"] }
|
||||
libc = "0.2.139"
|
||||
once_cell = "1.16.0"
|
||||
termcolor = "1.1.3"
|
||||
|
||||
|
@ -1,5 +1,13 @@
|
||||
use super::Cmd;
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::{
|
||||
error::Error,
|
||||
fs::{self, File},
|
||||
io::{self, BufRead, BufReader, ErrorKind},
|
||||
os::linux::fs::MetadataExt,
|
||||
path::PathBuf,
|
||||
process,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mountpoint {
|
||||
@ -21,14 +29,31 @@ impl Cmd for Mountpoint {
|
||||
Command::new(self.name)
|
||||
.about("see if a directory or file is a mountpoint")
|
||||
.author("Nathan Fisher")
|
||||
.after_long_help(
|
||||
"EXIT STATUS\n \
|
||||
0\n \
|
||||
success: the directory is a mountpoint, or device is a block\
|
||||
device on --devno\n \
|
||||
1\n \
|
||||
failure: incorrect invocation, permissions or system error\
|
||||
\n 32\n \
|
||||
failure: the directory is not a mountpoint, or device is not a \
|
||||
block device on --devno"
|
||||
)
|
||||
.args([
|
||||
Arg::new("fs-devno")
|
||||
.help("Show the major/minor numbers of the device that is mounted on the given directory.")
|
||||
.help(
|
||||
"Show the major/minor numbers of the device that is \
|
||||
mounted on the given directory.",
|
||||
)
|
||||
.short('d')
|
||||
.long("fs-devno")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("devno")
|
||||
.help("Show the major/minor numbers of the given blockdevice on standard output.")
|
||||
.help(
|
||||
"Show the major/minor numbers of the given blockdevice \
|
||||
on standard output.",
|
||||
)
|
||||
.short('x')
|
||||
.long("devno")
|
||||
.conflicts_with("fs-devno")
|
||||
@ -38,14 +63,92 @@ impl Cmd for Mountpoint {
|
||||
.short('q')
|
||||
.long("quiet")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("file").num_args(1).required(true),
|
||||
])
|
||||
}
|
||||
|
||||
fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
unimplemented!();
|
||||
let Some(matches) = matches else {
|
||||
return Err(io::Error::new(ErrorKind::Other, "no input").into());
|
||||
};
|
||||
let file = matches.get_one::<String>("file").unwrap();
|
||||
if matches.get_flag("fs-devno") {
|
||||
match fs_devno(file)? {
|
||||
Some(maj_min) => println!("{maj_min}"),
|
||||
None => {
|
||||
println!("{file} is not a mountpoint");
|
||||
process::exit(32);
|
||||
}
|
||||
}
|
||||
} else if matches.get_flag("devno") {
|
||||
let devno = devno(file)?;
|
||||
println!("{}:{}", devno.0, devno.1);
|
||||
} else {
|
||||
let val = is_mountpoint(file)?;
|
||||
if val {
|
||||
if !matches.get_flag("quiet") {
|
||||
println!("{file} is a mountpoint");
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
if !matches.get_flag("quiet") {
|
||||
println!("{file} is not a mountpoint");
|
||||
}
|
||||
process::exit(32);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn path(&self) -> Option<crate::Path> {
|
||||
self.path
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mountpoint(path: &str) -> Result<bool, Box<dyn Error>> {
|
||||
let fd = File::open("/proc/mounts")?;
|
||||
let reader = BufReader::new(fd);
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
if let Some(mntpt) = line.split_whitespace().skip(1).next() {
|
||||
if mntpt == path {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn fs_devno(path: &str) -> Result<Option<String>, Box<dyn Error>> {
|
||||
let p = PathBuf::from(path);
|
||||
if !p.exists() {
|
||||
let msg = format!("mountpoint: {path}: No such file or directory");
|
||||
return Err(Box::new(io::Error::new(ErrorKind::Other, msg)));
|
||||
}
|
||||
let fd = File::open("/proc/self/mountinfo")?;
|
||||
let reader = BufReader::new(fd);
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let mut line = line.split_whitespace().skip(2);
|
||||
if let Some(maj_min) = line.next() {
|
||||
if let Some(mntpt) = line.skip(1).next() {
|
||||
if mntpt == path {
|
||||
return Ok(Some(String::from(maj_min)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn devno(path: &str) -> Result<(u32, u32), Box<dyn Error>> {
|
||||
let meta = fs::metadata(path)?;
|
||||
let rdev = meta.st_rdev();
|
||||
if rdev == 0 {
|
||||
let msg = format!("Mountpoint: Error: {path} is not a character device");
|
||||
return Err(Box::new(io::Error::new(ErrorKind::Other, msg)));
|
||||
}
|
||||
let major = unsafe { libc::major(rdev) };
|
||||
let minor = unsafe { libc::minor(rdev) };
|
||||
Ok((major, minor))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user