quot: Add tests

To facilitate the task, we change the comparison function so that users
with equal filesystem usage are sorted by UID, and add an undocumented
option that prevents quot from replacing numerical UIDs with names.  We
also switch from getfsfile(3) to getmntpoint(3) so the first line is
identical regardless of whether we pass quot a mountpoint or a device.

Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D53133
This commit is contained in:
Dag-Erling Smørgrav committed 2025-10-17 13:55:12 +02:00
1 parent 8209311c51
commit aa870a1935
5 files changed
+126 -7

No files matched your search

+2
View File
@@ -1285,6 +1285,8 @@
..
pw
..
quot
..
rpcbind
..
sa
+5 -1
View File
@@ -1,5 +1,9 @@
.include <src.opts.mk>
PROG= quot
MAN= quot.8
LIBADD= ufs
LIBADD= ufs util
HAS_TESTS=
SUBDIR.${MK_TESTS}= tests
.include <bsd.prog.mk>
+13 -6
View File
@@ -42,6 +42,7 @@
#include <fcntl.h>
#include <fstab.h>
#include <libufs.h>
#include <mntopts.h>
#include <paths.h>
#include <pwd.h>
#include <stdbool.h>
@@ -55,6 +56,7 @@
/* some flags of what to do: */
static bool all;
static bool count;
static bool noname;
static bool unused;
static void (*func)(int, struct fs *);
static long blocksize;
@@ -227,7 +229,7 @@ user(uid_t uid)
for (usr = users + uid % nusers, i = nusers; --i >= 0; usr--) {
if (usr->name == NULL) {
usr->uid = uid;
if ((pwd = getpwuid(uid)) == NULL)
if (noname || (pwd = getpwuid(uid)) == NULL)
asprintf(&usr->name, "#%u", uid);
else
usr->name = strdup(pwd->pw_name);
@@ -248,7 +250,10 @@ cmpusers(const void *v1, const void *v2)
{
const struct user *u1 = v1, *u2 = v2;
return (u2->space - u1->space);
return (u2->space > u1->space ? 1 :
u2->space < u1->space ? -1 :
u1->uid > u2->uid ? 1 :
u1->uid < u2->uid ? -1 : 0);
}
#define sortusers(users) \
@@ -469,12 +474,11 @@ int
main(int argc, char *argv[])
{
struct statfs *mp;
struct fstab *fs;
int ch, cnt;
func = douser;
header = getbsize(&headerlen, &blocksize);
while ((ch = getopt(argc, argv, "acfhknv")) != -1) {
while ((ch = getopt(argc, argv, "acfhkNnv")) != -1) {
switch (ch) {
case 'a':
all = true;
@@ -491,6 +495,9 @@ main(int argc, char *argv[])
case 'k':
blocksize = 1024;
break;
case 'N':
noname = true;
break;
case 'n':
func = donames;
break;
@@ -513,8 +520,8 @@ main(int argc, char *argv[])
quot(mp->f_mntfromname, mp->f_mntonname);
}
while (argc-- > 0) {
if ((fs = getfsfile(*argv)) != NULL)
quot(fs->fs_spec, 0);
if ((mp = getmntpoint(*argv)) != NULL)
quot(mp->f_mntfromname, mp->f_mntonname);
else
quot(*argv, 0);
argv++;
+4
View File
@@ -0,0 +1,4 @@
PACKAGE= tests
ATF_TESTS_SH= quot_test
.include <bsd.test.mk>
+102
View File
@@ -0,0 +1,102 @@
#
# Copyright (c) 2025 Dag-Erling Smørgrav <[email protected]>
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Create and mount a UFS filesystem on a small memory disk
quot_setup()
{
atf_check -o save:dev mdconfig -t malloc -s 16M
local dev=$(cat dev)
atf_check -o ignore newfs "$@" /dev/$dev
atf_check mkdir mnt
local mnt=$(realpath mnt)
atf_check mount /dev/$dev "$mnt"
echo "/dev/$dev: ($mnt)" >expect
printf "%5d\t%5d\t%-8s\n" 8 2 "#0" >>expect
}
# Create a directory owned by a given UID
quot_adduid()
{
local uid=$1
atf_check install -d -o $uid -g 0 mnt/$uid
printf "%5d\t%5d\t%-8s\n" 4 1 "#$uid" >>expect
}
# Perform the tests
quot_test()
{
local dev=$(cat dev)
# Create inodes owned by a large number of users to exercise
# hash collisions and rehashing. The code uses an open hash
# table that starts out with only 8 entries and doubles every
# time it fills up.
local uid
for uid in $(seq 1 32); do
quot_adduid $uid
done
# Also create inodes owned by users with long UIDs, up to the
# highest possible value (2^32 - 2, because chown(2) and
# friends interpret 2^32 - 1 as “leave unchanged”).
local shift
for shift in $(seq 6 32); do
quot_adduid $(((1 << shift) - 2))
done
# Since quot operates directly on the underlying device, not
# on the mounted filesystem, we remount read-only to ensure
# that everything gets flushed to the memory disk.
atf_check mount -ur /dev/$dev
atf_check -o file:expect quot -fkN /dev/$dev
atf_check -o file:expect quot -fkN $(realpath mnt)
}
# Unmount and release the memory disk
quot_cleanup()
{
if [ -d mnt ]; then
umount mnt || true
fi
if [ -f dev ]; then
mdconfig -d -u $(cat dev) || true
fi
}
atf_test_case ufs1 cleanup
ufs1_head()
{
atf_set descr "Test quot on UFS1"
atf_set require.user root
}
ufs1_body()
{
quot_setup -O1
quot_test
}
ufs1_cleanup()
{
quot_cleanup
}
atf_test_case ufs2 cleanup
ufs2_head()
{
atf_set descr "Test quot on UFS2"
atf_set require.user root
}
ufs2_body()
{
quot_setup -O2
quot_test
}
ufs2_cleanup()
{
quot_cleanup
}
atf_init_test_cases()
{
atf_add_test_case ufs1
atf_add_test_case ufs2
}