Skip to content

Commit b426044

Browse files
committed
stat: fix mount table read when /proc is unavailable
Only read mount information when needed (%m directive) and handle gracefully when /proc/self/mountinfo is not accessible, fixing stat failures in chroot environments without /proc mounted. see https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2133797
1 parent 7654075 commit b426044

File tree

1 file changed

+27
-11
lines changed

1 file changed

+27
-11
lines changed

src/uu/stat/src/stat.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use uucore::{entries, format_usage, show_error, show_warning};
1919

2020
use clap::{Arg, ArgAction, ArgMatches, Command};
2121
use std::borrow::Cow;
22+
use std::cell::OnceCell;
2223
use std::ffi::{OsStr, OsString};
2324
use std::fs::{FileType, Metadata};
2425
use std::io::Write;
@@ -306,7 +307,8 @@ struct Stater {
306307
show_fs: bool,
307308
from_user: bool,
308309
files: Vec<OsString>,
309-
mount_list: Option<Vec<OsString>>,
310+
mount_list: OnceCell<Option<Vec<OsString>>>,
311+
mount_list_needed: bool,
310312
default_tokens: Vec<Token>,
311313
default_dev_tokens: Vec<Token>,
312314
}
@@ -964,30 +966,44 @@ impl Stater {
964966

965967
// mount points aren't displayed when showing filesystem information, or
966968
// whenever the format string does not request the mount point.
967-
let mount_list = if show_fs
968-
|| !default_tokens
969+
let mount_list_needed = !show_fs
970+
&& default_tokens
969971
.iter()
970-
.any(|tok| matches!(tok, Token::Directive { format: 'm', .. }))
971-
{
972-
None
973-
} else {
974-
Some(Self::populate_mount_list()?)
975-
};
972+
.any(|tok| matches!(tok, Token::Directive { format: 'm', .. }));
976973

977974
Ok(Self {
978975
follow: matches.get_flag(options::DEREFERENCE),
979976
show_fs,
980977
from_user: !format_str.is_empty(),
981978
files,
979+
mount_list: OnceCell::new(),
980+
mount_list_needed,
982981
default_tokens,
983982
default_dev_tokens,
984-
mount_list,
985983
})
986984
}
987985

988986
fn find_mount_point<P: AsRef<Path>>(&self, p: P) -> Option<&OsString> {
987+
if !self.mount_list_needed {
988+
return None;
989+
}
990+
991+
let mount_list = self.mount_list.get_or_init(|| {
992+
match Self::populate_mount_list() {
993+
Ok(list) => Some(list),
994+
Err(e) => {
995+
// Show warning like GNU does when mount information cannot be read
996+
show_warning!(
997+
"{}",
998+
translate!("stat-error-cannot-read-filesystem", "error" => e.to_string())
999+
);
1000+
None
1001+
}
1002+
}
1003+
});
1004+
9891005
let path = p.as_ref().canonicalize().ok()?;
990-
self.mount_list
1006+
mount_list
9911007
.as_ref()?
9921008
.iter()
9931009
.find(|root| path.starts_with(root))

0 commit comments

Comments
 (0)