From c458568feb3717a4081a7b77eefbee481a87fbfe Mon Sep 17 00:00:00 2001 From: OpenAI Date: Fri, 19 Jun 2026 12:55:26 +0000 Subject: [PATCH] nwnss: document quota test sudo and ext4 project model --- src/nwnss/nssUserspaceQuota.c | 6 +++- tests/README.md | 26 ++++++++++++++-- tests/mars_nwe_test_config.sh.example.in | 11 +++++-- .../quota/nwnss_quota_xfs_volume_test.sh.in | 31 ++++++++++++++----- tests/nwnss/quota/test_nwnss_quota.c | 2 ++ 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/nwnss/nssUserspaceQuota.c b/src/nwnss/nssUserspaceQuota.c index a2a6d85..410ef87 100644 --- a/src/nwnss/nssUserspaceQuota.c +++ b/src/nwnss/nssUserspaceQuota.c @@ -490,11 +490,15 @@ NssQuotaProviderKind_e NssQuotaProviderForOtherfsMount(const char *fsType, const char *mountOptions, int nwQuotaAvailable) { - if (nssQuotaFsTypeMatches(fsType, "xfs")) { + if (nssQuotaFsTypeMatches(fsType, "xfs") || + nssQuotaFsTypeMatches(fsType, "ext4")) { if (nssQuotaMountOptionMatches(mountOptions, "prjquota") || nssQuotaMountOptionMatches(mountOptions, "pquota")) { return NSS_QUOTA_PROVIDER_OTHERFS_LINUX_PROJECT_QUOTA; } + } + + if (nssQuotaFsTypeMatches(fsType, "xfs")) { if (nssQuotaMountOptionMatches(mountOptions, "usrquota") || nssQuotaMountOptionMatches(mountOptions, "uquota")) { return NSS_QUOTA_PROVIDER_OTHERFS_LINUX_USER_QUOTA; diff --git a/tests/README.md b/tests/README.md index e700eb2..3bac08a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -95,12 +95,32 @@ ctest -L networked --output-on-failure ``` -Optional root-only quota volume tests are also config-gated. For example, +Optional quota volume tests are also config-gated. For example, `nwnss.quota.xfs-volume` creates throw-away loop-mounted XFS images and checks that `libnwnss` detects a plain XFS mount as no Linux quota provider and an XFS -mount with `prjquota` as the Linux project-quota provider. It is skipped unless +mount with `prjquota` as the Linux project-quota provider. The provider model +recognizes Linux project quota for XFS and ext4, but this first root smoke only +creates XFS loop images because xfs_quota-style directory-tree/project testing +is the initial OtherFS approximation. The test is skipped unless `NWNSS_QUOTA_XFS_VOLUME_TEST=1` is set in the environment or the build-local -config file, and it still skips when root privileges or `mkfs.xfs` are missing. +config file. It can run as root, or as a normal user with passwordless sudo for +the small set of loop/mount commands used by the test. Do not store the root +password in `mars_nwe_test_config.sh`; use sudoers `NOPASSWD` for the test +commands or run this one test as root. + +On Gentoo, install/enable `sudo`, add the test user to `wheel`, and edit sudoers +with `visudo`. A locked-down local drop-in can be created with +`visudo -f /etc/sudoers.d/mars-nwe-tests`; adjust command paths with +`command -v mkfs.xfs mount umount true sudo` on the target system: + +```sudoers +Cmnd_Alias MARS_NWE_QUOTA_TEST = /usr/sbin/mkfs.xfs, /usr/bin/mount, /usr/bin/umount, /usr/bin/true +%wheel ALL=(root) NOPASSWD: MARS_NWE_QUOTA_TEST +``` + +If the system is not merged-/usr, use `/sbin/mkfs.xfs`, `/bin/mount`, and +`/bin/umount` instead. Keep the build-local config at mode `0600`; it may hold +NCP test passwords, but not the root password. Quota-dual/all smokes additionally need `MARS_NWE_TEST_QUOTA_SYSROOT` and `MARS_NWE_TEST_QUOTA_MOUNT`; optional variables include diff --git a/tests/mars_nwe_test_config.sh.example.in b/tests/mars_nwe_test_config.sh.example.in index c287193..02ccc69 100644 --- a/tests/mars_nwe_test_config.sh.example.in +++ b/tests/mars_nwe_test_config.sh.example.in @@ -24,10 +24,17 @@ # MARS_NWE_TEST_QUOTA_MOUNT=/mnt/mars-quota # MARS_NWE_TEST_NW_LOG=/var/log/mars-nwe.log -# Enable optional root-only XFS loop-volume quota smoke for libnwnss. -# It creates throw-away loop-mounted XFS images in TMPDIR and skips unless root. +# Enable optional XFS loop-volume quota smoke for libnwnss. +# It creates throw-away loop-mounted XFS images in TMPDIR. Linux project +# quotas are modeled for XFS and ext4, but this first root smoke only creates +# XFS loop images because xfs_quota-style directory-tree/project testing is the +# initial OtherFS approximation. The test runs as root or via passwordless +# sudo. Do not store the root password here. Configure sudoers for only the +# needed test commands, or run this single test as root. # NWNSS_QUOTA_XFS_VOLUME_TEST=1 # NWNSS_QUOTA_XFS_IMAGE_SIZE=512M +# NWNSS_QUOTA_SUDO=sudo +# NWNSS_QUOTA_SUDO_FLAGS=-n # Optional per-test knobs already consumed by existing smoke scripts. # NWFS_NCPFS_DIR_QUOTA_4K=12 diff --git a/tests/nwnss/quota/nwnss_quota_xfs_volume_test.sh.in b/tests/nwnss/quota/nwnss_quota_xfs_volume_test.sh.in index 205543b..b2cb14a 100644 --- a/tests/nwnss/quota/nwnss_quota_xfs_volume_test.sh.in +++ b/tests/nwnss/quota/nwnss_quota_xfs_volume_test.sh.in @@ -2,7 +2,9 @@ # Optional XFS quota smoke for libnwnss provider detection. # It creates two throw-away XFS test volumes: one mounted without quota options # and one mounted with project quota enabled. The test skips unless explicitly -# enabled because it needs root privileges and loop mounts. +# enabled because it needs root privileges and loop mounts. If the test is +# not run as root it uses passwordless sudo only; root passwords must not be +# stored in the build-local config file. set -eu @@ -20,13 +22,26 @@ skip() { exit "$SKIP" } +run_root() { + if [ "$(id -u)" = 0 ]; then + "$@" + else + "${NWNSS_QUOTA_SUDO:-sudo}" ${NWNSS_QUOTA_SUDO_FLAGS:--n} "$@" + fi +} + [ "${NWNSS_QUOTA_XFS_VOLUME_TEST:-0}" = 1 ] || \ skip "set NWNSS_QUOTA_XFS_VOLUME_TEST=1 to create loop-mounted XFS quota test volumes" -[ "$(id -u)" = 0 ] || skip "root privileges are required for loop mounts" command -v mkfs.xfs >/dev/null 2>&1 || skip "mkfs.xfs is not available" command -v mount >/dev/null 2>&1 || skip "mount is not available" command -v findmnt >/dev/null 2>&1 || skip "findmnt is not available" [ -x "$PROBE" ] || skip "quota mount probe helper is not built" +if [ "$(id -u)" != 0 ]; then + command -v "${NWNSS_QUOTA_SUDO:-sudo}" >/dev/null 2>&1 || \ + skip "sudo is not available and the test is not running as root" + run_root true >/dev/null 2>&1 || \ + skip "passwordless sudo is required for loop-mounted XFS quota tests" +fi TMPROOT=$(mktemp -d "${TMPDIR:-/tmp}/nwnss-quota-xfs.XXXXXX") PLAIN_IMG="$TMPROOT/plain.img" @@ -36,8 +51,8 @@ QUOTA_MNT="$TMPROOT/quota" cleanup() { set +e - mountpoint -q "$PLAIN_MNT" && umount "$PLAIN_MNT" - mountpoint -q "$QUOTA_MNT" && umount "$QUOTA_MNT" + mountpoint -q "$PLAIN_MNT" && run_root umount "$PLAIN_MNT" + mountpoint -q "$QUOTA_MNT" && run_root umount "$QUOTA_MNT" rm -rf "$TMPROOT" } trap cleanup EXIT INT TERM @@ -45,11 +60,11 @@ trap cleanup EXIT INT TERM mkdir -p "$PLAIN_MNT" "$QUOTA_MNT" truncate -s "${NWNSS_QUOTA_XFS_IMAGE_SIZE:-512M}" "$PLAIN_IMG" truncate -s "${NWNSS_QUOTA_XFS_IMAGE_SIZE:-512M}" "$QUOTA_IMG" -mkfs.xfs -f -q "$PLAIN_IMG" >/dev/null 2>&1 || skip "mkfs.xfs failed for plain image" -mkfs.xfs -f -q "$QUOTA_IMG" >/dev/null 2>&1 || skip "mkfs.xfs failed for quota image" +run_root mkfs.xfs -f -q "$PLAIN_IMG" >/dev/null 2>&1 || skip "mkfs.xfs failed for plain image" +run_root mkfs.xfs -f -q "$QUOTA_IMG" >/dev/null 2>&1 || skip "mkfs.xfs failed for quota image" -mount -o loop "$PLAIN_IMG" "$PLAIN_MNT" || skip "plain XFS loop mount failed" -mount -o loop,prjquota "$QUOTA_IMG" "$QUOTA_MNT" || skip "project-quota XFS loop mount failed" +run_root mount -o loop "$PLAIN_IMG" "$PLAIN_MNT" || skip "plain XFS loop mount failed" +run_root mount -o loop,prjquota "$QUOTA_IMG" "$QUOTA_MNT" || skip "project-quota XFS loop mount failed" plain_fstype=$(findmnt -n -o FSTYPE --target "$PLAIN_MNT") plain_opts=$(findmnt -n -o OPTIONS --target "$PLAIN_MNT") diff --git a/tests/nwnss/quota/test_nwnss_quota.c b/tests/nwnss/quota/test_nwnss_quota.c index 78bbd7e..d48199c 100644 --- a/tests/nwnss/quota/test_nwnss_quota.c +++ b/tests/nwnss/quota/test_nwnss_quota.c @@ -124,6 +124,8 @@ int main(void) NSS_QUOTA_PROVIDER_OTHERFS_LINUX_PROJECT_QUOTA); CHECK(NssQuotaProviderForOtherfsMount("xfs", "rw,pquota", 0) == NSS_QUOTA_PROVIDER_OTHERFS_LINUX_PROJECT_QUOTA); + CHECK(NssQuotaProviderForOtherfsMount("ext4", "rw,prjquota", 0) == + NSS_QUOTA_PROVIDER_OTHERFS_LINUX_PROJECT_QUOTA); CHECK(NssQuotaProviderForOtherfsMount("xfs", "rw,uquota", 0) == NSS_QUOTA_PROVIDER_OTHERFS_LINUX_USER_QUOTA); CHECK(NssQuotaProviderForOtherfsMount("ext4", "rw,usrquota", 0) ==