diff --git a/patches/proton/0004-Makefile.in-revert-haswell.patch b/patches/proton/0004-Makefile.in-revert-haswell.patch index 0af5f36..f6a303c 100644 --- a/patches/proton/0004-Makefile.in-revert-haswell.patch +++ b/patches/proton/0004-Makefile.in-revert-haswell.patch @@ -6,7 +6,7 @@ index b86d2cc5..e4474332 100644 endif CROSSLDFLAGS += -Wl,--file-alignment,4096 --CFLAGS ?= -O3 -march=haswell -mtune=generic +-CFLAGS ?= -O2 -march=core-avx2 -mtune=core-avx2 +CFLAGS ?= -O2 -march=nocona -mtune=core-avx2 OPTIMIZE_FLAGS := $(CFLAGS) -mfpmath=sse SANITY_FLAGS := -fwrapv -fno-strict-aliasing diff --git a/patches/wine/0004-proton-annoyances/Revert-winex11.drv-disable-wm-decorations-by-default.patch b/patches/wine/0004-proton-annoyances/Revert-winex11.drv-disable-wm-decorations-by-default.patch deleted file mode 100644 index e185a8b..0000000 --- a/patches/wine/0004-proton-annoyances/Revert-winex11.drv-disable-wm-decorations-by-default.patch +++ /dev/null @@ -1,56 +0,0 @@ -This reverts commit b6ba4e0ccc645c078900db8fbafadc9ac4eec125. ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -78,7 +78,7 @@ - BOOL use_system_cursors = TRUE; - BOOL grab_fullscreen = FALSE; - BOOL managed_mode = TRUE; -+BOOL decorated_mode = TRUE; --BOOL decorated_mode = FALSE; - BOOL private_color_map = FALSE; - int primary_monitor = 0; - BOOL client_side_graphics = TRUE; ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -99,7 +99,6 @@ AddReg=\ - ThemeManager,\ - VersionInfo,\ - LicenseInformation,\ -- WineDecorateWindows,\ - NVIDIANGX, \ - ProtonOverrides,\ - SteamClient -@@ -130,7 +129,6 @@ AddReg=\ - ThemeManager,\ - VersionInfo,\ - LicenseInformation,\ -- WineDecorateWindows,\ - NVIDIANGX, \ - TTS, \ - ProtonOverrides,\ -@@ -178,7 +176,6 @@ AddReg=\ - Tapi,\ - VersionInfo,\ - LicenseInformation,\ -- WineDecorateWindows,\ - NVIDIANGX, \ - ProtonOverrides,\ - SteamClient.ntamd64 -@@ -3208,6 +3205,3 @@ HKCU,Software\Wine\AppDefaults\RiftApart.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ffxvi.exe\DllOverrides,"atiadlxx",,"builtin" - HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Height",0x10001,480 - HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Width",0x10001,640 -- --[WineDecorateWindows] --HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"Decorated",,"N" ---- a/programs/winecfg/x11drvdlg.c -+++ b/programs/winecfg/x11drvdlg.c -@@ -152,7 +152,7 @@ - CheckDlgButton(dialog, IDC_ENABLE_MANAGED, BST_UNCHECKED); - free(buf); - -+ buf = get_reg_key(config_key, keypath(L"X11 Driver"), L"Decorated", L"Y"); -- buf = get_reg_key(config_key, keypath(L"X11 Driver"), L"Decorated", L"N"); - if (IS_OPTION_TRUE(*buf)) - CheckDlgButton(dialog, IDC_ENABLE_DECORATED, BST_CHECKED); - else diff --git a/patches/wine/0005-osu/0021-Revert-ntdll-Wait-for-thread-suspension-in-NtSuspend.patch b/patches/wine/0005-osu/0021-Revert-ntdll-Wait-for-thread-suspension-in-NtSuspend.patch new file mode 100644 index 0000000..1e37fe7 --- /dev/null +++ b/patches/wine/0005-osu/0021-Revert-ntdll-Wait-for-thread-suspension-in-NtSuspend.patch @@ -0,0 +1,124 @@ +From 1cdd690a124a20c8d03d8786de2fe81d2ab2f36f Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Fri, 31 Jan 2025 11:04:58 -0800 +Subject: [PATCH 1/2] Revert "ntdll: Wait for thread suspension in + NtSuspendThread()." + +This reverts commit bfa83480970ff96bb4e4c6290f1b45745ff5d757. +--- + dlls/ntdll/unix/thread.c | 26 ++++---------------------- + server/protocol.def | 6 ++---- + server/thread.c | 28 ++++------------------------ + 3 files changed, 10 insertions(+), 50 deletions(-) + +diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c +index c3ab1317295..b50a5b1483d 100644 +--- a/dlls/ntdll/unix/thread.c ++++ b/dlls/ntdll/unix/thread.c +@@ -1622,40 +1622,22 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, + /****************************************************************************** + * NtSuspendThread (NTDLL.@) + */ +-NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *ret_count ) ++NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) + { + BOOL self = FALSE; +- unsigned int ret, count = 0; +- HANDLE wait_handle = NULL; ++ unsigned int ret; + + SERVER_START_REQ( suspend_thread ) + { + req->handle = wine_server_obj_handle( handle ); +- if (!(ret = wine_server_call( req )) || ret == STATUS_PENDING) ++ if (!(ret = wine_server_call( req ))) + { + self = reply->count & 0x80000000; +- count = reply->count & 0x7fffffff;; +- wait_handle = wine_server_ptr_handle( reply->wait_handle ); ++ if (count) *count = reply->count & 0x7fffffff; + } + } + SERVER_END_REQ; +- + if (self) usleep( 0 ); +- +- if (ret == STATUS_PENDING && wait_handle) +- { +- NtWaitForSingleObject( wait_handle, FALSE, NULL ); +- +- SERVER_START_REQ( suspend_thread ) +- { +- req->handle = wine_server_obj_handle( handle ); +- req->waited_handle = wine_server_obj_handle( wait_handle ); +- ret = wine_server_call( req ); +- } +- SERVER_END_REQ; +- } +- +- if (!ret && ret_count) *ret_count = count; + return ret; + } + +diff --git a/server/protocol.def b/server/protocol.def +index f52d2cf3b49..e434e261ffb 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -1203,11 +1203,9 @@ typedef volatile struct input_shared_memory input_shm_t; + + /* Suspend a thread */ + @REQ(suspend_thread) +- obj_handle_t handle; /* thread handle */ +- obj_handle_t waited_handle; /* handle waited on */ ++ obj_handle_t handle; /* thread handle */ + @REPLY +- int count; /* new suspend count */ +- obj_handle_t wait_handle; /* handle to wait on */ ++ int count; /* new suspend count */ + @END + + +diff --git a/server/thread.c b/server/thread.c +index 71c00fb6e35..67821c1b735 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1816,32 +1816,12 @@ DECL_HANDLER(suspend_thread) + { + struct thread *thread; + +- if (req->waited_handle) +- { +- struct context *context; +- +- if (!(context = (struct context *)get_handle_obj( current->process, req->waited_handle, +- 0, &context_ops ))) +- return; +- close_handle( current->process, req->waited_handle ); /* avoid extra server call */ +- set_error( context->status ); +- release_object( context ); +- return; +- } +- +- if (!(thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) return; +- +- if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); +- else ++ if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) + { +- reply->count = suspend_thread( thread ); +- if (!get_error() && thread != current && thread->context && thread->context->status == STATUS_PENDING) +- { +- set_error( STATUS_PENDING ); +- reply->wait_handle = alloc_handle( current->process, thread->context, SYNCHRONIZE, 0 ); +- } ++ if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED ); ++ else reply->count = suspend_thread( thread ); ++ release_object( thread ); + } +- release_object( thread ); + } + + /* resume a thread */ +-- +2.48.1 + diff --git a/patches/wine/0005-osu/0022-Revert-ntdll-HACK-Delay-resuming-thread-after-suspen.patch b/patches/wine/0005-osu/0022-Revert-ntdll-HACK-Delay-resuming-thread-after-suspen.patch new file mode 100644 index 0000000..84dd83e --- /dev/null +++ b/patches/wine/0005-osu/0022-Revert-ntdll-HACK-Delay-resuming-thread-after-suspen.patch @@ -0,0 +1,58 @@ +From c6d874bfefaa22588a58ab24407d2e8771725368 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Fri, 31 Jan 2025 11:05:07 -0800 +Subject: [PATCH 2/2] Revert "ntdll: HACK: Delay resuming thread after + suspending self." + +This reverts commit a65aa9c07be77d44fdc3392ef11a4b581128485e. +--- + dlls/ntdll/unix/thread.c | 5 +---- + server/thread.c | 6 +----- + 2 files changed, 2 insertions(+), 9 deletions(-) + +diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c +index b50a5b1483d..3302ea104c2 100644 +--- a/dlls/ntdll/unix/thread.c ++++ b/dlls/ntdll/unix/thread.c +@@ -1624,7 +1624,6 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, + */ + NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) + { +- BOOL self = FALSE; + unsigned int ret; + + SERVER_START_REQ( suspend_thread ) +@@ -1632,12 +1631,10 @@ NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) + req->handle = wine_server_obj_handle( handle ); + if (!(ret = wine_server_call( req ))) + { +- self = reply->count & 0x80000000; +- if (count) *count = reply->count & 0x7fffffff; ++ if (count) *count = reply->count; + } + } + SERVER_END_REQ; +- if (self) usleep( 0 ); + return ret; + } + +diff --git a/server/thread.c b/server/thread.c +index 67821c1b735..1c12d0a6276 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -912,11 +912,7 @@ int suspend_thread( struct thread *thread ) + int old_count = thread->suspend; + if (thread->suspend < MAXIMUM_SUSPEND_COUNT) + { +- if (!(thread->process->suspend + thread->suspend++)) +- { +- stop_thread( thread ); +- if (thread == current) return old_count | 0x80000000; +- } ++ if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread ); + } + else set_error( STATUS_SUSPEND_COUNT_EXCEEDED ); + return old_count; +-- +2.48.1 + diff --git a/patches/wine/0006-build/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch b/patches/wine/0006-build/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch new file mode 100644 index 0000000..b403dca --- /dev/null +++ b/patches/wine/0006-build/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch @@ -0,0 +1,43 @@ +From 046670cd17d81661e58ac65ad75730df9dcfd957 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Mon, 30 Dec 2024 02:31:59 -0800 +Subject: [PATCH] configure.ac: Omit frame pointers on x86_64, leaf frame + pointers on i386. + +--- + configure.ac | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 76e0cc5..de57ff5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1014,11 +1014,13 @@ This is an error since --enable-archs=$wine_arch was requested.])]) + + case $wine_arch in + i386) WINE_TRY_PE_CFLAGS([-fno-omit-frame-pointer]) ++ WINE_TRY_PE_CFLAGS([-momit-leaf-frame-pointer]) + WINE_TRY_PE_CFLAGS([-mstack-alignment=4]) + WINE_TRY_PE_CFLAGS([-mpreferred-stack-boundary=2]) + WINE_TRY_PE_CFLAGS([-Wl,--disable-stdcall-fixup], + [AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--disable-stdcall-fixup"])]) ;; +- x86_64) WINE_TRY_PE_CFLAGS([-Wformat-overflow]) ++ x86_64) WINE_TRY_PE_CFLAGS([-fomit-frame-pointer]) ++ WINE_TRY_PE_CFLAGS([-Wformat-overflow]) + WINE_TRY_PE_CFLAGS([-Wnonnull]) + WINE_TRY_PE_CFLAGS([-mcx16]) + WINE_TRY_PE_CFLAGS([-mcmodel=small]) ;; +@@ -2033,8 +2035,9 @@ char*f(const char *h,char n) {return strchr(h,n);}]])],[ac_cv_c_logicalop_noisy= + + case $HOST_ARCH in + dnl gcc-4.6+ omits frame pointers by default, breaking some copy protections +- i386) WINE_TRY_CFLAGS([-fno-omit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer"]) ;; ++ i386) WINE_TRY_CFLAGS([-fno-omit-frame-pointer -momit-leaf-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer -momit-leaf-frame-pointer"]) ;; + x86_64) ++ WINE_TRY_CFLAGS([-fomit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fomit-frame-pointer"]) + case $host_os in + dnl Mingw uses Windows 64-bit types, not Unix ones + cygwin*|mingw32*) WINE_TRY_CFLAGS([-Wno-format]) ;; +-- +2.47.1 + diff --git a/patches/wine/0006-build/configure.ac-Omit-frame-pointers-and-enforce-stack-a.patch b/patches/wine/0006-build/configure.ac-Omit-frame-pointers-and-enforce-stack-a.patch deleted file mode 100644 index f0346fe..0000000 --- a/patches/wine/0006-build/configure.ac-Omit-frame-pointers-and-enforce-stack-a.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 2303f24ee7fb119d9ab3dad1fb6eff3cf911b1ee Mon Sep 17 00:00:00 2001 -From: William Horvath -Date: Sun, 8 Sep 2024 02:47:03 -0700 -Subject: [PATCH] configure.ac: Omit frame pointers and enforce stack alignment. - -clang/llvm-mingw doesn't recognize the mpreferred-stack-boundary flag, but we -still want to ensure the stack is aligned to 4-byte boundaries to avoid any new -potential compiler bugs (like the one in mingw-gcc for march=avx512). ---- - configure.ac | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index b6418b0..b990804 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1003,6 +1003,7 @@ This is an error since --enable-archs=$wine_arch was requested.])]) - WINE_TRY_PE_CFLAGS([-ffunction-sections]) - WINE_TRY_PE_CFLAGS([-Wno-misleading-indentation], - [AS_VAR_APPEND([MSHTML_CFLAGS],[" -Wno-misleading-indentation"])]) -+ WINE_TRY_PE_CFLAGS([-fomit-frame-pointer]) - - dnl clang had broken -fms-hotpatch support before version 18 (https://github.com/llvm/llvm-project/pull/77245) - WINE_TRY_PE_CFLAGS([-fms-hotpatch -DMIN_CLANG_VERSION=18], -@@ -1013,8 +1014,7 @@ This is an error since --enable-archs=$wine_arch was requested.])]) - WINE_TRY_PE_CFLAGS([-flarge-source-files -Wmisleading-indentation],[AS_VAR_APPEND(${wine_arch}_EXTRACFLAGS,[" -Wno-misleading-indentation"])]) - - case $wine_arch in -- i386) WINE_TRY_PE_CFLAGS([-fno-omit-frame-pointer]) -- WINE_TRY_PE_CFLAGS([-mstack-alignment=4]) -+ i386) WINE_TRY_PE_CFLAGS([-mstack-alignment=4]) - WINE_TRY_PE_CFLAGS([-mpreferred-stack-boundary=2]) - WINE_TRY_PE_CFLAGS([-Wl,--disable-stdcall-fixup], - [AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--disable-stdcall-fixup"])]) ;; -@@ -2033,7 +2033,6 @@ char*f(const char *h,char n) {return strchr(h,n);}]])],[ac_cv_c_logicalop_noisy= - - case $HOST_ARCH in - dnl gcc-4.6+ omits frame pointers by default, breaking some copy protections -- i386) WINE_TRY_CFLAGS([-fno-omit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer"]) ;; - x86_64) - case $host_os in - dnl Mingw uses Windows 64-bit types, not Unix ones -@@ -2052,6 +2051,7 @@ int a(int b, ...) { __builtin_ms_va_list list; __builtin_ms_va_start(list,b); }] - esac ;; - arm) - WINE_TRY_CFLAGS([-Wincompatible-function-pointer-types],[EXTRACFLAGS="$EXTRACFLAGS -Wno-error=incompatible-function-pointer-types"]) ;; -+ *) WINE_TRY_CFLAGS([-fomit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fomit-frame-pointer"]) ;; - esac - - CFLAGS=$saved_CFLAGS --- -2.46.0 - diff --git a/patches/wine/0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch b/patches/wine/0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch new file mode 100644 index 0000000..15553a4 --- /dev/null +++ b/patches/wine/0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch @@ -0,0 +1,12 @@ +diff --git a/tools/makedep.c b/tools/makedep.c +index e8e5512f5f8..ed5731383fc 100644 +--- a/tools/makedep.c ++++ b/tools/makedep.c +@@ -4427,6 +4427,7 @@ static void output_silent_rules(void) + "GEN", + "LN", + "MSG", ++ "NASM", + "SED", + "TEST", + "WIDL", diff --git a/setup.sh b/setup.sh index 2904c0f..d886fda 100755 --- a/setup.sh +++ b/setup.sh @@ -1,11 +1,11 @@ #!/bin/bash -pkgver=9-13 +pkgver=9-14 buildname="proton-osu" pkgname="${buildname}-${pkgver}" protonurl=https://github.com/CachyOS/proton-cachyos.git -protontag=cachyos-9.0-20250106-slr +protontag=cachyos-9.0-20250126-slr protonsdk="registry.gitlab.steamos.cloud/proton/sniper/sdk:latest" umu_protonfixesurl=https://github.com/Open-Wine-Components/umu-protonfixes.git @@ -25,7 +25,9 @@ _main() { _envsetup || _failure "Failed preparing build environment." _dirsetup_initial || _failure "Failed initial directory setup." - if [ "${_do_umu_only}" = "true" ]; then + if [ "${_do_rearchive}" = "true" ]; then + _create_archive || _failure "Couldn't create the compressed archive. You need to have already built proton to use this." + elif [ "${_do_umu_only}" = "true" ]; then "${umu_builder_dir}/build.sh" || _failure "Building umu-run failed." elif [ "${_do_build}" = "true" ]; then _sources || _failure "Failed to prepare sources." @@ -46,6 +48,7 @@ _parse_args() { _do_bundle_umu=true _do_cleanbuild=false _do_umu_only=false + _do_rearchive=false while [[ $# -gt 0 ]]; do case $1 in @@ -54,6 +57,7 @@ _parse_args() { no-bundle-umu) _do_bundle_umu=false ;; cleanbuild) _do_cleanbuild=true ;; umu-only) _do_umu_only=true ;; + rearchive) _do_rearchive=true ;; *) _warning "Unknown option: $1" ;; esac shift @@ -122,10 +126,19 @@ _build() { make -j1 redist || _failure "Build failed." + _create_archive +} +############################################## +# Create the final compressed archive. +############################################## +_create_archive() { + cd "${builddir}" || _failure "Can't build because there is no build directory." + if [ "${_do_bundle_umu}" = "true" ]; then _message "Starting static umu-run bundling procedure..." if ! _build_umu_run; then - _warning "Failed to build umu-run. Continuing without it." + _warning "Failed to build umu-run" + { read -rp "\033[0;33m[!] %s\033[0m\n Continue without it? (y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] ; } || _failure else _message "Copying umu-run to build directory..." rm -rf "${builddir}/${buildname}/umu-run" @@ -235,6 +248,7 @@ _help() { _message " cleanbuild Run 'make clean' in the build directory before 'make'" _message " no-bundle-umu Don't build and bundle umu-run with Proton" _message " umu-only Only build the static umu-run self-extracting executable" + _message " rearchive Just re-bundle umu-run and proton into the final tarball. You must have already built proton to use this, but umu will be rebuilt." echo "" _message "No arguments grabs sources, patches, builds, and installs" @@ -248,6 +262,7 @@ _print_config() { _message " bundle umu: ${_do_bundle_umu}" _message " clean build: ${_do_cleanbuild}" _message " umu only: ${_do_umu_only}" + _message " rearchive: ${_do_rearchive}" } ############################################## # Run diff --git a/umu-static-bundler/lib/git-utils.sh b/umu-static-bundler/lib/git-utils.sh index 56d1954..8118278 100755 --- a/umu-static-bundler/lib/git-utils.sh +++ b/umu-static-bundler/lib/git-utils.sh @@ -100,13 +100,13 @@ _repo_updater() { # Keep submodules updated if [ -f ".gitmodules" ]; then _message "Updating submodules for ${repo_path}." - - if ! git submodule update --init --depth 1 --recursive -f --progress 2> >(tee /tmp/submodule_error >&2); then + submodule_error=$(mktemp) + if ! git submodule update --init --depth 1 --recursive -f --progress 2> >(tee "${submodule_error}" >&2); then # If it fails, check if it's due to directory conflicts - if grep -q "destination path.*already exists and is not an empty directory" /tmp/submodule_error; then + if grep -q "destination path.*already exists and is not an empty directory" "${submodule_error}"; then # Extract the problematic path from the error message local conflict_path - conflict_path=$(grep "destination path.*already exists" /tmp/submodule_error | sed -E "s/.*path '(.*)' already exists.*/\1/") + conflict_path=$(grep "destination path.*already exists" "${submodule_error}" | sed -E "s/.*path '(.*)' already exists.*/\1/") if [ -n "${conflict_path}" ] && [ -d "${conflict_path}" ] && [ ! -d "${conflict_path}/.git" ]; then # Safety check: ensure the conflict path is under repo_path local abs_repo_path @@ -122,10 +122,10 @@ _repo_updater() { _failure "Security check failed: conflicting path ${conflict_path} is outside repository" fi else - _failure "Submodule update failed: $(cat /tmp/submodule_error)" + _failure "Submodule update failed: $(cat "${submodule_error}")" fi else - _failure "Submodule update failed: $(cat /tmp/submodule_error)" + _failure "Submodule update failed: $(cat "${submodule_error}")" fi fi