#!/usr/bin/env bash set -euo pipefail cd "$(dirname "$0")/.." binary="$PWD/bin/uce_fastcgi.linux.bin" root=$(mktemp -d /tmp/uce-server-arguments.XXXXXX) listener_pid="" cleanup() { [[ -n "$listener_pid" ]] && kill "$listener_pid" 2>/dev/null || true rm -rf "$root" } trap cleanup EXIT cfg="$root/settings.cfg" socket_path="$root/sentinel.sock" cp /etc/uce/settings.cfg "$cfg" sed -E -i \ -e "s|^[[:space:]]*FCGI_SOCKET_PATH[[:space:]]*=.*|FCGI_SOCKET_PATH=|" \ -e "s|^[[:space:]]*FCGI_PORT[[:space:]]*=.*|FCGI_PORT=|" \ -e "s|^[[:space:]]*CLI_SOCKET_PATH[[:space:]]*=.*|CLI_SOCKET_PATH=$socket_path|" \ -e "s|^[[:space:]]*HTTP_PORT[[:space:]]*=.*|HTTP_PORT=|" \ -e "s|^[[:space:]]*PROACTIVE_COMPILE_ENABLED[[:space:]]*=.*|PROACTIVE_COMPILE_ENABLED=false|" \ -e "s|^[[:space:]]*WORKER_COUNT[[:space:]]*=.*|WORKER_COUNT=1|" \ -e "s|^[[:space:]]*BIN_DIRECTORY[[:space:]]*=.*|BIN_DIRECTORY=$root/bin|" \ -e "s|^[[:space:]]*TMP_UPLOAD_PATH[[:space:]]*=.*|TMP_UPLOAD_PATH=$root/upload|" \ -e "s|^[[:space:]]*SESSION_PATH[[:space:]]*=.*|SESSION_PATH=$root/session|" \ "$cfg" python3 -c 'import socket,sys,time; s=socket.socket(socket.AF_UNIX); s.bind(sys.argv[1]); s.listen(); time.sleep(30)' "$socket_path" & listener_pid=$! for _ in $(seq 1 50); do [[ -S "$socket_path" ]] && break sleep 0.02 done [[ -S "$socket_path" ]] socket_inode=$(stat -c %i "$socket_path") invoke() { local output="$1" shift local timeout_seconds="${INVOKE_TIMEOUT_SECONDS:-2}" timeout --signal=TERM --kill-after=1s "$timeout_seconds" unshare --mount --fork \ bash -c 'mount --bind "$1" /etc/uce/settings.cfg; exec "$2" "${@:3}"' \ _ "$cfg" "$binary" "$@" >"$output.stdout" 2>"$output.stderr" } for option in --help -h; do invoke "$root/help" "$option" grep -q '^Usage: uce_fastcgi' "$root/help.stdout" grep -q -- '--precompile' "$root/help.stdout" grep -q -- '--serialize-module' "$root/help.stdout" [[ ! -s "$root/help.stderr" ]] done for arguments in '--unknown' '--precompile extra' '--serialize-module' '--help extra'; do read -r -a argv <<<"$arguments" set +e invoke "$root/invalid" "${argv[@]}" rc=$? set -e [[ $rc -eq 2 ]] grep -q '^invalid arguments$' "$root/invalid.stderr" grep -q '^Usage: uce_fastcgi' "$root/invalid.stderr" [[ ! -s "$root/invalid.stdout" ]] done cp bin/wasm/core.wasm "$root/serialize.wasm" INVOKE_TIMEOUT_SECONDS=30 invoke "$root/serialize" --serialize-module "$root/serialize.wasm" [[ -s "$root/serialize.cwasm" ]] [[ ! -s "$root/serialize.stderr" ]] # Serialization shares the unit compile lock. If the wasm path is replaced # while the serializer is waiting, it must read the replacement and must not # publish a stale native artifact for the old inode. cp bin/wasm/core.wasm "$root/race.wasm" exec 8>"$root/race.wasm.lock" flock 8 INVOKE_TIMEOUT_SECONDS=30 invoke "$root/race" --serialize-module "$root/race.wasm" & race_pid=$! sleep 0.1 kill -0 "$race_pid" printf 'not wasm\n' >"$root/race.wasm.next" mv "$root/race.wasm.next" "$root/race.wasm" flock -u 8 set +e wait "$race_pid" race_rc=$? set -e [[ $race_rc -eq 1 ]] grep -Eqi 'wasm|magic|WebAssembly|compile' "$root/race.stderr" [[ ! -e "$root/race.cwasm" ]] if compgen -G "$root/race.cwasm.*.tmp" >/dev/null; then echo "failed serialization left a temporary artifact" >&2 exit 1 fi [[ -S "$socket_path" ]] [[ "$(stat -c %i "$socket_path")" == "$socket_inode" ]] kill -0 "$listener_pid" echo 'server argument handling passed: help and invalid arguments exited before listener setup'