#!/usr/bin/env bash # Copyright 2021 Collabora Ltd. # SPDX-License-Identifier: MIT set -eu set -o pipefail # Don't load the Steam Overlay into this helper script. Put it back later. saved_ld_preload="${LD_PRELOAD-}" unset LD_PRELOAD me="$(readlink -f "$0")" here="${me%/*}" log () { printf '%s\n' "${me}[$$]: $*" >&2 || : } usage () { local code="$1" shift if [ "$code" -ne 0 ]; then exec >&2 fi echo "Usage:" echo "$me [OPTIONS] [--] COMMAND [ARGS...]" echo echo "Run a command in the scout Steam Runtime." echo echo "Required arguments:" echo "COMMAND [ARGS...] Run this." echo echo "Options:" echo "--verb=%verb% Mode to operate in [default=waitforexitandrun]." exit "${code}" } main () { local getopt_temp="help" local ours local runtime local src local theirs local theirs_should_be local verbose= if [ "${STEAM_LINUX_RUNTIME_VERBOSE-}" = 1 ]; then verbose=yes fi getopt_temp="$getopt_temp,verb:" getopt_temp="$getopt_temp,verbose" getopt_temp="$(getopt -o '' --long "$getopt_temp" -n "$me" -- "$@")" eval "set -- $getopt_temp" unset getopt_temp while [ "$#" -gt 0 ]; do case "$1" in (--help) usage 0 # not reached ;; (--verb) case "$2" in (run|waitforexitandrun) ;; (*) log "Ignoring unknown Steam compatibility interface verb: $2" ;; esac shift 2 ;; (--verbose) verbose=yes shift ;; (--) shift break ;; (-*) log "Unknown option: $1" usage 125 # not reached ;; (*) break ;; esac done if [ "$#" -eq 0 ] || [ "$1" = -- ]; then log "Error: A command to run is required" usage 125 fi mkdir -p "${here}/var" if [ "${STEAM_LINUX_RUNTIME_LOG-}" = 1 ]; then echo "See SteamLinuxRuntime_soldier/var/ for newer" \ "SteamLinuxRuntime log files." \ > "${here}/var/.slr-latest.log.$$" mv -f "${here}/var/.slr-latest.log.$$" "${here}/var/slr-latest.log" fi [ -z "$verbose" ] || log "Command to run: $(printf '%q ' "$@")" # Just because zenity was available on the host system doesn't mean # it's available in this container. soldier historically didn't have it, # but it was added in 0.20210618.0. if [ -x /usr/bin/zenity ]; then export STEAM_ZENITY=/usr/bin/zenity else unset STEAM_ZENITY fi if [ -d "${here}/steam-runtime" ]; then src="${here}/steam-runtime" [ -z "$verbose" ] || log "Using local scout runtime ${src}" rm -fr "${here}/var/unpack" elif [ -n "${STEAM_RUNTIME_SCOUT-}" ] && [ -d "${STEAM_RUNTIME_SCOUT-}" ]; then src="${STEAM_RUNTIME_SCOUT}" [ -z "$verbose" ] || log "Using specified scout runtime ${src}" rm -fr "${here}/var/unpack" else src="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-"$HOME/.steam/root"}/ubuntu12_32/steam-runtime" theirs="$(cat "$src/checksum" || echo none)" theirs_should_be="$(cat "${src}.checksum")" if [ "$theirs" = "$theirs_should_be" ]; then [ -z "$verbose" ] || log "Using default scout runtime ${src}" rm -fr "${here}/var/unpack" else log "warning: $src is not the expected version" log "warning: expected: $theirs_should_be" log "warning: found: $theirs" if [ -d "${here}/var/unpack" ]; then ours="$(cat "${here}/var/unpack/steam-runtime/checksum" || echo none)" else ours=none fi if [ "$theirs_should_be" != "$ours" ]; then # Recover by unpacking a copy locally. log "Recovering by unpacking $src.tar.xz* into ${here}/var/unpack..." mkdir -p "${here}/var/unpack" cat "$src.tar.xz".* | tar -C "${here}/var/unpack" -Jxf- echo "$theirs_should_be" > "${here}/var/unpack/steam-runtime/checksum" fi src="${here}/var/unpack/steam-runtime" [ -z "$verbose" ] || log "Falling back to using ${src}" fi fi # Note that this only works because run.sh does not take the # $(realpath) of its $0, and because we are no longer using setup.sh, # which uses the equivalent of $(find ${top} -type l -name '*.so*') # to list the libraries in the runtime (which wouldn't recurse into # the subdirectories of var/steam-runtime in our case). runtime="${here}/var/steam-runtime" mkdir -p "$runtime" if [ -e "$runtime/version.txt" ]; then ours="$(cat "$runtime/version.txt" || echo none)" else ours=none fi theirs="$(cat "$src/version.txt")" if [ "$ours" != "$theirs" ]; then [ -z "$verbose" ] || log "scout runtime switched from '$ours' to '$theirs'" printf '%s\n' "$theirs" > "$runtime/version.txt" else [ -z "$verbose" ] || log "scout runtime version '$ours'" fi ln -fns "$src/amd64" "$runtime/" ln -fns "$src/i386" "$runtime/" ln -fns "$src/lib" "$runtime/" ln -fns "$src/run.sh" "$runtime/" ln -fns "$src/scripts" "$runtime/" ln -fns "$src/setup.sh" "$runtime/" ln -fns "$src/usr" "$runtime/" mkdir -p "$runtime/pinned_libs_32" mkdir -p "$runtime/pinned_libs_64" # We know exactly what's in the soldier and scout runtimes, and we # know soldier is strictly newer in all cases, so the only libraries # we need to pin are those that we have hard-coded to be pinned; # so we don't need to run setup.sh, and can do something more # abbreviated. # libcurl in the Steam Runtime is internally identified # as libcurl.so.4, but with a symlink at libcurl.so.3 # as a result of some unfortunate ABI weirdness back in # 2007. It also has Debian-specific symbol versioning as a # result of the versioned symbols introduced as a # Debian-specific change in 2005-2006, which were preserved # across the rename from libcurl.so.3 to libcurl.so.4, not # matching the versioned symbols that upstream subsequently # added to libcurl.so.4; as a result, a system libcurl.so.4 # probably isn't going to be a drop-in replacement for our # libcurl. # # Debian/Ubuntu subsequently (in 2018) switched to a SONAME # and versioning that match upstream, but the Steam Runtime # is based on a version that is older than that, so anything # built against the Steam Runtime will expect the old SONAME # and versioned symbols; make sure we use the Steam Runtime # version. ln -fns "$src/usr/lib/x86_64-linux-gnu/libcurl.so.4" \ "$runtime/pinned_libs_64/libcurl.so.4" ln -fns "$src/usr/lib/i386-linux-gnu/libcurl.so.4" \ "$runtime/pinned_libs_32/libcurl.so.4" # The version of libcurl.so.4 in the Steam Runtime is actually # binary-compatible with the older libcurl.so.3 in Debian/Ubuntu, # so pin it under both names. ln -fns "$src/usr/lib/x86_64-linux-gnu/libcurl.so.4" \ "$runtime/pinned_libs_64/libcurl.so.3" ln -fns "$src/usr/lib/i386-linux-gnu/libcurl.so.4" \ "$runtime/pinned_libs_32/libcurl.so.3" # Deliberately not pinning libcurl-gnutls.so.[34]: soldier has a # newer version of those, which is believed to be compatible with the # ones in scout. # Deliberately not pinning 32-bit libgtk-x11-2.0.so.0, # libdbusmenu-gtk.so.4, libdbusmenu-glib.so.4, libdbus-1.so.3: # in the normal scout runtime those are pinned for the benefit of the # Steam client itself, but let's try keeping 32-bit games consistent # with 64-bit games. if command -v steam-runtime-launcher-interface-0 >/dev/null; then set -- \ steam-runtime-launcher-interface-0 \ scout-in-container:scout-on-soldier \ "$@" fi if [ -n "$saved_ld_preload" ]; then case "$1" in (*=*) # Replace inadvisable executable name with something env(1) # will not misinterpret set -- sh -euc 'exec -- "$@"' sh "$@" ;; esac set -- env LD_PRELOAD="$saved_ld_preload" "$@" fi [ -z "$verbose" ] || log "Running: $runtime/run.sh $(printf '%q ' "$@")" exec "$runtime/run.sh" "$@" # This should never be reached exit 1 } main "$@" # vim:set sw=4 sts=4 et: