From 81fced01665d93a452486fa7f747ae1c9d1295d53211a1dcf6ca9e0fb891bb4e Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Wed, 2 Jun 2021 13:04:49 +0000 Subject: [PATCH 1/7] Accepting request 896791 from home:haasn:branches:Base:System - add fallback for filesystems without renameat2 This change makes it succeed successfully on my system, which has a ZFS rootfs (so no renameat2). OBS-URL: https://build.opensuse.org/request/show/896791 OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=11 --- compat-usrmerge.changes | 5 +++++ xmv.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index 6a2d438..eb5757f 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Jun 1 23:27:08 UTC 2021 - Niklas Haas + +- add fallback for filesystems without renameat2 + ------------------------------------------------------------------- Thu Mar 25 09:50:48 UTC 2021 - Ludwig Nussel diff --git a/xmv.c b/xmv.c index f7c31a4..d29bae5 100644 --- a/xmv.c +++ b/xmv.c @@ -66,10 +66,34 @@ int main(int argc, char** argv) if (argc-optind < 2) help(argv[0], 1); - r = syscall (SYS_renameat2, AT_FDCWD, argv[optind], AT_FDCWD, argv[optind+1], RENAME_EXCHANGE); + const char *source = argv[optind], *target = argv[optind+1]; + r = syscall (SYS_renameat2, AT_FDCWD, source, AT_FDCWD, target, RENAME_EXCHANGE); if (r < 0) { - perror("renameat2"); - return 1; + if (errno != EINVAL) { + perror("renameat2"); + return 1; + } + + /* Fallback for systems without renameat2 support */ + char *tmp; + r = asprintf(&tmp, "%s.XXXXXX", target); + if (r < 0) { + perror("asprintf"); + return 1; + } + mktemp(tmp); + + r = renameat(AT_FDCWD, target, AT_FDCWD, tmp); + if (!r) + r = renameat(AT_FDCWD, source, AT_FDCWD, target); + if (!r) + r = renameat(AT_FDCWD, tmp, AT_FDCWD, source); + free(tmp); + + if (r < 0) { + perror("renameat"); + return 1; + } } return 0; From ba81243db79a879c52916703e67c6a52fc1264d306c172931e302d11f4fd9177 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Wed, 2 Jun 2021 13:25:33 +0000 Subject: [PATCH 2/7] avoid allocation OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=12 --- convertfs | 8 +------- xmv.c | 11 +++++++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/convertfs b/convertfs index 8126a2c..b2a8c27 100644 --- a/convertfs +++ b/convertfs @@ -105,10 +105,4 @@ done set +e echo "Run ldconfig." -ldconfig -r "$ROOT" - -#. $ROOT/etc/selinux/config -#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 +ldconfig -r "$ROOT" || : diff --git a/xmv.c b/xmv.c index d29bae5..d3bc20d 100644 --- a/xmv.c +++ b/xmv.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifndef RENAME_EXCHANGE # define RENAME_EXCHANGE (1 << 1) @@ -74,13 +75,16 @@ int main(int argc, char** argv) return 1; } - /* Fallback for systems without renameat2 support */ - char *tmp; - r = asprintf(&tmp, "%s.XXXXXX", target); + // Fallback for systems without renameat2 support + puts("!!! WARNING: rename2 RENAME_EXCHANGE not supported !!!"); + puts("!!! fallback to unsafe rename !!!"); + char tmp[PATH_MAX]; + r = snprintf(tmp, sizeof(tmp), "%s.XXXXXX", target); if (r < 0) { perror("asprintf"); return 1; } + // not intended to be use in /tmp so good enough mktemp(tmp); r = renameat(AT_FDCWD, target, AT_FDCWD, tmp); @@ -88,7 +92,6 @@ int main(int argc, char** argv) r = renameat(AT_FDCWD, source, AT_FDCWD, target); if (!r) r = renameat(AT_FDCWD, tmp, AT_FDCWD, source); - free(tmp); if (r < 0) { perror("renameat"); From 4090c927d8425e6f66a4a3c598b3cd9c515c288989f9d78ff9acf47f36f39098 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Wed, 2 Jun 2021 15:29:59 +0000 Subject: [PATCH 3/7] - exit early if one of the affected directories has mountpoint beneath it OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=13 --- compat-usrmerge.changes | 6 ++++++ convertfs | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index eb5757f..f7108d0 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Wed Jun 2 15:29:15 UTC 2021 - Ludwig Nussel + +- exit early if one of the affected directories has mountpoint + beneath it + ------------------------------------------------------------------- Tue Jun 1 23:27:08 UTC 2021 - Niklas Haas diff --git a/convertfs b/convertfs index b2a8c27..2a2a2fc 100644 --- a/convertfs +++ b/convertfs @@ -25,6 +25,15 @@ mountpoint -q "$ROOT/usr" || CP_HARDLINK="-l" set -e +while read dev mp other; do + for dir in bin sbin lib lib64; do + 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 + # merge / and /usr in new dir in /usr for dir in bin sbin lib lib64; do rm -rf -- "$ROOT/usr/${dir}.usrmerge" @@ -43,7 +52,7 @@ for dir in bin sbin lib lib64; do rm -rf "$f.usrmerge~" mv "$f" "$f.usrmerge~" fi - done < <(find "$ROOT/usr/$dir" -type d -printf "%P\n" ) + done < <(find "$ROOT/usr/$dir" -xdev -type d -printf "%P\n" ) echo "Merge the copy with \`$ROOT/usr/$dir'." [[ -d "$ROOT/usr/${dir}.usrmerge" ]] \ || mkdir -p "$ROOT/usr/${dir}.usrmerge" @@ -51,14 +60,14 @@ for dir in bin sbin lib lib64; do echo "Clean up duplicates in \`$ROOT/usr/$dir'." # delete all symlinks that have been backed up. /usr versions # override / ones - find "$ROOT/usr/${dir}.usrmerge" -type l -name '*.usrmerge~' -delete || : + find "$ROOT/usr/${dir}.usrmerge" -xdev -type l -name '*.usrmerge~' -delete || : # 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" \ - -name '*.usrmerge~' -type f) + -xdev -name '*.usrmerge~' -type f) done # switch over merged dirs in /usr for dir in bin sbin lib lib64; do @@ -72,7 +81,7 @@ done for dir in bin sbin lib lib64; do if [ ! -L "$ROOT/$dir" -a -d "$ROOT/$dir" ]; then echo "Create \`$ROOT/$dir' symlink." - rm -rf "$ROOT/${dir}.usrmerge" || : + rm --one-file-system -rf "$ROOT/${dir}.usrmerge" || : ln -s usr/$dir "$ROOT/${dir}.usrmerge" /usr/libexec/xmv "$ROOT/$dir" "$ROOT/${dir}.usrmerge" fi @@ -88,7 +97,7 @@ for dir in bin sbin lib lib64; do if [ -d "$d" ]; then echo "$d ..." mv "$d" "$d~" - rm -rf "$d~" + rm --one-file-system -rf "$d~" fi done done From 6ecb38177fbf0cb68447b02a211f7dec9b1e8ceda55dd80feac30923251722c9 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Wed, 2 Jun 2021 15:30:56 +0000 Subject: [PATCH 4/7] update OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=14 --- compat-usrmerge.changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index f7108d0..919f75e 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -7,7 +7,7 @@ Wed Jun 2 15:29:15 UTC 2021 - Ludwig Nussel ------------------------------------------------------------------- Tue Jun 1 23:27:08 UTC 2021 - Niklas Haas -- add fallback for filesystems without renameat2 +- add fallback for filesystems without renameat2 (boo#1186637) ------------------------------------------------------------------- Thu Mar 25 09:50:48 UTC 2021 - Ludwig Nussel From e0d86ebe21e38874a66e9a74a4083fb4b92c4ce6ed82fc74be731a5cbde2fe97 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Mon, 7 Jun 2021 09:03:29 +0000 Subject: [PATCH 5/7] - fix conversion with split /usr (boo#1186781) OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=15 --- compat-usrmerge.changes | 5 +++++ convertfs | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index 919f75e..e2f59de 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Mon Jun 7 09:02:56 UTC 2021 - Ludwig Nussel + +- fix conversion with split /usr (boo#1186781) + ------------------------------------------------------------------- Wed Jun 2 15:29:15 UTC 2021 - Ludwig Nussel diff --git a/convertfs b/convertfs index 2a2a2fc..4c25e87 100644 --- a/convertfs +++ b/convertfs @@ -16,6 +16,9 @@ cleanup() { for dir in bin sbin lib lib64; do rm -rf -- "$ROOT/usr/${dir}.usrmerge" done + 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." } trap 'ret=$?; [[ $ret -ne 0 ]] && cleanup;exit $ret;' EXIT @@ -41,7 +44,7 @@ for dir in bin sbin lib lib64; do [[ -d "$ROOT/$dir" ]] || continue echo "Make a copy of \`$ROOT/$dir'." [[ -d "$ROOT/$dir" ]] \ - && cp -ax -l "$ROOT/$dir" "$ROOT/usr/${dir}.usrmerge" + && cp -ax $CP_HARDLINK "$ROOT/$dir" "$ROOT/usr/${dir}.usrmerge" # 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 From 3318269fb9dc3fb8598e1d041e9ff0a1b74fa05baf9ada1254bc0f77d62946c7 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Tue, 8 Jun 2021 09:47:14 +0000 Subject: [PATCH 6/7] Accepting request 898293 from home:favogt:branches:Base:System - Avoid dependency on mountpoint from util-linux - Also check for availability of find OBS-URL: https://build.opensuse.org/request/show/898293 OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=16 --- compat-usrmerge.changes | 6 ++++++ convertfs | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index e2f59de..a873f68 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Jun 8 07:37:33 UTC 2021 - Fabian Vogt + +- Avoid dependency on mountpoint from util-linux +- Also check for availability of find + ------------------------------------------------------------------- Mon Jun 7 09:02:56 UTC 2021 - Ludwig Nussel diff --git a/convertfs b/convertfs index 4c25e87..01cc310 100644 --- a/convertfs +++ b/convertfs @@ -5,7 +5,7 @@ ROOT= # the package is installed with AutoReq off, so no guarantee that # coreutils actually works -if ! (cp --help && mountpoint --help && mountpoint --help) > /dev/null; then +if ! { cp --help && find --help; } > /dev/null; then echo "tools not functional, exit" exit 1 fi @@ -24,11 +24,11 @@ cleanup() { trap 'ret=$?; [[ $ret -ne 0 ]] && cleanup;exit $ret;' EXIT trap 'exit 1;' SIGINT -mountpoint -q "$ROOT/usr" || CP_HARDLINK="-l" - set -e +usrismountpoint= while read dev mp other; do + [ "$mp" = "/usr" ] && usrismountpoint=1 for dir in bin sbin lib lib64; do if [ "${mp#$ROOT/$dir}" != "$mp" ] || [ "${mp#$ROOT/usr/$dir}" != "$mp" ]; then echo "Please unmount $mp before the conversion" @@ -37,6 +37,8 @@ while read dev mp other; do done done < /proc/mounts +[ -n "$usrismountpoint" ] || CP_HARDLINK="-l" + # merge / and /usr in new dir in /usr for dir in bin sbin lib lib64; do rm -rf -- "$ROOT/usr/${dir}.usrmerge" From be2a961a1f6bae4d9e5ed8c00089a512520abdee05c2523ef3239dd82630f1d7 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Tue, 8 Jun 2021 13:14:14 +0000 Subject: [PATCH 7/7] Accepting request 898426 from home:lnussel:usrmove - early exit in case of overlayfs (boo#1187027) OBS-URL: https://build.opensuse.org/request/show/898426 OBS-URL: https://build.opensuse.org/package/show/Base:System/compat-usrmerge?expand=0&rev=17 --- compat-usrmerge.changes | 5 +++++ convertfs | 27 ++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/compat-usrmerge.changes b/compat-usrmerge.changes index a873f68..94eb82c 100644 --- a/compat-usrmerge.changes +++ b/compat-usrmerge.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Jun 8 12:03:52 UTC 2021 - Ludwig Nussel + +- early exit in case of overlayfs (boo#1187027) + ------------------------------------------------------------------- Tue Jun 8 07:37:33 UTC 2021 - Fabian Vogt diff --git a/convertfs b/convertfs index 01cc310..e82a95d 100644 --- a/convertfs +++ b/convertfs @@ -3,6 +3,19 @@ ROOT= +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 + # the package is installed with AutoReq off, so no guarantee that # coreutils actually works if ! { cp --help && find --help; } > /dev/null; then @@ -12,7 +25,7 @@ fi # clean up after ourselves no matter how we die. cleanup() { - echo "Something failed, cleaning up" + echo "UsrMerge conversion failed, cleaning up" for dir in bin sbin lib lib64; do rm -rf -- "$ROOT/usr/${dir}.usrmerge" done @@ -26,10 +39,16 @@ trap 'exit 1;' SIGINT set -e -usrismountpoint= +if [ "$(stat -f -c %T "${ROOT:-/}")" = "overlayfs" ]; then + echo "UsrMerge conversion does not work on overlayfs" + exit 1 +fi + +CP_HARDLINK="-l" while read dev mp other; do - [ "$mp" = "/usr" ] && usrismountpoint=1 + [ "$mp" = "$ROOT/usr" ] && CP_HARDLINK="" for dir in bin sbin lib lib64; do + [ -d "$ROOT/$dir" ] || continue if [ "${mp#$ROOT/$dir}" != "$mp" ] || [ "${mp#$ROOT/usr/$dir}" != "$mp" ]; then echo "Please unmount $mp before the conversion" exit 1 @@ -37,8 +56,6 @@ while read dev mp other; do done done < /proc/mounts -[ -n "$usrismountpoint" ] || CP_HARDLINK="-l" - # merge / and /usr in new dir in /usr for dir in bin sbin lib lib64; do rm -rf -- "$ROOT/usr/${dir}.usrmerge"