Skip to content

Commit 7479731

Browse files
committed
First version of findmnt
1 parent 1681794 commit 7479731

File tree

6 files changed

+225
-0
lines changed

6 files changed

+225
-0
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ feat_common_core = [
3535
"mountpoint",
3636
"rev",
3737
"setsid",
38+
"findmnt",
3839
]
3940

4041
[workspace.dependencies]
@@ -76,6 +77,7 @@ lsmem = { optional = true, version = "0.0.1", package = "uu_lsmem", path = "src/
7677
mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", path = "src/uu/mountpoint" }
7778
rev = { optional = true, version = "0.0.1", package = "uu_rev", path = "src/uu/rev" }
7879
setsid = { optional = true, version = "0.0.1", package = "uu_setsid", path ="src/uu/setsid" }
80+
findmnt = { optional = true, version = "0.0.1", package = "uu_findmnt", path = "src/uu/findmnt" }
7981

8082
[dev-dependencies]
8183
# dmesg test require fixed-boot-time feature turned on.

src/uu/findmnt/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "uu_findmnt"
3+
version = "0.0.1"
4+
edition = "2021"
5+
6+
[lib]
7+
path = "src/findmnt.rs"
8+
9+
[[bin]]
10+
name = "findmnt"
11+
path = "src/main.rs"
12+
13+
[dependencies]
14+
tabled = { workspace = true }
15+
uucore = { workspace = true }
16+
clap = { workspace = true }

src/uu/findmnt/findmnt.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# findmnt
2+
3+
```
4+
findmnt [options]
5+
```
6+
7+
findmnt will list all mounted filesytems or search for a filesystem. The findmnt command is able to search in /etc/fstab, /etc/fstab.d, /etc/mtab or /proc/self/mountinfo. If device or mountpoint is not given, all filesystems are shown.

src/uu/findmnt/src/findmnt.rs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
use core::fmt;
2+
use std::fs;
3+
4+
use clap::{crate_version, Command};
5+
use tabled::{settings::Style, Table, Tabled};
6+
use uucore::{error::UResult, help_about};
7+
8+
#[uucore::main]
9+
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
10+
let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
11+
12+
// By default findmnt reads /proc/self/mountinfo
13+
let mut res = Findmnt::new(MOUNTINFO_DIR);
14+
res.form_nodes();
15+
res.print_table();
16+
Ok(())
17+
}
18+
19+
pub static MOUNTINFO_DIR: &str = "/proc/self/mountinfo";
20+
pub static ABOUT: &str = help_about!("findmnt.md");
21+
22+
pub fn uu_app() -> Command {
23+
Command::new(uucore::util_name())
24+
.version(crate_version!())
25+
.about(ABOUT)
26+
}
27+
28+
#[derive(Debug, Clone)]
29+
pub struct Findmnt<'a> {
30+
pub nodes_vec: Vec<Node>,
31+
file_name: &'a str,
32+
}
33+
34+
impl<'a> Findmnt<'a> {
35+
pub fn new(file_name: &str) -> Findmnt {
36+
Findmnt {
37+
file_name,
38+
nodes_vec: Vec::<Node>::new(),
39+
}
40+
}
41+
42+
pub fn form_nodes(&mut self) {
43+
let res = fs::read_to_string(self.file_name).unwrap();
44+
let lines = res.lines();
45+
let mut unsorted_vec = Vec::<Node>::new();
46+
47+
for line in lines {
48+
let res = Node::parse(line);
49+
unsorted_vec.push(res);
50+
}
51+
52+
self.nodes_vec = unsorted_vec;
53+
// /, /proc, /sys, /dev, /run, /tmp, /boot
54+
// Sort the vec according to this
55+
self.sort_nodes();
56+
}
57+
58+
pub fn print_table(&self) {
59+
let mut table = Table::new(self.nodes_vec.clone());
60+
table.with(Style::empty());
61+
print!("{}", table)
62+
}
63+
64+
fn sort_nodes(&mut self) {
65+
let unsorted_vec = self.nodes_vec.clone();
66+
let mut sorted_vec = Vec::new();
67+
68+
// "/"
69+
// This should always give one element
70+
let res = unsorted_vec
71+
.iter()
72+
.find(|node| node.target == Types::ROOT.to_string());
73+
sorted_vec.push(res.unwrap().clone());
74+
75+
// "proc"
76+
sorted_vec.extend(self.filter(Types::PROC));
77+
78+
// "/sys"
79+
sorted_vec.extend(self.filter(Types::SYS));
80+
81+
// "/dev"
82+
sorted_vec.extend(self.filter(Types::DEV));
83+
84+
// "/run"
85+
sorted_vec.extend(self.filter(Types::RUN));
86+
87+
// "/tmp"
88+
sorted_vec.extend(self.filter(Types::TMP));
89+
90+
// "/boot"
91+
sorted_vec.extend(self.filter(Types::BOOT));
92+
93+
self.nodes_vec = sorted_vec;
94+
}
95+
96+
fn filter(&self, pattern: Types) -> Vec<Node> {
97+
let mut temp_vec = Vec::<Node>::new();
98+
let _ = self.filter_with_pattern(pattern).iter().for_each(|node| {
99+
temp_vec.push(node.clone());
100+
});
101+
temp_vec
102+
}
103+
104+
fn filter_with_pattern(&self, pattern: Types) -> Vec<Node> {
105+
self.nodes_vec
106+
.iter()
107+
.filter(|node| node.target.starts_with(&pattern.to_string()))
108+
.cloned()
109+
.collect()
110+
}
111+
}
112+
113+
// Different types for a particular node
114+
#[derive(Debug, Clone)]
115+
pub enum Types {
116+
ROOT,
117+
PROC,
118+
SYS,
119+
DEV,
120+
RUN,
121+
TMP,
122+
BOOT,
123+
}
124+
125+
impl fmt::Display for Types {
126+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127+
match self {
128+
Types::ROOT => write!(f, "{}", "/"),
129+
Types::PROC => write!(f, "{}", "/proc"),
130+
Types::SYS => write!(f, "{}", "/sys"),
131+
Types::DEV => write!(f, "{}", "/dev"),
132+
Types::RUN => write!(f, "{}", "/run"),
133+
Types::TMP => write!(f, "{}", "/tmp"),
134+
Types::BOOT => write!(f, "{}", "/boot"),
135+
}
136+
}
137+
}
138+
139+
// Represents each row for the table
140+
#[derive(Debug, Clone, Tabled)]
141+
pub struct Node {
142+
target: String,
143+
source: String,
144+
fstype: String,
145+
options: String,
146+
}
147+
148+
impl Node {
149+
fn new(target: String, source: String, fstype: String, options: String) -> Node {
150+
Node {
151+
target,
152+
source,
153+
fstype,
154+
options,
155+
}
156+
}
157+
158+
pub fn filter_with_pattern(node_vec: &Vec<Node>, pattern: Types) -> Vec<Node> {
159+
node_vec
160+
.iter()
161+
.filter(|node| node.target.starts_with(&pattern.to_string()))
162+
.cloned()
163+
.collect()
164+
}
165+
166+
// This is the main function that parses the default /proc/self/mountinfo
167+
pub fn parse(line: &str) -> Self {
168+
let (_, rest) = line.split_once("/").unwrap();
169+
let (target, rest) = rest.trim().split_once(" ").unwrap();
170+
let (options, rest) = rest.trim().split_once(" ").unwrap();
171+
let (_, rest) = rest.trim().split_once("-").unwrap();
172+
let (fstype, rest) = rest.trim().split_once(" ").unwrap();
173+
let (source, rest) = rest.trim().split_once(" ").unwrap();
174+
let options_added = if let Some(_) = rest.split_once("rw") {
175+
rest.split_once("rw").unwrap().1
176+
} else {
177+
rest
178+
};
179+
180+
let final_options = options.to_owned() + options_added;
181+
182+
Self::new(
183+
target.to_string(),
184+
source.to_string(),
185+
fstype.to_string(),
186+
final_options,
187+
)
188+
}
189+
}

src/uu/findmnt/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uucore::bin!(uu_findmnt);

0 commit comments

Comments
 (0)