Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions lib/linux/detect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ detect_system() {
# ─── Distribution ───────────────────────────────────────────────────────
SYS_DISTRO_ID="unknown"; SYS_DISTRO_NAME="unknown"
SYS_DISTRO_VERSION=""; SYS_DISTRO_CODENAME=""; SYS_DISTRO_LIKE=""
if [[ -r /etc/os-release ]]; then
local root="${SYS_ROOT:-}"
if [[ -r "$root/etc/os-release" ]]; then
# shellcheck disable=SC1091
. /etc/os-release
. "$root/etc/os-release"
SYS_DISTRO_ID="${ID:-unknown}"
SYS_DISTRO_NAME="${PRETTY_NAME:-${NAME:-unknown}}"
SYS_DISTRO_VERSION="${VERSION_ID:-}"
Expand All @@ -138,10 +139,10 @@ detect_system() {

# ─── Board / virtualisation ─────────────────────────────────────────────
SYS_MODEL="unknown"; SYS_IS_PI=0; SYS_IS_WSL=0; SYS_IS_CONTAINER=0
if [[ -r /proc/device-tree/model ]]; then
SYS_MODEL="$(tr -d '\0' </proc/device-tree/model 2>/dev/null || echo unknown)"
elif [[ -r /sys/devices/virtual/dmi/id/product_name ]]; then
SYS_MODEL="$(cat /sys/devices/virtual/dmi/id/product_name 2>/dev/null || echo unknown)"
if [[ -r "$root/proc/device-tree/model" ]]; then
SYS_MODEL="$(tr -d '\0' <"$root/proc/device-tree/model" 2>/dev/null || echo unknown)"
elif [[ -r "$root/sys/devices/virtual/dmi/id/product_name" ]]; then
SYS_MODEL="$(cat "$root/sys/devices/virtual/dmi/id/product_name" 2>/dev/null || echo unknown)"
fi
if [[ "$SYS_MODEL" == *"Raspberry Pi"* ]]; then SYS_IS_PI=1; fi
# WSL: three independent signals, because none is reliable alone. The env
Expand All @@ -150,26 +151,26 @@ detect_system() {
SYS_WSL_VERSION=""; SYS_WSL_DISTRO=""
if [[ -n "${WSL_DISTRO_NAME:-}" ]]; then
SYS_IS_WSL=1; SYS_WSL_DISTRO="$WSL_DISTRO_NAME"
elif grep -qi microsoft /proc/version 2>/dev/null; then
elif grep -qi microsoft "$root/proc/version" 2>/dev/null; then
SYS_IS_WSL=1
elif grep -qiE 'microsoft|wsl' /proc/sys/kernel/osrelease 2>/dev/null; then
elif grep -qiE 'microsoft|wsl' "$root/proc/sys/kernel/osrelease" 2>/dev/null; then
SYS_IS_WSL=1
fi
if (( SYS_IS_WSL )); then
# WSL2 ships a real Linux kernel tagged microsoft-standard-WSL2 and has
# /run/WSL; WSL1 is a syscall translation layer on an NT-era version string.
if grep -qiE 'wsl2|microsoft-standard' /proc/sys/kernel/osrelease 2>/dev/null \
|| grep -qi 'WSL2' /proc/version 2>/dev/null \
|| [[ -d /run/WSL ]]; then
if grep -qiE 'wsl2|microsoft-standard' "$root/proc/sys/kernel/osrelease" 2>/dev/null \
|| grep -qi 'WSL2' "$root/proc/version" 2>/dev/null \
|| [[ -d "$root/run/WSL" ]]; then
SYS_WSL_VERSION=2
else
SYS_WSL_VERSION=1
fi
if [[ -z "$SYS_WSL_DISTRO" && -r /etc/wsl.conf ]]; then
SYS_WSL_DISTRO="$(awk -F= '/^[[:space:]]*hostname/{gsub(/ /,"",$2); print $2}' /etc/wsl.conf 2>/dev/null)"
if [[ -z "$SYS_WSL_DISTRO" && -r "$root/etc/wsl.conf" ]]; then
SYS_WSL_DISTRO="$(awk -F= '/^[[:space:]]*hostname/{gsub(/ /,"",$2); print $2}' "$root/etc/wsl.conf" 2>/dev/null)"
fi
fi
if [[ -f /.dockerenv ]] || grep -qE '(docker|lxc|containerd)' /proc/1/cgroup 2>/dev/null; then
if [[ -f "$root/.dockerenv" ]] || grep -qE '(docker|lxc|containerd)' "$root/proc/1/cgroup" 2>/dev/null; then
SYS_IS_CONTAINER=1
fi

Expand All @@ -186,10 +187,10 @@ detect_system() {

# ─── Hardware ───────────────────────────────────────────────────────────
SYS_CPU_CORES="$(nproc 2>/dev/null || echo 1)"
SYS_CPU_NAME="$(awk -F': ' '/^model name|^Model/{print $2; exit}' /proc/cpuinfo 2>/dev/null || echo unknown)"
SYS_CPU_NAME="$(awk -F': ' '/^model name|^Model/{print $2; exit}' "$root/proc/cpuinfo" 2>/dev/null || echo unknown)"
if [[ -z "$SYS_CPU_NAME" ]]; then SYS_CPU_NAME="unknown"; fi
local mem_kb
mem_kb="$(awk '/^MemTotal:/{print $2}' /proc/meminfo 2>/dev/null || echo 0)"
mem_kb="$(awk '/^MemTotal:/{print $2}' "$root/proc/meminfo" 2>/dev/null || echo 0)"
SYS_RAM_GB="$(awk -v k="$mem_kb" 'BEGIN{printf "%.1f", k/1048576}')"
SYS_FREE_DISK_GB="$(df -BG / 2>/dev/null | awk 'NR==2{gsub("G","",$4); print $4}' || echo 0)"
if [[ -z "$SYS_FREE_DISK_GB" ]]; then SYS_FREE_DISK_GB=0; fi
Expand Down
105 changes: 105 additions & 0 deletions tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,111 @@ fi
# ─── Detection ──────────────────────────────────────────────────────────────
describe "detection"

if it "detects Debian-like distributions"; then
tmp="$(mktemp -d)"; mkdir -p "$tmp/etc"
cat >"$tmp/etc/os-release" <<'EOF'
ID=ubuntu
PRETTY_NAME="Ubuntu 22.04 LTS"
VERSION_ID="22.04"
VERSION_CODENAME="jammy"
ID_LIKE="debian"
EOF
(
SYS_ROOT="$tmp"
uname() { echo "Linux"; }
detect_system
if [[ "$SYS_DISTRO_ID" == "ubuntu" && "$SYS_DISTRO_NAME" == "Ubuntu 22.04 LTS" && "$SYS_IS_DEBIAN_LIKE" -eq 1 ]]; then
true
else false; fi
) && pass || fail "failed to detect ubuntu as debian-like"
rm -rf "$tmp"
fi

if it "detects WSL2 environment"; then
tmp="$(mktemp -d)"; mkdir -p "$tmp/proc/sys/kernel" "$tmp/run"
cat >"$tmp/proc/version" <<'EOF'
Linux version 5.15.90.1-microsoft-standard-WSL2 (oe-user@oe-host) (x86_64-msft-linux-gcc (GCC) 9.3.0, GNU ld (GNU Binutils) 2.34.0.20200220) #1 SMP Fri Jan 27 02:56:13 UTC 2023
EOF
cat >"$tmp/proc/sys/kernel/osrelease" <<'EOF'
5.15.90.1-microsoft-standard-WSL2
EOF
mkdir -p "$tmp/run/WSL"
(
SYS_ROOT="$tmp"
uname() { echo "Linux"; }
detect_system
if [[ "$SYS_IS_WSL" -eq 1 && "$SYS_WSL_VERSION" == "2" ]]; then
true
else false; fi
) && pass || fail "failed to detect WSL2"
rm -rf "$tmp"
fi

if it "detects Raspberry Pi"; then
tmp="$(mktemp -d)"; mkdir -p "$tmp/proc/device-tree"
echo -n "Raspberry Pi 4 Model B Rev 1.2" > "$tmp/proc/device-tree/model"
(
SYS_ROOT="$tmp"
uname() { echo "Linux"; }
detect_system
if [[ "$SYS_IS_PI" -eq 1 ]]; then
true
else false; fi
) && pass || fail "failed to detect Raspberry Pi"
rm -rf "$tmp"
fi

if it "detects Docker container"; then
tmp="$(mktemp -d)"
touch "$tmp/.dockerenv"
(
SYS_ROOT="$tmp"
uname() { echo "Linux"; }
detect_system
if [[ "$SYS_IS_CONTAINER" -eq 1 ]]; then
true
else false; fi
) && pass || fail "failed to detect Docker container"
rm -rf "$tmp"
fi

if it "detects non-Debian distributions"; then
tmp="$(mktemp -d)"; mkdir -p "$tmp/etc"
cat >"$tmp/etc/os-release" <<'EOF'
ID=alpine
PRETTY_NAME="Alpine Linux v3.18"
VERSION_ID="3.18.2"
EOF
(
SYS_ROOT="$tmp"
uname() { echo "Linux"; }
ID=""
NAME=""
ID_LIKE=""
detect_system
if [[ "$SYS_DISTRO_ID" == "alpine" && "$SYS_DISTRO_NAME" == "Alpine Linux v3.18" && "$SYS_IS_DEBIAN_LIKE" -eq 0 ]]; then
true
else false; fi
) && pass || fail "failed to correctly detect alpine as non-debian-like"
rm -rf "$tmp"
fi

if it "handles missing os-release gracefully"; then
tmp="$(mktemp -d)"
(
SYS_ROOT="$tmp"
uname() { echo "Linux"; }
ID=""
NAME=""
ID_LIKE=""
detect_system
if [[ "$SYS_DISTRO_ID" == "unknown" && "$SYS_DISTRO_NAME" == "unknown" && "$SYS_IS_DEBIAN_LIKE" -eq 0 ]]; then
true
else false; fi
) && pass || fail "failed to gracefully handle missing os-release"
rm -rf "$tmp"
fi

if it "identifies the architecture"; then
case "$SYS_ARCH" in x64|arm64|armhf) pass ;; *) fail "odd arch: $SYS_ARCH" ;; esac
fi
Expand Down
Loading