summaryrefslogtreecommitdiffstats
path: root/modules.d/30convertfs/convertfs.sh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xmodules.d/30convertfs/convertfs.sh193
1 files changed, 193 insertions, 0 deletions
diff --git a/modules.d/30convertfs/convertfs.sh b/modules.d/30convertfs/convertfs.sh
new file mode 100755
index 0000000..58fa56d
--- /dev/null
+++ b/modules.d/30convertfs/convertfs.sh
@@ -0,0 +1,193 @@
+#!/bin/bash
+
+type ismounted > /dev/null 2>&1 || . /lib/dracut-lib.sh
+
+ROOT="$1"
+
+if [[ ! -d $ROOT ]]; then
+ echo "Usage: $0 <rootdir>"
+ exit 1
+fi
+
+if [[ $ROOT -ef / ]]; then
+ echo "Can't convert the running system."
+ echo "Please boot with 'rd.convertfs' on the kernel command line,"
+ echo "to update with the help of the initramfs,"
+ echo "or run this script from a rescue system."
+ exit 1
+fi
+
+while [[ $ROOT != "${ROOT%/}" ]]; do
+ ROOT=${ROOT%/}
+done
+
+if [ ! -L "$ROOT"/var/run -a -e "$ROOT"/var/run ]; then
+ echo "Converting /var/run to symlink"
+ mv -f "$ROOT"/var/run "$ROOT"/var/run.runmove~
+ ln -sfn ../run "$ROOT"/var/run
+fi
+
+if [ ! -L "$ROOT"/var/lock -a -e "$ROOT"/var/lock ]; then
+ echo "Converting /var/lock to symlink"
+ mv -f "$ROOT"/var/lock "$ROOT"/var/lock.lockmove~
+ ln -sfn ../run/lock "$ROOT"/var/lock
+fi
+
+needconvert() {
+ for dir in "$ROOT/bin" "$ROOT/sbin" "$ROOT/lib" "$ROOT/lib64"; do
+ if [[ -e $dir ]]; then
+ [[ -L $dir ]] || return 0
+ fi
+ done
+ return 1
+}
+
+if ! [ -e "$ROOT/usr/bin" ]; then
+ echo "$ROOT/usr/bin does not exist!"
+ echo "Make sure, the kernel command line has enough information"
+ echo "to mount /usr (man dracut.cmdline)"
+ exit 1
+fi
+
+if ! needconvert; then
+ echo "Your system is already converted."
+ exit 0
+fi
+
+testfile="$ROOT/.usrmovecheck$$"
+rm -f -- "$testfile"
+: > "$testfile"
+if [[ ! -e $testfile ]]; then
+ echo "Cannot write to $ROOT/"
+ exit 1
+fi
+rm -f -- "$testfile"
+
+testfile="$ROOT/usr/.usrmovecheck$$"
+rm -f -- "$testfile"
+: > "$testfile"
+if [[ ! -e $testfile ]]; then
+ echo "Cannot write to $ROOT/usr/"
+ exit 1
+fi
+rm -f -- "$testfile"
+
+find_mount() {
+ local dev wanted_dev
+ wanted_dev="$(readlink -e -q "$1")"
+ while read -r dev _ || [ -n "$dev" ]; do
+ [ "$dev" = "$wanted_dev" ] && echo "$dev" && return 0
+ done < /proc/mounts
+ return 1
+}
+
+# clean up after ourselves no matter how we die.
+cleanup() {
+ echo "Something failed. Move back to the original state"
+ for dir in "$ROOT/bin" "$ROOT/sbin" "$ROOT/lib" "$ROOT/lib64" \
+ "$ROOT/usr/bin" "$ROOT/usr/sbin" "$ROOT/usr/lib" \
+ "$ROOT/usr/lib64"; do
+ [[ -d "${dir}.usrmove-new" ]] && rm -fr -- "${dir}.usrmove-new"
+ if [[ -d "${dir}.usrmove-old" ]]; then
+ mv "$dir" "${dir}.del~"
+ mv "${dir}.usrmove-old" "$dir"
+ rm -fr -- "${dir}.del~"
+ fi
+ done
+}
+
+trap 'ret=$?; [[ $ret -ne 0 ]] && cleanup;exit $ret;' EXIT
+trap 'exit 1;' SIGINT
+
+ismounted "$ROOT/usr" || CP_HARDLINK="-l"
+
+set -e
+
+# merge / and /usr in new dir in /usr
+for dir in bin sbin lib lib64; do
+ rm -rf -- "$ROOT/usr/${dir}.usrmove-new"
+ [[ -L "$ROOT/$dir" ]] && continue
+ [[ -d "$ROOT/$dir" ]] || continue
+ echo "Make a copy of \`$ROOT/usr/$dir'."
+ [[ -d "$ROOT/usr/$dir" ]] \
+ && cp -ax -l "$ROOT/usr/$dir" "$ROOT/usr/${dir}.usrmove-new"
+ echo "Merge the copy with \`$ROOT/$dir'."
+ [[ -d "$ROOT/usr/${dir}.usrmove-new" ]] \
+ || mkdir -p "$ROOT/usr/${dir}.usrmove-new"
+ cp -axT $CP_HARDLINK --backup --suffix=.usrmove~ "$ROOT/$dir" "$ROOT/usr/${dir}.usrmove-new"
+ echo "Clean up duplicates in \`$ROOT/usr/$dir'."
+ # delete all symlinks that have been backed up
+ find "$ROOT/usr/${dir}.usrmove-new" -type l -name '*.usrmove~' -delete || :
+ # replace symlink with backed up binary
+ # shellcheck disable=SC2156
+ find "$ROOT/usr/${dir}.usrmove-new" \
+ -name '*.usrmove~' \
+ -type f \
+ -exec bash -c 'p="{}";o=${p%%%%.usrmove~};
+ [[ -L "$o" ]] && mv -f "$p" "$o"' ';' || :
+done
+# switch over merged dirs in /usr
+for dir in bin sbin lib lib64; do
+ [[ -d "$ROOT/usr/${dir}.usrmove-new" ]] || continue
+ echo "Switch to new \`$ROOT/usr/$dir'."
+ rm -fr -- "$ROOT/usr/${dir}.usrmove-old"
+ mv "$ROOT/usr/$dir" "$ROOT/usr/${dir}.usrmove-old"
+ mv "$ROOT/usr/${dir}.usrmove-new" "$ROOT/usr/$dir"
+done
+
+# replace dirs in / with links to /usr
+for dir in bin sbin lib lib64; do
+ [[ -L "$ROOT/$dir" ]] && continue
+ [[ -d "$ROOT/$dir" ]] || continue
+ echo "Create \`$ROOT/$dir' symlink."
+ rm -fr -- "$ROOT/${dir}.usrmove-old" || :
+ mv "$ROOT/$dir" "$ROOT/${dir}.usrmove-old"
+ ln -sfn usr/$dir "$ROOT/$dir"
+done
+
+echo "Clean up backup files."
+# everything seems to work; cleanup
+for dir in bin sbin lib lib64; 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/usr/${dir}.usrmove-old" ]] \
+ && mv "$ROOT/usr/${dir}.usrmove-old" "$ROOT/usr/${dir}.usrmove-old~"
+ [[ -d "$ROOT/${dir}.usrmove-old" ]] \
+ && mv "$ROOT/${dir}.usrmove-old" "$ROOT/${dir}.usrmove-old~"
+done
+
+for dir in bin sbin lib lib64; do
+ if [[ -d "$ROOT/usr/${dir}.usrmove-old~" ]]; then
+ rm -rf -- "$ROOT/usr/${dir}.usrmove-old~"
+ fi
+
+ if [[ -d "$ROOT/${dir}.usrmove-old~" ]]; then
+ rm -rf -- "$ROOT/${dir}.usrmove-old~"
+ fi
+done
+
+for dir in lib lib64; do
+ [[ -d "$ROOT/$dir" ]] || continue
+ for lib in "$ROOT"/usr/"${dir}"/lib*.so*.usrmove~; do
+ [[ -f $lib ]] || continue
+ mv "$lib" "${lib/.so/_so}"
+ done
+done
+
+set +e
+
+echo "Run ldconfig."
+ldconfig -r "$ROOT"
+
+if [[ -f "$ROOT"/etc/selinux/config ]]; then
+ # shellcheck disable=SC1090
+ . "$ROOT"/etc/selinux/config
+fi
+
+if [ -n "$(command -v setfiles)" ] && [ "$SELINUX" != "disabled" ] && [ -f /etc/selinux/"${SELINUXTYPE}"/contexts/files/file_contexts ]; then
+ echo "Fixing SELinux labels"
+ setfiles -r "$ROOT" -p /etc/selinux/"${SELINUXTYPE}"/contexts/files/file_contexts "$ROOT"/sbin "$ROOT"/bin "$ROOT"/lib "$ROOT"/lib64 "$ROOT"/usr/lib "$ROOT"/usr/lib64 "$ROOT"/etc/ld.so.cache "$ROOT"/var/cache/ldconfig || :
+fi
+
+echo "Done."
+exit 0