From nobody Mon Oct 20 16:11:40 2025 X-Original-To: dev-commits-src-branches@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 4cr0mX66j2z6Cgl6; Mon, 20 Oct 2025 16:11:40 +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 4cr0mX3tV1z3VQs; Mon, 20 Oct 2025 16:11:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760976700; 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=h+zfWY4u1F6oxp9EF1YJ/4hSeJK5FHKN8UDWRCkUDQU=; b=ARS74+l/4TCY/dtHENEkECQPt0dwyW5qywqCVC0IrXp/Eo595fikuZ603XpKHyMo+Ra3g4 u+TZWQeEOPHGCN1qozoc+jHnMEOr9ylTnHDnrPw9aw5jkQLen5w4YpVEzI1pjog1rzXzV5 A1iM1aUTnbefYIRPh9VE6lWxXZrbxe7xlLTeWcstMNytpIHmcf56CmCvmDqDgY0WzDA7Of ijL/eP/r+oYBFz0+uBTcopuXZmPUVAQA9Ujn/TNIs2xbeHjKr/n/AXA9Obdj9TsgKunCvA /17obFC9UMBLbEMaBJo7hjzr1+EeB8C9IvI1xRu+28ytMINwt60cP6NnBGwcdg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760976700; 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=h+zfWY4u1F6oxp9EF1YJ/4hSeJK5FHKN8UDWRCkUDQU=; b=LSSkLIX5Prk+hxCXfe40PeSxsGNPnyZZVul/7wZ1ynHWwfkbFgk4JOIaGx6phOmfdBOuYS oXlmsWCORLwiZYWomSBbW3UEmExqB+strkxZSmx0ciEb21BwBCWxrlfrqB/HYd7rtrNDuS ChATT8FiJh3R2b+E1UDl3I7ziEPZeGQQPgiACkVP55X67QGrzXGBnNlnaEQ9WhXmQUj2nD uJupRiInv/rE5u9UA3jplBnStFWOwFAOutWtQb6EVCgoFNsvMsGy4PqBa7viomdG/zTEjs m+yAtZBBExWVjWI5qkufbD76YwvppnQE/pXSoWhDGVrf3fSHPOfJyqCyCn7zUw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1760976700; a=rsa-sha256; cv=none; b=DEgiPpDjzil2CmTpMc7arZcX5Wr8UHxcgYT7zQoqfD0Ismh4QzMpOwBj0Tsxnsxhbh/wrM 7wK/VecSZ5wv/WdxbKYRvvyqxdOIW1lS8waVuyUHaDrFZKNfw3oXcOQVsPw5KA6dU/F2vW xiCXwahwvbMsdtVkPcsn2GFR0N1yfShH7rTsHq8DT4Ik4GxlAwNkBExvYdvujU8cl1rNrF kAZx6TTWINWipO3AA9J9lnxmGJEv76aa69SBXlxgi4uXvQnQw7WuG9RG/vDpX4GRNyyOCQ QQjRXgNKxksFKBQqWhDqEFWL3YmvHym1aAJ3AQzhoqr0WFY1zvgBqz22XwHg9Q== 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 4cr0mX3R7Nz4pY; Mon, 20 Oct 2025 16:11:40 +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 59KGBeci036468; Mon, 20 Oct 2025 16:11:40 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59KGBeF4036465; Mon, 20 Oct 2025 16:11:40 GMT (envelope-from git) Date: Mon, 20 Oct 2025 16:11:40 GMT Message-Id: <202510201611.59KGBeF4036465@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: b5f3f1a661ab - stable/15 - quot: Add tests List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@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/stable/15 X-Git-Reftype: branch X-Git-Commit: b5f3f1a661ab69986c3379fa4c9c2b38785933db Auto-Submitted: auto-generated The branch stable/15 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=b5f3f1a661ab69986c3379fa4c9c2b38785933db commit b5f3f1a661ab69986c3379fa4c9c2b38785933db Author: Dag-Erling Smørgrav AuthorDate: 2025-10-17 11:55:12 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2025-10-20 16:11:22 +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 (cherry picked from commit aa870a1935bccb66e02c4c31630706768a3e7d74) --- 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 e6a013f010de..9ab2f3e972d6 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -1283,6 +1283,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 +}