From nobody Thu Oct 30 23:52:35 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 4cyLWl38M6z6FnL4; Thu, 30 Oct 2025 23:52:35 +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 4cyLWl1WFgz3cjV; Thu, 30 Oct 2025 23:52:35 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1761868355; 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=CRBUVdlsM6mHkR+kpGG0gAizAt0uEDfL4AekSUzUYSc=; b=UWCXRzLaVETArBD5D+FK4ldHDn9Q/ROoxme3wFk6ve2z7zY/ZdiAKtN7yP7RhpI9tZ6cvw yFjehaszg9JHqIWjJObPo4+Fyz91ttNrW/1TtddGVJUwbXHA9XAeIzNAf7qI81ojZoiRIs 8FlFwaC3deddjMV/6gQ/UQlYphOfFMkWm8gMVuNZvnPJ9yKrnEYNuE0P3sYgx/50l1k2JF b05ZvH6T79GP2VIy09URc4eBQEjx1PQJmbbzbLHJkce/GFwXRcjdlW7v5Dnsi8Wpq8/kAf KmikX1VU3BfnI65SAViZnBlLD7W0w1VD2nSkK3vLXccy+dWjWPII/nBiNrxAUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1761868355; 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=CRBUVdlsM6mHkR+kpGG0gAizAt0uEDfL4AekSUzUYSc=; b=gd6M27PDeg2fExXvYm3IGu2nCjajzB1OzYPFp5p4cfkpOm9AH1yVhVrKBIxn77TiWhPivl 39rHn8y810vpzZecpD1GBsju56xGPQFf4NpSVu42atu4qpqxquGkHrcJo+lEn0ZGwOO/Bb fjdVDQkh+QI60R67HEBb1v0nIRbs+e/rCqRaBqvrBXME90Zi7MxWKDbu52OcaERI7Gqy5H YZOcfszMdjc3XHb7ZWWkfisSUomL4pR0sCFFqcUuavKdvaV2QAstL9mE+rYOteefmH5FUC 3NJSE2R5LIeHtqCfvcB10Umsg0e63yM7/Nf+W2iYsD5HAXC5ucGQkrScmA+ong== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1761868355; a=rsa-sha256; cv=none; b=cOP2LUxzP5as3TJj0yUSM1I+OMWZ3WgYwCRSp4IwbFvKLX9FBRMoe4mOHOX50OmLGWj9+u ZI1dDUlE5cSHIIHHc4Qd8nmeY1bf3oUwO+T7HKWbdJR3FptHCGy0d7W0yYIpfYd44ehpmj PfpxcOhP5XQibSCH8pZEiF+ENGfGdKVMjU/gRixhX2nWq/ZxuZDSUWswUwV4sX7v+zMhFJ ydif1g4breFBaCNlvVGsgRrBKWun1Acj6OGw/UzfGWYOG4V+g/zepMOzURRZcwlT0Z6e9d sFJ9NM0xTGX4nrO9U8HEMcZwCuqBG4z9CAElGpX40OsBpPs7ODrm/cqtBBrj1Q== 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 4cyLWl0w4SzlWf; Thu, 30 Oct 2025 23:52:35 +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 59UNqZJn088367; Thu, 30 Oct 2025 23:52:35 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59UNqZkt088364; Thu, 30 Oct 2025 23:52:35 GMT (envelope-from git) Date: Thu, 30 Oct 2025 23:52:35 GMT Message-Id: <202510302352.59UNqZkt088364@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Colin Percival Subject: git: 1825be32d073 - releng/15.0 - 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: cperciva X-Git-Repository: src X-Git-Refname: refs/heads/releng/15.0 X-Git-Reftype: branch X-Git-Commit: 1825be32d073eb0f39d5ccbaff9eec6e0b8fc8fb Auto-Submitted: auto-generated The branch releng/15.0 has been updated by cperciva: URL: https://cgit.FreeBSD.org/src/commit/?id=1825be32d073eb0f39d5ccbaff9eec6e0b8fc8fb commit 1825be32d073eb0f39d5ccbaff9eec6e0b8fc8fb Author: Dag-Erling Smørgrav AuthorDate: 2025-10-17 11:55:12 +0000 Commit: Colin Percival CommitDate: 2025-10-30 23:48:55 +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. Approved by: re (cperciva) Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D53133 (cherry picked from commit aa870a1935bccb66e02c4c31630706768a3e7d74) (cherry picked from commit b5f3f1a661ab69986c3379fa4c9c2b38785933db) --- 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 +}