From nobody Fri Oct 17 11:55:26 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cp3DG3bQwz6D9pV; Fri, 17 Oct 2025 11:55:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cp3DG2JtPz3Pfj; Fri, 17 Oct 2025 11:55:26 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760702126; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=zEQCiaRSolN0/ZD02mmXD5Z0uNRLP/NTZxpDgWq3acw=; b=AJiEeuvHFgu5IM60dhRLj6vStCt9LicJyrO1p7ilLd7Xe9WOpHfu7ocAGeJVrrHNnyZDVz lpXo5b8QIaTYdT7IzBfrQ3u0w6Zn8dwQOquj5C/rCyRoeCCAe73Ue+Svtkt9jz7ukC0kyR bn9zr9tXg7NbgRziSegk5ve2X5Qz+sO70lr6MC0KtzGZVgTd7I0rSpPBCdPjhaPzR+LyO1 eypMfqeVv2wPIM/mTcN2pBML+fzTHq6+EYmQHbuvwCelruGOJynWjSqqnmoXVW1OMY4Rxw yxZI6hn8buW1SA0vVi+OI11yNCoCfTvvQS2OGbSXNU85/8ZfVS9DYBGXfPAW6g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760702126; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=zEQCiaRSolN0/ZD02mmXD5Z0uNRLP/NTZxpDgWq3acw=; b=pqbz6eCBKVBjtktbY/dSK7K/vblQn7PIt4Vc9W8KYHV+a8+EsyvKtWRXyn61XHgt6McFNa N1tvabiCOS2iwFjsx03/RgFvxWRF2aW9pFY1VQs/4KTKLhwAR3qYk+JtiIOg/ATCGcnm3i ONPEjSdC1JHz5r5MGSyKVpzZ3PtU0kchHwOoNZWWAi+3EQNrd9581ybYOvIpZtIODoF7H7 kIru3OlWn/3Gxt+uqUOYqwKLpa86kQ3VVW4PMFjBfja89KZfKU+5siiRgYjt9RnYcO34zA 2W/cTcO25TkxQCirNsAwYCQqXY5SLqrgF5ClYn8TWtdV5S/5ymrPdwd3jqFasQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1760702126; a=rsa-sha256; cv=none; b=OfBEeI+TFYKHNVRq1miOPlyraqlQQeMdw/MuQggUOnhd0MTbCl08a4hL9dlZJVNTtRrAKX RSBJHQjm6kP7MVLsRKUXid83EK95lJJl9M3JroONQB8T03OYStNbZyDPDm9ZJCpgiVmrA7 N2fVRfgubL9V3A7jSuFa3fg6GDGALjCqEgYbI6z9QpjBaNGGiQr2SDg1Sf0Sa6whCak3G0 GEGPybb7n9x86D2M3ZUcq8lhyrC8Cx1jlliGO+MHVdbIPEA6vaoRpl3cbbxwzRr9HKnuZP X7MDnJyK2ULfTqoRxA1qzCOKcsVQmjqm45c6kkpOVn+3AUP+wL6PnnrsWLfpOg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cp3DG1dJ6zthL; Fri, 17 Oct 2025 11:55:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 59HBtQ3o004769; Fri, 17 Oct 2025 11:55:26 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59HBtQHE004766; Fri, 17 Oct 2025 11:55:26 GMT (envelope-from git) Date: Fri, 17 Oct 2025 11:55:26 GMT Message-Id: <202510171155.59HBtQHE004766@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: aa870a1935bc - main - quot: Add tests List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: aa870a1935bccb66e02c4c31630706768a3e7d74 Auto-Submitted: auto-generated The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=aa870a1935bccb66e02c4c31630706768a3e7d74 commit aa870a1935bccb66e02c4c31630706768a3e7d74 Author: Dag-Erling Smørgrav AuthorDate: 2025-10-17 11:55:12 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2025-10-17 11:55:12 +0000 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 --- etc/mtree/BSD.tests.dist | 2 + usr.sbin/quot/Makefile | 6 ++- usr.sbin/quot/quot.c | 19 +++++--- usr.sbin/quot/tests/Makefile | 4 ++ usr.sbin/quot/tests/quot_test.sh | 102 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 7 deletions(-) diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 8a752925d0a5..520b41c8b88f 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -1285,6 +1285,8 @@ .. pw .. + quot + .. rpcbind .. sa diff --git a/usr.sbin/quot/Makefile b/usr.sbin/quot/Makefile index 34ebcb1009c8..2f32c8f2df8b 100644 --- a/usr.sbin/quot/Makefile +++ b/usr.sbin/quot/Makefile @@ -1,5 +1,9 @@ +.include + PROG= quot MAN= quot.8 -LIBADD= ufs +LIBADD= ufs util +HAS_TESTS= +SUBDIR.${MK_TESTS}= tests .include diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c index 323648d8d550..879580f649b9 100644 --- a/usr.sbin/quot/quot.c +++ b/usr.sbin/quot/quot.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -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++; diff --git a/usr.sbin/quot/tests/Makefile b/usr.sbin/quot/tests/Makefile new file mode 100644 index 000000000000..d4e64691f905 --- /dev/null +++ b/usr.sbin/quot/tests/Makefile @@ -0,0 +1,4 @@ +PACKAGE= tests +ATF_TESTS_SH= quot_test + +.include diff --git a/usr.sbin/quot/tests/quot_test.sh b/usr.sbin/quot/tests/quot_test.sh new file mode 100644 index 000000000000..21088d162a53 --- /dev/null +++ b/usr.sbin/quot/tests/quot_test.sh @@ -0,0 +1,102 @@ +# +# Copyright (c) 2025 Dag-Erling Smørgrav +# +# 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 +}