forked from josch/mmdebstrap
86 lines
2.7 KiB
Bash
86 lines
2.7 KiB
Bash
|
#!/bin/sh
|
||
|
|
||
|
set -eu
|
||
|
|
||
|
if [ "${MMDEBSTRAP_VERBOSITY:-1}" -ge 3 ]; then
|
||
|
set -x
|
||
|
fi
|
||
|
|
||
|
TARGET="$1"
|
||
|
|
||
|
# can_usrmerge_symlink() and can_usrmerge_symlink() are
|
||
|
# Copyright 2023 Helmut Grohne <helmut@subdivi.de>
|
||
|
# and part of the debootstrap source in /usr/share/debootstrap/functions
|
||
|
# https://salsa.debian.org/installer-team/debootstrap/-/merge_requests/96
|
||
|
# https://bugs.debian.org/104989
|
||
|
can_usrmerge_symlink() {
|
||
|
# Absolute symlinks can be relocated without problems.
|
||
|
test "${2#/}" = "$2" || return 0
|
||
|
while :; do
|
||
|
if test "${2#/}" != "$2"; then
|
||
|
# Handle double-slashes.
|
||
|
set -- "$1" "${2#/}"
|
||
|
elif test "${2#./}" != "$2"; then
|
||
|
# Handle ./ inside a link target.
|
||
|
set -- "$1" "${2#./}"
|
||
|
elif test "$2" = ..; then
|
||
|
# A parent directory symlink is ok if it does not
|
||
|
# cross the top level directory.
|
||
|
test "${1%/*/*}" != "$1" -a -n "${1%/*/*}"
|
||
|
return $?
|
||
|
elif test "${2#../}" != "$2"; then
|
||
|
# Symbolic link crossing / cannot be moved safely.
|
||
|
# This is prohibited by Debian Policy 10.5.
|
||
|
test "${1%/*/*}" = "$1" -o -z "${1%/*/*}" && return 1
|
||
|
set -- "${1%/*}" "${2#../}"
|
||
|
else
|
||
|
# Consider the symlink ok if its target does not
|
||
|
# contain a parent directory. When we fail here,
|
||
|
# the link target is non-minimal and doesn't happen
|
||
|
# in the archive.
|
||
|
test "${2#*/../}" = "$2"
|
||
|
return $?
|
||
|
fi
|
||
|
done
|
||
|
}
|
||
|
|
||
|
merge_usr_entry() {
|
||
|
# shellcheck disable=SC3043
|
||
|
local entry canon
|
||
|
canon="$TARGET/usr/${1#"$TARGET/"}"
|
||
|
test -h "$canon" &&
|
||
|
error 1 USRMERGEFAIL "cannot move %s as its destination exists as a symlink" "${1#"$TARGET"}"
|
||
|
if ! test -e "$canon"; then
|
||
|
mv "$1" "$canon"
|
||
|
return 0
|
||
|
fi
|
||
|
test -d "$1" ||
|
||
|
error 1 USRMERGEFAIL "cannot move non-directory %s as its destination exists" "${1#"$TARGET"}"
|
||
|
test -d "$canon" ||
|
||
|
error 1 USRMERGEFAIL "cannot move directory %s as its destination is not a directory" "${1#"$TARGET"}"
|
||
|
for entry in "$1/"* "$1/."*; do
|
||
|
# Some shells return . and .. on dot globs.
|
||
|
test "${entry%/.}" != "${entry%/..}" && continue
|
||
|
if test -h "$entry" && ! can_usrmerge_symlink "${entry#"$TARGET"}" "$(readlink "$entry")"; then
|
||
|
error 1 USRMERGEFAIL "cannot move relative symlink crossing top-level directory" "${entry#"$TARGET"}"
|
||
|
fi
|
||
|
# Ignore glob match failures
|
||
|
if test "${entry%'/*'}" != "${entry%'/.*'}" && ! test -e "$entry"; then
|
||
|
continue
|
||
|
fi
|
||
|
merge_usr_entry "$entry"
|
||
|
done
|
||
|
rmdir "$1"
|
||
|
}
|
||
|
|
||
|
# This is list includes all possible multilib directories. It must be
|
||
|
# updated when new multilib directories are being added. Hopefully,
|
||
|
# all new architectures use multiarch instead, so we never get to
|
||
|
# update this.
|
||
|
for dir in bin lib lib32 lib64 libo32 libx32 sbin; do
|
||
|
test -h "$TARGET/$dir" && continue
|
||
|
test -e "$TARGET/$dir" || continue
|
||
|
merge_usr_entry "$TARGET/$dir"
|
||
|
ln -s "usr/$dir" "$TARGET/$dir"
|
||
|
done
|