#!/usr/bin/env bash export SPEEDTEST_BASE_URL='https://fast-global-cdn.zsaz.io' set -euo pipefail base_url="${SPEEDTEST_BASE_URL:-https://speed.zsaz.io}" tmp_path="" cleanup() { if [[ -n "${tmp_path}" && -e "${tmp_path}" ]]; then rm -f -- "${tmp_path}" fi } trap cleanup EXIT HUP INT TERM fail() { printf 'speedtest: %s\n' "$*" >&2 exit 1 } detect_float_abi() { if [[ -n "${SPEEDTEST_FLOAT:-}" ]]; then case "${SPEEDTEST_FLOAT}" in hard|hardfloat) printf '%s' hardfloat ;; soft|softfloat) printf '%s' softfloat ;; *) fail 'SPEEDTEST_FLOAT must be hardfloat or softfloat' ;; esac return fi if command -v dpkg >/dev/null 2>&1; then case "$(dpkg --print-architecture 2>/dev/null || true)" in armel) printf '%s' softfloat; return ;; armhf) printf '%s' hardfloat; return ;; esac fi if command -v readelf >/dev/null 2>&1; then if readelf -A "$(command -v sh)" 2>/dev/null | grep -qi 'soft.*float'; then printf '%s' softfloat return fi fi printf '%s' hardfloat } os_name="$(uname -s 2>/dev/null || true)" machine="$(uname -m 2>/dev/null || true)" [[ -n "${os_name}" && -n "${machine}" ]] || fail 'cannot detect OS or architecture' case "${os_name}" in Linux) os=linux ;; Darwin) os=darwin ;; MINGW*|MSYS*|CYGWIN*) os=windows ;; *) fail "unsupported OS: ${os_name}" ;; esac if [[ "${os}" == windows && "${PROCESSOR_ARCHITECTURE:-}" == ARM64 ]]; then machine=arm64 fi case "${machine}" in x86_64|amd64) arch=amd64 ;; i386|i486|i586|i686|x86) arch=386 if [[ "${os}" == linux && -r /proc/cpuinfo ]] && ! grep -qiw sse2 /proc/cpuinfo; then arch=386-softfloat fi ;; aarch64|arm64) arch=arm64 ;; armv5*|armv5l) arch="armv5-$(detect_float_abi)" ;; armv6*|armv6l) arch="armv6-$(detect_float_abi)" ;; armv7*|armv7l|armv8l) arch="armv7-$(detect_float_abi)" ;; ppc64) arch=ppc64 ;; ppc64le) arch=ppc64le ;; riscv64) arch=riscv64 ;; s390x) arch=s390x ;; loongarch64|loong64) arch=loong64 ;; mips) arch=mips ;; mipsel|mipsle) arch=mipsle ;; mips64) arch=mips64 ;; mips64el|mips64le) arch=mips64le ;; *) fail "unsupported architecture: ${machine}" ;; esac case "${os}/${arch}" in windows/386|windows/amd64|windows/arm64) ;; darwin/amd64|darwin/arm64) ;; darwin/*|windows/*) fail "unsupported platform: ${os}/${arch}" ;; esac asset="speedtest-${os}-${arch}" [[ "${os}" == windows ]] && asset="${asset}.exe" url="${base_url%/}/bin/${asset}" shm_usable=false if [[ "${os}" == linux && -d /dev/shm && -w /dev/shm ]]; then shm_usable=true if command -v findmnt >/dev/null 2>&1 && findmnt -no OPTIONS /dev/shm 2>/dev/null | grep -qw noexec; then shm_usable=false elif [[ -r /proc/mounts ]] && awk '$2 == "/dev/shm" && $4 ~ /(^|,)noexec(,|$)/ { found=1 } END { exit !found }' /proc/mounts; then shm_usable=false fi fi if [[ "${shm_usable}" == true ]]; then tmp_path="/dev/shm/.speedtest.$$.${RANDOM}" else tmp_path="$(mktemp "${TMPDIR:-/tmp}/speedtest.XXXXXXXX")" fi if [[ "${os}" == windows ]]; then mv -- "${tmp_path}" "${tmp_path}.exe" tmp_path="${tmp_path}.exe" fi if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 2 --connect-timeout 10 --output "${tmp_path}" "${url}" || fail "download failed: ${url}" elif command -v wget >/dev/null 2>&1; then wget -qO "${tmp_path}" "${url}" || fail "download failed: ${url}" else fail 'curl or wget is required' fi chmod 700 "${tmp_path}" set +e "${tmp_path}" "$@" status=$? set -e exit "${status}"