stat: fix use of devname(3)

Besides being a little hard to parse through visually, this had its own
bug of inspecting st->st_mode to determine what to pass to devname(3),
which is only correct for st_rdev.

For st_dev, you're likely to be looking at files or directories and
attempting to assess what device they're located on, so the mode is
meaningless- we just have to assume that our filesystems are on
character devices and attempt to resolve st_dev as such.

Reviewed by:	des, kib (previous version)
Differential Revision:	https://reviews.freebsd.org/D56565
This commit is contained in:
Kyle Evans
2026-04-30 22:00:26 -05:00
parent 910f78a514
commit 4d4acdbfc2
2 changed files with 44 additions and 3 deletions
+11 -3
View File
@@ -650,6 +650,7 @@ format1(const struct stat *st,
struct timespec ts; struct timespec ts;
struct tm *tm; struct tm *tm;
int l, small, formats; int l, small, formats;
mode_t dtype;
tsp = NULL; tsp = NULL;
formats = 0; formats = 0;
@@ -665,9 +666,16 @@ format1(const struct stat *st,
small = (sizeof(st->st_dev) == 4); small = (sizeof(st->st_dev) == 4);
data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev; data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;
#if HAVE_DEVNAME #if HAVE_DEVNAME
sdata = devname(what == SHOW_st_dev ? st->st_dev : switch (what) {
st->st_rdev, S_ISCHR(st->st_mode) ? S_IFCHR : case SHOW_st_dev:
(S_ISBLK(st->st_mode) ? S_IFBLK : 0)); dtype = S_IFCHR;
break;
case SHOW_st_rdev:
dtype = st->st_mode & (S_IFCHR | S_IFBLK);
break;
}
sdata = devname(data, dtype);
#endif /* HAVE_DEVNAME */ #endif /* HAVE_DEVNAME */
if (hilo == HIGH_PIECE) { if (hilo == HIGH_PIECE) {
data = major(data); data = major(data);
+33
View File
@@ -25,6 +25,8 @@
# SUCH DAMAGE. # SUCH DAMAGE.
# #
: ${CHKPATH:="mnt"}
atf_test_case F_flag atf_test_case F_flag
F_flag_head() F_flag_head()
{ {
@@ -301,6 +303,36 @@ x_flag_body()
done done
} }
atf_test_case devname cleanup
devname_head()
{
atf_set "descr" "Verify that %Sd outputs a device name"
}
devname_body()
{
local devname devpath
atf_check -o save:dev mdconfig -t malloc -s 16M
read devname < dev
devpath="/dev/$devname"
atf_check -o not-empty newfs "$devpath"
atf_check mkdir "$CHKPATH"
atf_check mount "$devpath" "$CHKPATH"
atf_check -o inline:"$devname\n" stat -f '%Sd' "$CHKPATH"
atf_check -o inline:"$devname\n" stat -f '%Sr' "$devpath"
}
devname_cleanup()
{
if [ -d "$CHKPATH" ]; then
umount "$CHKPATH" || true
fi
if [ -f dev ]; then
mdconfig -d -u $(cat dev) || true
fi
}
atf_init_test_cases() atf_init_test_cases()
{ {
atf_add_test_case F_flag atf_add_test_case F_flag
@@ -315,4 +347,5 @@ atf_init_test_cases()
atf_add_test_case s_flag atf_add_test_case s_flag
atf_add_test_case t_flag atf_add_test_case t_flag
atf_add_test_case x_flag atf_add_test_case x_flag
atf_add_test_case devname
} }