support/scripts: fix and restrict conditions to accept merged dirs

Currently, we accept that the merged usr is backward, i.e. that the
/usr/bin, /usr/sbin, and /usr/lib entries be symlinks to, resp., /bin,
/sbin, and /lib. We also allow either entries to be symlinks to other
parts of the root. Both are accepted despite the comment at the top of
the script explaining what should be accepted.

However, a properly merged usr is the other way around: /bin, /sbin, and
/lib are the symlinks to resp. /usr/bin, /usr/sbin, and /usr/lib, which
are actual directories.

Fix the check-merged-usr script accordingly: implement the test as we
mean it, by testing the conditions rather than resorting to a convoluted
and incorrect use of stat(1).

Even though the split between test_dir() and test_merged() seems
superfluous, it'll come useful when we introduce support for merged-bin
in a later patch.

For skeletons, we require that the directories do exist, while we allow
them to be missing for overlays; indeed, it is perfectly legit to
provide an overlay that only contains totally unrelated directories
(e.g. /var/www to populate a webroot for example).

Extend the heading-comment to be more explicit (and drop '/' as there is
nothing to say about it).

Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Signed-off-by: Romain Naour <romain.naour@smile.fr>
This commit is contained in:
Yann E. MORIN
2025-09-01 11:01:17 +02:00
committed by Romain Naour
parent 1187c34d88
commit 4da66e8130

View File

@@ -2,13 +2,14 @@
#
# Check if a given custom skeleton or overlay complies to the merged /usr
# requirements:
# /
# /bin -> usr/bin
# /lib -> usr/lib
# /sbin -> usr/sbin
# /usr/bin/
# /usr/lib/
# /usr/sbin/
# /bin missing, or a relative symlink to usr/bin
# /lib missing, or a relative symlink to usr/lib
# /sbin missing, or a relative symlink to usr/sbin
# /usr/bin/ missing*, or an existing directory; not a symlink
# /usr/lib/ missing*, or an existing directory; not a symlink
# /usr/sbin/ missing*, or an existing directory; not a symlink
#
# *: must be present for skeletons, can be missing for overlays
#
# Input:
# --type TYPE the type of root to check: 'skeleton' or 'overlay'
@@ -17,7 +18,7 @@
# stdout: the list of non-compliant paths (empty if compliant).
# Exit code:
# 0: in case of success (stdout will be empty)
# !0: if any path is improperly merged
# !0: if any directory to check is improperly merged
#
opts="type:"
@@ -38,6 +39,12 @@ while :; do
esac
done
if [ "${type}" = "skeleton" ]; then
strict=true
else
strict=false
fi
report_error() {
local type="${1}"
local root="${2}"
@@ -54,44 +61,52 @@ report_error() {
is_success=false
}
# Extract the inode numbers for all of those directories. In case any is
# a symlink, we want to get the inode of the pointed-to directory, so we
# append '/.' to be sure we get the target directory. Since the symlinks
# can be anyway (/bin -> /usr/bin or /usr/bin -> /bin), we do that for
# each of them.
#
is_valid_merged() {
local root="${1}"
local dir1="${2}"
local dir2="${3}"
local inode1 inode2
inode1="$(stat -c '%i' "${root}${dir1}/." 2>/dev/null)"
inode2="$(stat -c '%i' "${root}${dir2}/." 2>/dev/null)"
test -z "${inode1}" || test "${inode1}" = "${inode2}"
}
test_merged() {
local type="${1}"
local root="${2}"
local dir1="${3}"
local dir2="${4}"
local base="${3}"
local dir1="${4}"
local dir2="${5}"
if ! is_valid_merged "${root}" "${dir1}" "${dir2}"; then
report_error "${type}" "${root}" \
'%s should be missing, or be a relative symlink to %s\n' \
"${dir1}" "${dir2}"
if ! test -e "${root}${base}${dir1}"; then
return 0
elif [ "$(readlink "${root}${base}${dir1}")" = "${dir2}" ]; then
return 0
fi
# Otherwise, this directory is not merged
report_error "${type}" "${root}" \
'%s%s should be missing, or be a relative symlink to %s\n' \
"${base}" "${dir1}" "${dir2}"
}
test_dir() {
local type="${1}"
local root="${2}"
local base="${3}"
local dir="${4}"
if ! test -e "${root}${base}${dir}" && ! ${strict}; then
return 0
elif test -d "${root}${base}${dir}" && ! test -L "${root}${base}${dir}"; then
return 0
fi
# Otherwise, this entry is not a proper directory
report_error "${type}" "${root}" \
"%s%s should exist, be a directory, and not be a symlink\n" \
"${base}" "${dir}"
}
is_success=true
for root; do
first=true
test_merged "${type}" "${root}" "/lib" "/usr/lib"
test_merged "${type}" "${root}" "/bin" "/usr/bin"
test_merged "${type}" "${root}" "/sbin" "/usr/sbin"
test_dir "${type}" "${root}" "/" "usr/bin"
test_dir "${type}" "${root}" "/" "usr/lib"
test_dir "${type}" "${root}" "/" "usr/sbin"
test_merged "${type}" "${root}" "/" "bin" "usr/bin"
test_merged "${type}" "${root}" "/" "lib" "usr/lib"
test_merged "${type}" "${root}" "/" "sbin" "usr/sbin"
done
${is_success}