From 4b2769aa9858f0099bddf01646aba7d5bb5baaa0 Mon Sep 17 00:00:00 2001 From: Zakary Timson Date: Mon, 26 Oct 2026 15:41:34 -0400 Subject: [PATCH] Update install.sh --- install.sh | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 57319c1..90e93e1 100644 --- a/install.sh +++ b/install.sh @@ -11,12 +11,57 @@ if [ "$EUID" -ne 0 ]; then exit 1 fi +# Ask a question; Enter accepts the default. prompt() { local __var="$1" __question="$2" __default="$3" __answer="" read -r -p "$__question [$__default]: " __answer < /dev/tty || __answer="" printf -v "$__var" '%s' "${__answer:-$__default}" } +# Like prompt, but "blank" is a legitimate value. Enter accepts the default; +# typing the clear word (e.g. "all" or "none") sets the value to empty. +prompt_blankable() { + local __var="$1" __question="$2" __default="$3" __clear="$4" __answer="" + read -r -p "$__question [${__default:-$__clear}]: " __answer < /dev/tty || __answer="" + + case "$__answer" in + "") __answer="$__default" ;; + "$__clear") __answer="" ;; + esac + + printf -v "$__var" '%s' "${__answer// /}" +} + +# Ask until the answer is one of the allowed choices. Enter accepts the default. +prompt_choice() { + local __var="$1" __question="$2" __default="$3" __answer="" __opt + shift 3 + + while true; do + read -r -p "$__question [$__default]: " __answer < /dev/tty || __answer="" + __answer="${__answer:-$__default}" + + for __opt in "$@"; do + if [ "$__answer" = "$__opt" ]; then + printf -v "$__var" '%s' "$__answer" + return 0 + fi + done + + echo " Please enter one of: $*" + done +} + +# Lists wireless interfaces (those with a /sys/class/net//wireless dir). +detect_wireless() { + local dir + for dir in /sys/class/net/*; do + if [ -d "$dir/wireless" ]; then + basename "$dir" + fi + done +} + EXISTING_CONFIG="/etc/fallback-ap.conf" if [ -f "$EXISTING_CONFIG" ]; then @@ -24,22 +69,81 @@ if [ -f "$EXISTING_CONFIG" ]; then source "$EXISTING_CONFIG" fi +DETECTED_WIFI="$(detect_wireless | tr '\n' ' ')" +DETECTED_WIFI="${DETECTED_WIFI% }" + DEFAULT_SSID="${SAVED_SSID:-$(hostname)}" DEFAULT_PASSWORD="${SAVED_PASSWORD:-abcd1234}" +DEFAULT_IFACE="${SAVED_IFACE:-${DETECTED_WIFI%% *}}" +DEFAULT_IFACE="${DEFAULT_IFACE:-wlan0}" DEFAULT_CIDR="${SAVED_CIDR:-10.10.10.1/24}" DEFAULT_DHCP_START_OCTET="${SAVED_DHCP_START_OCTET:-100}" DEFAULT_DHCP_END_OCTET="${SAVED_DHCP_END_OCTET:-250}" +DEFAULT_MONITOR_IFACE="${SAVED_MONITOR_IFACE-}" +DEFAULT_IGNORE_IFACE="${SAVED_IGNORE_IFACE-}" +DEFAULT_CHECK_MODE="${SAVED_CHECK_MODE:-link}" +DEFAULT_CHECK_TARGETS="${SAVED_CHECK_TARGETS:-1.1.1.1 8.8.8.8}" + +# --- Access point ---------------------------------------------------------------------------------------------------- [ -z "${FALLBACK_AP_SSID:-}" ] && prompt FALLBACK_AP_SSID "Access point SSID" "$DEFAULT_SSID" [ -z "${FALLBACK_AP_PASSWORD:-}" ] && prompt FALLBACK_AP_PASSWORD "Access point passphrase" "$DEFAULT_PASSWORD" + +if [ -z "${FALLBACK_AP_IFACE:-}" ]; then + if [ -n "$DETECTED_WIFI" ]; then + echo "Detected Wi-Fi interfaces: $DETECTED_WIFI" + fi + prompt FALLBACK_AP_IFACE "Interface to create the access point on" "$DEFAULT_IFACE" +fi + [ -z "${FALLBACK_AP_CIDR:-}" ] && prompt FALLBACK_AP_CIDR "Access point subnet (CIDR)" "$DEFAULT_CIDR" [ -z "${FALLBACK_AP_DHCP_START_OCTET:-}" ] && prompt FALLBACK_AP_DHCP_START_OCTET "DHCP range start (last octet)" "$DEFAULT_DHCP_START_OCTET" [ -z "${FALLBACK_AP_DHCP_END_OCTET:-}" ] && prompt FALLBACK_AP_DHCP_END_OCTET "DHCP range end (last octet)" "$DEFAULT_DHCP_END_OCTET" -export FALLBACK_AP_SSID FALLBACK_AP_PASSWORD FALLBACK_AP_CIDR FALLBACK_AP_DHCP_START_OCTET FALLBACK_AP_DHCP_END_OCTET +# --- Connectivity monitoring ----------------------------------------------------------------------------------------- +# +# The AP only starts when none of the monitored interfaces are online, and it +# is only ever created on the interface chosen above. +# +# These use "unset" (not "empty") to decide whether to ask, because an empty +# FALLBACK_AP_MONITOR_IFACE / FALLBACK_AP_IGNORE_IFACE is a valid answer +# meaning "all real interfaces" / "ignore nothing". +if [ -z "${FALLBACK_AP_MONITOR_IFACE+x}" ]; then + echo + echo "Which interfaces should count as 'online'? Enter a comma-separated list" + echo "(e.g. eth0,wlan0), or 'all' for every real interface. Virtual interfaces" + echo "(docker, veth, bridges, VPNs) are skipped automatically." + prompt_blankable FALLBACK_AP_MONITOR_IFACE "Interfaces to monitor" "$DEFAULT_MONITOR_IFACE" "all" +fi + +if [ -z "$FALLBACK_AP_MONITOR_IFACE" ] && [ -z "${FALLBACK_AP_IGNORE_IFACE+x}" ]; then + echo + echo "Any physical interfaces to ignore (globs allowed, e.g. enx*,usb0)?" + prompt_blankable FALLBACK_AP_IGNORE_IFACE "Interfaces to ignore" "$DEFAULT_IGNORE_IFACE" "none" +fi + +if [ -z "${FALLBACK_AP_CHECK_MODE:-}" ]; then + echo + echo "How should 'online' be determined?" + echo " link - the interface is connected (an upstream outage keeps the AP off)" + echo " internet - the interface is connected AND can ping out" + prompt_choice FALLBACK_AP_CHECK_MODE "Check mode" "$DEFAULT_CHECK_MODE" link internet +fi + +if [ "$FALLBACK_AP_CHECK_MODE" = "internet" ] && [ -z "${FALLBACK_AP_CHECK_TARGETS:-}" ]; then + prompt FALLBACK_AP_CHECK_TARGETS "Hosts to ping (space-separated)" "$DEFAULT_CHECK_TARGETS" +fi + +export FALLBACK_AP_SSID FALLBACK_AP_PASSWORD FALLBACK_AP_IFACE FALLBACK_AP_CIDR FALLBACK_AP_DHCP_START_OCTET FALLBACK_AP_DHCP_END_OCTET +export FALLBACK_AP_CHECK_MODE +[ -n "${FALLBACK_AP_MONITOR_IFACE+x}" ] && export FALLBACK_AP_MONITOR_IFACE +[ -n "${FALLBACK_AP_IGNORE_IFACE+x}" ] && export FALLBACK_AP_IGNORE_IFACE +[ -n "${FALLBACK_AP_CHECK_TARGETS+x}" ] && export FALLBACK_AP_CHECK_TARGETS + +echo echo "Downloading fallback-ap..." curl -fsSL "$SCRIPT_URL" -o "$INSTALL_PATH" chmod +x "$INSTALL_PATH" echo "Running installer..." -"$INSTALL_PATH" install +"$INSTALL_PATH" install \ No newline at end of file