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