I'm trying to run yazi on NetBSD. It basically works fine, but deletion behaves badly. I filed a bug report with yazi, they referred me to trash-rs, I ran its self tests and one of them immediately dumps core on NetBSD.
I've extracted the code (removing the locking to simplify it, my test is simple-threaded anyway), it generates the same backtrace in gdb.
Here's the code:
use std::path::PathBuf;
#[derive(Debug)]
struct MountPoint {
mnt_dir: PathBuf,
_mnt_type: String,
_mnt_fsname: String,
}
fn get_mount_points() -> Vec<MountPoint> {
fn c_buf_to_str(buf: &[libc::c_char]) -> Option<&str> {
let buf: &[u8] = unsafe { std::slice::from_raw_parts(buf.as_ptr() as _, buf.len()) };
if let Some(pos) = buf.iter().position(|x| *x == 0) {
// Shrink buffer to omit the null bytes
std::str::from_utf8(&buf[..pos]).ok()
} else {
std::str::from_utf8(buf).ok()
}
}
let mut fs_infos: *mut libc::statvfs = std::ptr::null_mut();
let count = unsafe { libc::getmntinfo(&mut fs_infos, libc::MNT_WAIT) };
if count < 1 {
return Vec::new();
}
let fs_infos: &[libc::statvfs] = unsafe { std::slice::from_raw_parts(fs_infos as _, count as _) };
let mut result = Vec::new();
for fs_info in fs_infos {
if fs_info.f_mntfromname[0] == 0 || fs_info.f_mntonname[0] == 0 {
// If we have missing information, no need to look any further...
continue;
}
let fs_type = c_buf_to_str(&fs_info.f_fstypename).unwrap_or_default();
let mount_to = match c_buf_to_str(&fs_info.f_mntonname) {
Some(m) => m,
None => {
continue;
}
};
let mount_from = c_buf_to_str(&fs_info.f_mntfromname).unwrap_or_default();
let mount_point =
MountPoint { mnt_dir: mount_to.into(), _mnt_fsname: mount_from.into(), _mnt_type: fs_type.into() };
result.push(mount_point);
}
result
}
fn main() {
let result = get_mount_points();
println!("{:?}", result);
}
In gdb, i get:
Program received signal SIGSEGV, Segmentation fault.
rust_statvfs::get_mount_points () at src/main.rs:29
29 if fs_info.f_mntfromname[0] == 0 || fs_info.f_mntonname[0] == 0 {
According to the NetBSD statvfs(5) man page statvfs(5) - NetBSD Manual Pages , the fields are strings of fixed length:
char f_fstypename[VFS_NAMELEN]; /* fs type name */
char f_mntonname[VFS_MNAMELEN]; /* directory on which mounted */
char f_mntfromname[VFS_MNAMELEN]; /* mounted file system */
char f_mntfromlabel[_VFS_MNAMELEN]; /* disk label name if avail */
so the test if the first byte is a zero should work.
Can anyone see what the bug is?