xref: /freebsd/usr.sbin/quot/tests/quot_test.sh (revision 8ccc0d235c226d84112561d453c49904398d085c)
1#
2# Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org>
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6
7# Create and mount a UFS filesystem on a small memory disk
8quot_setup()
9{
10	atf_check -o save:dev mdconfig -t malloc -s 16M
11	local dev=$(cat dev)
12	atf_check -o ignore newfs "$@" /dev/$dev
13	atf_check mkdir mnt
14	local mnt=$(realpath mnt)
15	atf_check mount /dev/$dev "$mnt"
16	echo "/dev/$dev: ($mnt)" >expect
17	printf "%5d\t%5d\t%-8s\n" 8 2 "#0" >>expect
18	printf "%s\n" "/dev/$dev" >ninput
19	echo "/dev/$dev: ($mnt)" >nexpect
20}
21
22# Create a directory owned by a given UID
23quot_adduid()
24{
25	local uid=$1
26	atf_check install -d -o $uid -g 0 mnt/$uid
27	printf "%5d\t%5d\t%-8s\n" 4 1 "#$uid" >>expect
28	ls -di mnt/$uid >>ninput
29	printf "%s\t%s\n" "#$uid" mnt/$uid >>nexpect
30}
31
32# Perform the tests
33quot_test()
34{
35	local dev=$(cat dev)
36	# Deliberately add invalid lines to our -n input before the
37	# valid ones to verify that quot does not abort on first
38	# error.  Note that quot deliberately ignores initial lines
39	# that don't start with a number, and that after encountering
40	# at least one line that does start with a number, quot would
41	# previously terminate on encountering one that doesn't (now
42	# it simply ignores them).  This also tests that we don't
43	# require whitespace between the inode number and the comment.
44	echo "0zero" >>ninput
45	echo "invalid" >>ninput
46	echo "-1minusone" >>ninput
47	# Create inodes owned by a large number of users to exercise
48	# hash collisions and rehashing.  The code uses an open hash
49	# table that starts out with only 8 entries and doubles every
50	# time it fills up.
51	local uid
52	for uid in $(seq 1 32); do
53		quot_adduid $uid
54	done
55	# Also create inodes owned by users with long UIDs, up to the
56	# highest possible value (2^32 - 2, because chown(2) and
57	# friends interpret 2^32 - 1 as “leave unchanged”).
58	local shift
59	for shift in $(seq 6 32); do
60		quot_adduid $(((1 << shift) - 2))
61	done
62	# Since quot operates directly on the underlying device, not
63	# on the mounted filesystem, we remount read-only to ensure
64	# that everything gets flushed to the memory disk.
65	atf_check mount -ur /dev/$dev
66	atf_check -o file:expect quot -fkN /dev/$dev
67	atf_check -o file:expect quot -fkN $(realpath mnt)
68	# Test -n option
69	atf_check -o file:nexpect \
70	    -e inline:"quot: invalid inode 0\nquot: invalid inode -1\n" \
71	    quot -Nn /dev/$dev <ninput
72}
73
74# Unmount and release the memory disk
75quot_cleanup()
76{
77	if [ -d mnt ]; then
78		umount mnt || true
79	fi
80	if [ -f dev ]; then
81		mdconfig -d -u $(cat dev) || true
82	fi
83}
84
85atf_test_case ufs1 cleanup
86ufs1_head()
87{
88	atf_set descr "Test quot on UFS1"
89	atf_set require.user root
90}
91ufs1_body()
92{
93	quot_setup -O1
94	quot_test
95}
96ufs1_cleanup()
97{
98	quot_cleanup
99}
100
101atf_test_case ufs2 cleanup
102ufs2_head()
103{
104	atf_set descr "Test quot on UFS2"
105	atf_set require.user root
106}
107ufs2_body()
108{
109	quot_setup -O2
110	quot_test
111}
112ufs2_cleanup()
113{
114	quot_cleanup
115}
116
117atf_init_test_cases()
118{
119	atf_add_test_case ufs1
120	atf_add_test_case ufs2
121}
122