2021-02-25 11:44:07 +01:00
|
|
|
#!/bin/bash
|
|
|
|
# based on code from dracut convertfs.sh
|
|
|
|
|
|
|
|
ROOT=
|
|
|
|
|
2021-06-08 15:14:14 +02:00
|
|
|
is_usrmerged() {
|
|
|
|
local r=1
|
|
|
|
for dir in bin sbin lib lib64; do
|
|
|
|
[ -d "$ROOT/$dir" ] || continue
|
|
|
|
[ -L "$ROOT/$dir" ] || return 1
|
|
|
|
r=0
|
|
|
|
done
|
|
|
|
return "$r"
|
|
|
|
}
|
|
|
|
|
|
|
|
# check if there's anything to do
|
|
|
|
is_usrmerged && exit 0
|
|
|
|
|
2021-02-25 11:44:07 +01:00
|
|
|
# the package is installed with AutoReq off, so no guarantee that
|
|
|
|
# coreutils actually works
|
2021-06-08 11:47:14 +02:00
|
|
|
if ! { cp --help && find --help; } > /dev/null; then
|
2021-02-25 11:44:07 +01:00
|
|
|
echo "tools not functional, exit"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# clean up after ourselves no matter how we die.
|
|
|
|
cleanup() {
|
2021-06-08 15:14:14 +02:00
|
|
|
echo "UsrMerge conversion failed, cleaning up"
|
2021-02-25 11:44:07 +01:00
|
|
|
for dir in bin sbin lib lib64; do
|
|
|
|
rm -rf -- "$ROOT/usr/${dir}.usrmerge"
|
|
|
|
done
|
2021-06-07 11:03:29 +02:00
|
|
|
echo "!!! ATTENTION: Do NOT proceed if you see this message during"
|
|
|
|
echo "!!! distribution upgrade. Chances are high that your system might"
|
|
|
|
echo "!!! break beyond repair if you do."
|
2021-02-25 11:44:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
trap 'ret=$?; [[ $ret -ne 0 ]] && cleanup;exit $ret;' EXIT
|
|
|
|
trap 'exit 1;' SIGINT
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
2021-06-08 15:14:14 +02:00
|
|
|
if [ "$(stat -f -c %T "${ROOT:-/}")" = "overlayfs" ]; then
|
|
|
|
echo "UsrMerge conversion does not work on overlayfs"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
CP_HARDLINK="-l"
|
2021-06-02 17:29:59 +02:00
|
|
|
while read dev mp other; do
|
2021-06-08 15:14:14 +02:00
|
|
|
[ "$mp" = "$ROOT/usr" ] && CP_HARDLINK=""
|
2021-06-02 17:29:59 +02:00
|
|
|
for dir in bin sbin lib lib64; do
|
2021-06-08 15:14:14 +02:00
|
|
|
[ -d "$ROOT/$dir" ] || continue
|
2021-06-02 17:29:59 +02:00
|
|
|
if [ "${mp#$ROOT/$dir}" != "$mp" ] || [ "${mp#$ROOT/usr/$dir}" != "$mp" ]; then
|
|
|
|
echo "Please unmount $mp before the conversion"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
done < /proc/mounts
|
|
|
|
|
2021-02-25 11:44:07 +01:00
|
|
|
# merge / and /usr in new dir in /usr
|
|
|
|
for dir in bin sbin lib lib64; do
|
|
|
|
rm -rf -- "$ROOT/usr/${dir}.usrmerge"
|
|
|
|
[[ -L "$ROOT/$dir" ]] && continue
|
|
|
|
[[ -d "$ROOT/$dir" ]] || continue
|
|
|
|
echo "Make a copy of \`$ROOT/$dir'."
|
|
|
|
[[ -d "$ROOT/$dir" ]] \
|
2021-06-07 11:03:29 +02:00
|
|
|
&& cp -ax $CP_HARDLINK "$ROOT/$dir" "$ROOT/usr/${dir}.usrmerge"
|
2021-03-18 14:44:16 +01:00
|
|
|
# cp can't handle copying a dir over non-directories. So move
|
|
|
|
# those away in advance. Happened with /lib/udev existing as
|
|
|
|
# link on older distros
|
|
|
|
while read d; do
|
|
|
|
f="$ROOT/usr/$dir.usrmerge/$d"
|
2021-10-07 15:00:27 +02:00
|
|
|
if test -L "$f" -o \( -e "$f" -a ! -d "$f" \); then
|
2021-03-18 14:44:16 +01:00
|
|
|
echo "Warning: /$dir/$d conflicts with directory /usr/$dir/$d and will be removed"
|
|
|
|
rm -rf "$f.usrmerge~"
|
|
|
|
mv "$f" "$f.usrmerge~"
|
|
|
|
fi
|
2021-06-02 17:29:59 +02:00
|
|
|
done < <(find "$ROOT/usr/$dir" -xdev -type d -printf "%P\n" )
|
2021-02-25 11:44:07 +01:00
|
|
|
echo "Merge the copy with \`$ROOT/usr/$dir'."
|
|
|
|
[[ -d "$ROOT/usr/${dir}.usrmerge" ]] \
|
|
|
|
|| mkdir -p "$ROOT/usr/${dir}.usrmerge"
|
2021-06-16 10:20:00 +02:00
|
|
|
cp -axT -l --backup --suffix=.usrmerge~ "$ROOT/usr/$dir" "$ROOT/usr/${dir}.usrmerge"
|
2021-02-25 11:44:07 +01:00
|
|
|
echo "Clean up duplicates in \`$ROOT/usr/$dir'."
|
|
|
|
# delete all symlinks that have been backed up. /usr versions
|
|
|
|
# override / ones
|
2021-06-02 17:29:59 +02:00
|
|
|
find "$ROOT/usr/${dir}.usrmerge" -xdev -type l -name '*.usrmerge~' -delete || :
|
2021-02-25 11:44:07 +01:00
|
|
|
# in rare cases the symlinks may point from /usr to /, so remove
|
|
|
|
# the link in that case
|
|
|
|
while read file; do
|
|
|
|
o=${file%%.usrmerge~}
|
|
|
|
[ -L "$o" ] && mv -f "$file" "$o"
|
|
|
|
done < <(find "$ROOT/usr/${dir}.usrmerge" \
|
2021-06-02 17:29:59 +02:00
|
|
|
-xdev -name '*.usrmerge~' -type f)
|
2021-02-25 11:44:07 +01:00
|
|
|
done
|
|
|
|
# switch over merged dirs in /usr
|
|
|
|
for dir in bin sbin lib lib64; do
|
|
|
|
if [ -d "$ROOT/usr/${dir}.usrmerge" ]; then
|
|
|
|
echo "Switch to new \`$ROOT/usr/$dir'."
|
|
|
|
/usr/libexec/xmv "$ROOT/usr/${dir}.usrmerge" "$ROOT/usr/$dir"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
# replace dirs in / with links to /usr
|
|
|
|
for dir in bin sbin lib lib64; do
|
|
|
|
if [ ! -L "$ROOT/$dir" -a -d "$ROOT/$dir" ]; then
|
|
|
|
echo "Create \`$ROOT/$dir' symlink."
|
2021-06-02 17:29:59 +02:00
|
|
|
rm --one-file-system -rf "$ROOT/${dir}.usrmerge" || :
|
2021-02-25 11:44:07 +01:00
|
|
|
ln -s usr/$dir "$ROOT/${dir}.usrmerge"
|
|
|
|
/usr/libexec/xmv "$ROOT/$dir" "$ROOT/${dir}.usrmerge"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
echo "Clean up backup files."
|
|
|
|
# everything seems to work; cleanup
|
|
|
|
for dir in bin sbin lib lib64; do
|
|
|
|
for pfx in usr/ /; do
|
|
|
|
# if we get killed in the middle of "rm -rf", ensure not to leave
|
|
|
|
# an incomplete directory, which is moved back by cleanup()
|
|
|
|
d="$ROOT/${pfx}${dir}.usrmerge"
|
|
|
|
if [ -d "$d" ]; then
|
|
|
|
echo "$d ..."
|
|
|
|
mv "$d" "$d~"
|
2021-06-02 17:29:59 +02:00
|
|
|
rm --one-file-system -rf "$d~"
|
2021-02-25 11:44:07 +01:00
|
|
|
fi
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
# XXX: confirm this is needed
|
|
|
|
for dir in lib lib64; do
|
|
|
|
[[ -d "$ROOT/$dir" ]] || continue
|
|
|
|
for lib in "$ROOT"/usr/${dir}/lib*.so*.usrmerge~; do
|
|
|
|
[[ -f $lib ]] || continue
|
|
|
|
mv -v $lib ${lib/.so/_so}
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
set +e
|
|
|
|
|
|
|
|
echo "Run ldconfig."
|
2021-06-02 15:25:33 +02:00
|
|
|
ldconfig -r "$ROOT" || :
|