Scope preserved NFS no_root_squash warning to image staging export
-
Summary
When STORAGE_rebuild_nfs_exports != yes, configureNFS() currently warns if no_root_squash appears anywhere in /etc/exports.That produces a false warning when /images/dev is already configured correctly with all_squash,anonuid=…,anongid=…, but an unrelated read-only export (for example a mounted Linux ISO tree) intentionally uses no_root_squash.
Change
Add nfsDevExportHasNoRootSquash() and scope the check to exactly:${STORAGE_image_share_path}/dev
The warning still appears when the image staging export itself uses no_root_squash, but unrelated exports no longer trigger it.
Regression coverage
tests/nfs-preserved-exports-warning.test.sh covers:- safe /images/dev plus an ISO export using no_root_squash -> no warning condition
- /images/dev using no_root_squash -> warning condition
- similarly named paths and commented lines -> ignored
- configureNFS() actually uses the scoped helper
Reproduction
Example preserved exports:
/images *(ro,sync,no_wdelay,subtree_check,insecure_locks,all_squash,anonuid=1002,anongid=1002,fsid=0)
/images/dev *(rw,async,no_wdelay,subtree_check,all_squash,anonuid=1002,anongid=1002,fsid=1)
/var/www/html/ISO/Ubuntu/26.04X64/ *(ro,sync,no_wdelay,insecure_locks,no_root_squash,insecure)The existing global grep -q “no_root_squash” “$nfsconfig” reports that captures land as root even though the /images/dev export is already ownership-safe.
diff --git a/lib/common/functions.sh b/lib/common/functions.sh
— a/lib/common/functions.sh
+++ b/lib/common/functions.sh
@@ -1,3 +1,14 @@
+nfsDevExportHasNoRootSquash() {- local config=“$1”
- local devpath=“${STORAGE_image_share_path%/}/dev”
- [[ -f “$config” ]] || return 1
- awk -v path=“$devpath” ’
-
$1 == path && /(^|[,(])no_root_squash([,)]|$)/ { -
found=1 -
} -
END { exit !found } - ’ “$config”
+}
configureNFS() {
dots “Setting up NFS configuration file”
if [[ -f “/etc/nfs.conf” ]]; then
@@ -25,7 +36,7 @@
dots “Setting up exports file”
if [[ ${STORAGE_rebuild_nfs_exports} != yes ]]; then
echo “Skipped”
-
if [[ -f "$nfsconfig" ]] && grep -q "no_root_squash" "$nfsconfig"; then
-
if nfsDevExportHasNoRootSquash "$nfsconfig"; then echo echo " ** WARNING: ${nfsconfig} still exports with no_root_squash." echo " ** Captures land as root, so moving the image out of"
diff --git a/tests/nfs-preserved-exports-warning.test.sh b/tests/nfs-preserved-exports-warning.test.sh
new file mode 100755
— /dev/null
+++ b/tests/nfs-preserved-exports-warning.test.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# The preserved-exports warning must only inspect the image staging export.
+# An unrelated read-only ISO export may intentionally use no_root_squash and
+# must not make FOG claim that /images/dev will capture files as root.
+#
+# Usage: bash tests/nfs-preserved-exports-warning.test.sh
+
+root=$(cd – “$(dirname – “${BASH_SOURCE[0]}”)/…” && pwd)
+functions=“$root/lib/common/functions.sh”
+
+pass=0
+fail=0
+
+pass_case() {- pass=$((pass + 1))
+}
+fail_case() {
- fail=$((fail + 1))
- printf ’ FAIL %s\n’ “$1”
+}
+if [[ ! -r $functions ]]; then
- echo “FAIL: cannot read $functions” >&2
- exit 1
+fi
+# Load only the helper under test. Sourcing all of functions.sh would make
+# this small unit test depend on the installer’s global setup.
+helper=$(- awk ’
-
/^nfsDevExportHasNoRootSquash\(\) \{/ { emit=1 } -
emit { print } -
emit && /^}/ { exit } - ’ “$functions”
+)
+if [[ -z $helper ]]; then - echo “FAIL: nfsDevExportHasNoRootSquash() not found” >&2
- exit 1
+fi
+eval “$helper”
+tmp=$(mktemp)
+trap ‘rm -f “$tmp”’ EXIT
+STORAGE_image_share_path=/images
+
+cat > “$tmp” <<‘EOF_CASE’
+/images *(ro,sync,all_squash,anonuid=1002,anongid=1002,fsid=0)
+/images/dev *(rw,async,all_squash,anonuid=1002,anongid=1002,fsid=1)
+/var/www/html/ISO/Ubuntu/26.04X64/ *(ro,sync,no_root_squash,insecure)
+EOF_CASE
+if nfsDevExportHasNoRootSquash “$tmp”; then- fail_case “unrelated ISO no_root_squash does not trigger warning”
+else - pass_case
+fi
+cat > “$tmp” <<‘EOF_CASE’
+/images *(ro,sync,all_squash,anonuid=1002,anongid=1002,fsid=0)
+/images/dev *(rw,async,no_root_squash,fsid=1)
+EOF_CASE
+if nfsDevExportHasNoRootSquash “$tmp”; then- pass_case
+else - fail_case “/images/dev no_root_squash triggers warning”
+fi
+cat > “$tmp” <<‘EOF_CASE’
+/images/dev *(rw,async,all_squash,anonuid=1002,anongid=1002,fsid=1)
+/images-old/dev *(rw,async,no_root_squash,fsid=2)
+# /images/dev *(rw,no_root_squash)
+EOF_CASE
+if nfsDevExportHasNoRootSquash “$tmp”; then- fail_case “prefix paths and comments do not trigger warning”
+else - pass_case
+fi
+if ! grep -q ‘if nfsDevExportHasNoRootSquash “$nfsconfig”; then’ “$functions”; then
- echo " FAIL configureNFS does not use nfsDevExportHasNoRootSquash" >&2
- fail=$((fail + 1))
+else - pass=$((pass + 1))
+fi
+echo “ok $pass”
+[[ $fail -eq 0 ]] || { echo “FAIL ($fail of $((pass + fail)))” >&2; exit 1; }
+exit 0