First working version for RasPi Zero 2W
This commit is contained in:
Executable
+507
@@ -0,0 +1,507 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Configuration (may be overridden by unattended.sh)
|
||||
# ==============================================================================
|
||||
|
||||
ZEROTIER_VERSION="${ZEROTIER_VERSION:-1.16.2}"
|
||||
SOFTWARE_ROOT="${SOFTWARE_ROOT:-/usr/local/software}"
|
||||
SYSOP_DATA_ROOT="${SYSOP_DATA_ROOT:-/media/sysop}"
|
||||
REQUIRED_SWAP_MIB="${REQUIRED_SWAP_MIB:-2048}"
|
||||
ROOTFS_BUILD_SIZE="${ROOTFS_BUILD_SIZE:-1400M}"
|
||||
MAKE_JOBS="${MAKE_JOBS:-1}"
|
||||
ENABLE_SSO="${ENABLE_SSO:-0}"
|
||||
PREBUILT_BINARY="${PREBUILT_BINARY:-}"
|
||||
|
||||
ZEROTIER_ROOT="$SOFTWARE_ROOT/zerotier"
|
||||
ZEROTIER_VERSIONS="$ZEROTIER_ROOT/versions"
|
||||
ZEROTIER_BUILD_PROFILE="${ZEROTIER_VERSION}-linux-musl-aarch64-sso${ENABLE_SSO}"
|
||||
ZEROTIER_INSTALL="$ZEROTIER_VERSIONS/$ZEROTIER_BUILD_PROFILE"
|
||||
ZEROTIER_STATE="$SYSOP_DATA_ROOT/zerotier"
|
||||
|
||||
BUILD_DIRECTORY="$SOFTWARE_ROOT/.zerotier-build-$ZEROTIER_BUILD_PROFILE"
|
||||
SOURCE_DIRECTORY="$BUILD_DIRECTORY/ZeroTierOne"
|
||||
|
||||
BUILD_DEPS=(
|
||||
build-base
|
||||
linux-headers
|
||||
openssl-dev
|
||||
pkgconf
|
||||
)
|
||||
|
||||
if [[ "$ENABLE_SSO" == "1" ]]; then
|
||||
BUILD_DEPS+=(cargo)
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Helpers and cleanup
|
||||
# ==============================================================================
|
||||
|
||||
BUILD_DEPS_INSTALLED=0
|
||||
BUILD_REQUIRED=1
|
||||
PREBUILT_AVAILABLE=0
|
||||
STATE_WAS_PRESENT=0
|
||||
|
||||
die()
|
||||
{
|
||||
echo "ERROR: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
safe_remove_build_directory()
|
||||
{
|
||||
case "$BUILD_DIRECTORY" in
|
||||
"$SOFTWARE_ROOT"/.zerotier-build-*)
|
||||
rm -rf -- "$BUILD_DIRECTORY"
|
||||
;;
|
||||
*)
|
||||
echo "WARNING: Refusing to remove unexpected path: $BUILD_DIRECTORY" >&2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
release_build_resources()
|
||||
{
|
||||
local result=0
|
||||
|
||||
if (( BUILD_DEPS_INSTALLED == 1 )); then
|
||||
echo "=== Removing ZeroTier build dependencies ==="
|
||||
|
||||
if apk del .zerotier-builddeps; then
|
||||
BUILD_DEPS_INSTALLED=0
|
||||
else
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
|
||||
safe_remove_build_directory
|
||||
return "$result"
|
||||
}
|
||||
|
||||
cleanup_on_exit()
|
||||
{
|
||||
local status=$?
|
||||
|
||||
trap - EXIT
|
||||
set +e
|
||||
release_build_resources
|
||||
exit "$status"
|
||||
}
|
||||
|
||||
migrate_directory_to_state()
|
||||
{
|
||||
local source="$1"
|
||||
|
||||
if [[ -L "$source" ]]; then
|
||||
rm -f -- "$source"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -d "$source" ]]; then
|
||||
cp -a "$source/." "$ZEROTIER_STATE/" 2>/dev/null || true
|
||||
rm -rf -- "$source"
|
||||
elif [[ -e "$source" ]]; then
|
||||
die "Refusing to replace non-directory path: $source"
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup_on_exit EXIT
|
||||
trap 'exit 129' HUP
|
||||
trap 'exit 130' INT
|
||||
trap 'exit 143' TERM
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Validate the Alpine diskless/ZFS environment
|
||||
# ==============================================================================
|
||||
|
||||
[[ $EUID -eq 0 ]] || die "This installer must be run as root."
|
||||
|
||||
for command in apk git lbu mount rc-update
|
||||
do
|
||||
command -v "$command" >/dev/null 2>&1 ||
|
||||
die "Missing required command: $command"
|
||||
done
|
||||
|
||||
[[ -d "$SOFTWARE_ROOT" ]] || die "Missing software dataset mount: $SOFTWARE_ROOT"
|
||||
[[ -d "$SYSOP_DATA_ROOT" ]] || die "Missing sysop dataset mount: $SYSOP_DATA_ROOT"
|
||||
|
||||
SOFTWARE_FILESYSTEM="$({
|
||||
awk -v path="$SOFTWARE_ROOT" '$2 == path { print $3; exit }' /proc/mounts
|
||||
} || true)"
|
||||
|
||||
[[ "$SOFTWARE_FILESYSTEM" == "zfs" ]] ||
|
||||
die "$SOFTWARE_ROOT must be a mounted ZFS dataset, not '${SOFTWARE_FILESYSTEM:-unknown}'."
|
||||
|
||||
case "$REQUIRED_SWAP_MIB" in
|
||||
''|*[!0-9]*) die "REQUIRED_SWAP_MIB must be a positive integer." ;;
|
||||
esac
|
||||
|
||||
case "$MAKE_JOBS" in
|
||||
''|*[!0-9]*) die "MAKE_JOBS must be a positive integer." ;;
|
||||
esac
|
||||
|
||||
case "$ENABLE_SSO" in
|
||||
0|1) ;;
|
||||
*) die "ENABLE_SSO must be either 0 or 1." ;;
|
||||
esac
|
||||
|
||||
(( REQUIRED_SWAP_MIB > 0 )) || die "REQUIRED_SWAP_MIB must be greater than zero."
|
||||
(( MAKE_JOBS > 0 )) || die "MAKE_JOBS must be greater than zero."
|
||||
|
||||
if [[ -x "$ZEROTIER_INSTALL/zerotier-one" ]]; then
|
||||
EXISTING_VERSION="$(
|
||||
"$ZEROTIER_INSTALL/zerotier-one" -v 2>/dev/null || true
|
||||
)"
|
||||
|
||||
if [[ "$EXISTING_VERSION" == "$ZEROTIER_VERSION" ]]; then
|
||||
BUILD_REQUIRED=0
|
||||
else
|
||||
echo "WARNING: Existing ZeroTier binary reports version '${EXISTING_VERSION:-unknown}'; replacing it."
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( BUILD_REQUIRED == 1 )) &&
|
||||
[[ -n "$PREBUILT_BINARY" && -s "$PREBUILT_BINARY" ]]
|
||||
then
|
||||
PREBUILT_AVAILABLE=1
|
||||
BUILD_REQUIRED=0
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Check swap and free space when compilation is needed
|
||||
# ==============================================================================
|
||||
|
||||
if (( BUILD_REQUIRED == 1 )); then
|
||||
ACTIVE_SWAP_KB="$(awk 'NR > 1 { total += $3 } END { print total + 0 }' /proc/swaps)"
|
||||
REQUIRED_SWAP_KB=$((REQUIRED_SWAP_MIB * 1024))
|
||||
|
||||
(( ACTIVE_SWAP_KB >= REQUIRED_SWAP_KB )) ||
|
||||
die "ZeroTier compilation requires at least ${REQUIRED_SWAP_MIB} MiB active swap."
|
||||
|
||||
AVAILABLE_KB="$(df -Pk "$SOFTWARE_ROOT" | awk 'NR == 2 { print $4 }')"
|
||||
REQUIRED_FREE_KB=$((1200 * 1024))
|
||||
|
||||
(( AVAILABLE_KB >= REQUIRED_FREE_KB )) ||
|
||||
die "At least 1200 MB must be free on $SOFTWARE_ROOT for the ZeroTier build."
|
||||
|
||||
echo
|
||||
echo "=== Reusing all active swap devices for compilation ==="
|
||||
grep -E 'MemTotal|SwapTotal|SwapFree' /proc/meminfo
|
||||
elif (( PREBUILT_AVAILABLE == 1 )); then
|
||||
echo
|
||||
echo "=== Using precompiled ZeroTier ${ZEROTIER_VERSION} binary ==="
|
||||
echo "Source: $PREBUILT_BINARY"
|
||||
else
|
||||
echo
|
||||
echo "=== Reusing the existing ZeroTier ${ZEROTIER_VERSION} binary ==="
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Enlarge the temporary RAM root filesystem
|
||||
# ==============================================================================
|
||||
|
||||
if (( BUILD_REQUIRED == 1 )); then
|
||||
ROOT_FILESYSTEM="$(awk '$2 == "/" { print $3; exit }' /proc/mounts)"
|
||||
|
||||
if [[ "$ROOT_FILESYSTEM" == "tmpfs" ]]; then
|
||||
echo
|
||||
echo "=== Enlarging temporary rootfs limit to $ROOTFS_BUILD_SIZE ==="
|
||||
mount -o "remount,size=$ROOTFS_BUILD_SIZE" /
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Install build-only packages
|
||||
# ==============================================================================
|
||||
|
||||
if (( BUILD_REQUIRED == 1 )); then
|
||||
echo
|
||||
echo "=== Installing ZeroTier build dependencies ==="
|
||||
|
||||
if [[ "$ENABLE_SSO" == "1" ]]; then
|
||||
echo "ZeroTier SSO is enabled; Rust/Cargo will be installed."
|
||||
else
|
||||
echo "ZeroTier SSO is disabled; Rust/Cargo are not required."
|
||||
fi
|
||||
|
||||
# --no-cache keeps the compiler toolchain out of the persistent APK cache.
|
||||
# Retry transient Wi-Fi/download failures, cleaning a partial virtual
|
||||
# package before each new attempt.
|
||||
APK_ADD_SUCCEEDED=0
|
||||
for attempt in 1 2 3; do
|
||||
if apk add \
|
||||
--no-cache \
|
||||
--virtual .zerotier-builddeps \
|
||||
"${BUILD_DEPS[@]}"
|
||||
then
|
||||
APK_ADD_SUCCEEDED=1
|
||||
break
|
||||
fi
|
||||
|
||||
echo "WARNING: Build dependency installation attempt $attempt failed."
|
||||
apk del .zerotier-builddeps >/dev/null 2>&1 || true
|
||||
|
||||
if (( attempt < 3 )); then
|
||||
echo "Retrying after $((attempt * 10)) seconds..."
|
||||
sleep $((attempt * 10))
|
||||
fi
|
||||
done
|
||||
|
||||
(( APK_ADD_SUCCEEDED == 1 )) ||
|
||||
die "Could not install ZeroTier build dependencies after 3 attempts."
|
||||
|
||||
BUILD_DEPS_INSTALLED=1
|
||||
|
||||
for command in gcc g++ make pkgconf strip
|
||||
do
|
||||
command -v "$command" >/dev/null 2>&1 ||
|
||||
die "Build dependency did not provide required command: $command"
|
||||
done
|
||||
|
||||
if [[ "$ENABLE_SSO" == "1" ]]; then
|
||||
command -v cargo >/dev/null 2>&1 ||
|
||||
die "SSO build dependency did not provide cargo."
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Download the exact pinned ZeroTier source tag
|
||||
# ==============================================================================
|
||||
|
||||
if (( BUILD_REQUIRED == 1 )); then
|
||||
echo
|
||||
echo "=== Downloading ZeroTier ${ZEROTIER_VERSION} source ==="
|
||||
|
||||
safe_remove_build_directory
|
||||
mkdir -p "$BUILD_DIRECTORY"
|
||||
|
||||
git init "$SOURCE_DIRECTORY"
|
||||
git -C "$SOURCE_DIRECTORY" remote add \
|
||||
origin \
|
||||
https://github.com/zerotier/ZeroTierOne.git
|
||||
|
||||
# Fetch the exact tag ref. This avoids both the earlier git-describe error
|
||||
# on a shallow checkout and ambiguity between branch and tag names.
|
||||
git -C "$SOURCE_DIRECTORY" fetch \
|
||||
--depth 1 \
|
||||
origin \
|
||||
"refs/tags/$ZEROTIER_VERSION:refs/tags/$ZEROTIER_VERSION"
|
||||
|
||||
git -C "$SOURCE_DIRECTORY" checkout \
|
||||
--detach \
|
||||
"refs/tags/$ZEROTIER_VERSION"
|
||||
|
||||
ACTUAL_COMMIT="$(git -C "$SOURCE_DIRECTORY" rev-parse HEAD)"
|
||||
TAG_COMMIT="$(
|
||||
git -C "$SOURCE_DIRECTORY" \
|
||||
rev-parse --verify "refs/tags/$ZEROTIER_VERSION^{commit}"
|
||||
)"
|
||||
|
||||
[[ "$ACTUAL_COMMIT" == "$TAG_COMMIT" ]] ||
|
||||
die "Checked-out commit does not match tag $ZEROTIER_VERSION."
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Build conservatively for the Raspberry Pi Zero 2W
|
||||
# ==============================================================================
|
||||
|
||||
if (( BUILD_REQUIRED == 1 )); then
|
||||
echo
|
||||
echo "=== Building ZeroTier with ${MAKE_JOBS} make job(s) ==="
|
||||
|
||||
(
|
||||
cd "$SOURCE_DIRECTORY"
|
||||
|
||||
# BCM2710A1 does not provide the optional ARMv8 crypto extensions that
|
||||
# ZeroTier's aarch64 makefile otherwise enables by default.
|
||||
sed -i \
|
||||
's/-march=armv8-a+crypto/-march=armv8-a/g' \
|
||||
make-linux.mk
|
||||
|
||||
if grep -q -- '-march=armv8-a+crypto' make-linux.mk; then
|
||||
die "Could not disable ARM crypto-extension instructions."
|
||||
fi
|
||||
|
||||
export TMPDIR="$BUILD_DIRECTORY/tmp"
|
||||
|
||||
if [[ "$ENABLE_SSO" == "1" ]]; then
|
||||
export CARGO_BUILD_JOBS=1
|
||||
export CARGO_INCREMENTAL=0
|
||||
export CARGO_HOME="$BUILD_DIRECTORY/cargo-home"
|
||||
mkdir -p "$CARGO_HOME"
|
||||
fi
|
||||
|
||||
mkdir -p "$TMPDIR"
|
||||
|
||||
make \
|
||||
-j "$MAKE_JOBS" \
|
||||
CC=gcc \
|
||||
CXX=g++ \
|
||||
ZT_CONTROLLER=0 \
|
||||
ZT_SSO_SUPPORTED="$ENABLE_SSO" \
|
||||
one
|
||||
|
||||
strip zerotier-one
|
||||
)
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Install the binary on rpool/software
|
||||
# ==============================================================================
|
||||
|
||||
if (( PREBUILT_AVAILABLE == 1 )); then
|
||||
echo
|
||||
echo "=== Installing precompiled ZeroTier on rpool/software ==="
|
||||
|
||||
mkdir -p "$ZEROTIER_INSTALL"
|
||||
install -m 0755 \
|
||||
"$PREBUILT_BINARY" \
|
||||
"$ZEROTIER_INSTALL/zerotier-one"
|
||||
elif (( BUILD_REQUIRED == 1 )); then
|
||||
echo
|
||||
echo "=== Installing ZeroTier on rpool/software ==="
|
||||
|
||||
mkdir -p "$ZEROTIER_INSTALL"
|
||||
install -m 0755 \
|
||||
"$SOURCE_DIRECTORY/zerotier-one" \
|
||||
"$ZEROTIER_INSTALL/zerotier-one"
|
||||
fi
|
||||
|
||||
mkdir -p "$ZEROTIER_ROOT"
|
||||
ln -sfn "versions/$ZEROTIER_BUILD_PROFILE" "$ZEROTIER_ROOT/current"
|
||||
|
||||
rm -f \
|
||||
/usr/sbin/zerotier-one \
|
||||
/usr/sbin/zerotier-cli \
|
||||
/usr/sbin/zerotier-idtool
|
||||
|
||||
ln -s "$ZEROTIER_ROOT/current/zerotier-one" /usr/sbin/zerotier-one
|
||||
ln -s zerotier-one /usr/sbin/zerotier-cli
|
||||
ln -s zerotier-one /usr/sbin/zerotier-idtool
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Keep identity and future network state under sysop's ZFS-backed area
|
||||
# ==============================================================================
|
||||
|
||||
if [[ -d "$ZEROTIER_STATE" ]] &&
|
||||
find "$ZEROTIER_STATE" -mindepth 1 -print -quit | grep -q .
|
||||
then
|
||||
STATE_WAS_PRESENT=1
|
||||
fi
|
||||
|
||||
mkdir -p "$ZEROTIER_STATE" /sysop /var/lib
|
||||
chmod 0700 "$ZEROTIER_STATE"
|
||||
|
||||
if id sysop >/dev/null 2>&1; then
|
||||
chown sysop:sysop "$ZEROTIER_STATE"
|
||||
fi
|
||||
|
||||
migrate_directory_to_state /sysop/zerotier
|
||||
migrate_directory_to_state /var/lib/zerotier-one
|
||||
|
||||
ln -s "$ZEROTIER_STATE" /sysop/zerotier
|
||||
ln -s /sysop/zerotier /var/lib/zerotier-one
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# OpenRC service
|
||||
# ==============================================================================
|
||||
|
||||
cat >/etc/init.d/zerotier-one <<'OPENRC'
|
||||
#!/sbin/openrc-run
|
||||
|
||||
description="ZeroTier One network virtualization service"
|
||||
|
||||
command="/usr/sbin/zerotier-one"
|
||||
command_background="yes"
|
||||
pidfile="/run/${RC_SVCNAME}.pid"
|
||||
|
||||
depend()
|
||||
{
|
||||
need zfs-mount
|
||||
use net logger
|
||||
after networking
|
||||
}
|
||||
|
||||
start_pre()
|
||||
{
|
||||
if [ ! -d /var/lib/zerotier-one ]; then
|
||||
eerror "Persistent ZeroTier state is unavailable"
|
||||
return 1
|
||||
fi
|
||||
|
||||
modprobe tun >/dev/null 2>&1 || true
|
||||
}
|
||||
OPENRC
|
||||
|
||||
chmod 0755 /etc/init.d/zerotier-one
|
||||
|
||||
grep -qxF tun /etc/modules 2>/dev/null || echo tun >>/etc/modules
|
||||
rc-update add zerotier-one default
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Persist diskless symlinks and service files
|
||||
# ==============================================================================
|
||||
|
||||
for path in \
|
||||
/usr/sbin/zerotier-one \
|
||||
/usr/sbin/zerotier-cli \
|
||||
/usr/sbin/zerotier-idtool \
|
||||
/sysop/zerotier \
|
||||
/var/lib/zerotier-one \
|
||||
/etc/init.d/zerotier-one
|
||||
do
|
||||
lbu include "$path"
|
||||
done
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Verify without joining a network
|
||||
# ==============================================================================
|
||||
|
||||
echo
|
||||
echo "=== Verifying the ZeroTier installation ==="
|
||||
|
||||
if ! INSTALLED_VERSION="$(/usr/sbin/zerotier-one -v 2>/dev/null)"; then
|
||||
die "The ZeroTier binary cannot run on this Raspberry Pi/Alpine system."
|
||||
fi
|
||||
|
||||
echo "$INSTALLED_VERSION"
|
||||
[[ "$INSTALLED_VERSION" == "$ZEROTIER_VERSION" ]] ||
|
||||
die "ZeroTier reports version '$INSTALLED_VERSION', expected '$ZEROTIER_VERSION'."
|
||||
|
||||
if ldd /usr/sbin/zerotier-one 2>&1 | grep -q 'not found'; then
|
||||
ldd /usr/sbin/zerotier-one >&2 || true
|
||||
die "The ZeroTier binary has missing runtime libraries."
|
||||
fi
|
||||
|
||||
if (( STATE_WAS_PRESENT == 0 )) && [[ -d "$ZEROTIER_STATE/networks.d" ]]; then
|
||||
die "A fresh installation unexpectedly contains joined-network configuration."
|
||||
fi
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# Remove toolchain and source tree
|
||||
# ==============================================================================
|
||||
|
||||
echo
|
||||
release_build_resources
|
||||
|
||||
trap - EXIT HUP INT TERM
|
||||
|
||||
echo
|
||||
echo "ZeroTier ${ZEROTIER_VERSION} is installed and enabled for the next boot."
|
||||
echo "Existing identity/configuration is preserved; a fresh install is not joined."
|
||||
Reference in New Issue
Block a user