Add canonical boot configuration synchronization

This commit is contained in:
v3d 2026-06-30 16:29:51 +02:00
parent 254a9b9cf3
commit eda151065c
14 changed files with 424 additions and 50 deletions

View file

@ -16,12 +16,14 @@ select choice in "Enable" "Disable"; do
case "$choice" in
Enable)
backup_gallery
/usr/local/lib/pivilion/config-sync.sh set PIVILION_GENERATOR_ENABLED yes
a2ensite 000-upload.conf >/dev/null
systemctl reload apache2
install -d -m 2775 -o www-data -g www-data "$PIVILION_WEBROOT/gen/upload"
echo "Generator enabled at http://<device-address>:81/"
break ;;
Disable)
/usr/local/lib/pivilion/config-sync.sh set PIVILION_GENERATOR_ENABLED no
a2dissite 000-upload.conf >/dev/null || true
systemctl reload apache2
echo "Generator disabled."

View file

@ -3,5 +3,5 @@ set -euo pipefail
source /usr/local/lib/pivilion/common.sh
[ "$(id -u)" -eq 0 ] || exec sudo "$0" "$@"
pivilion_load_config
pivilion_set_mode hotspot
/usr/local/lib/pivilion/config-sync.sh set PIVILION_MODE hotspot
echo "Pivilion will start in open hotspot mode after the next reboot."

View file

@ -3,7 +3,7 @@ set -euo pipefail
source /usr/local/lib/pivilion/common.sh
[ "$(id -u)" -eq 0 ] || exec sudo "$0" "$@"
pivilion_load_config
pivilion_set_mode onion
/usr/local/lib/pivilion/config-sync.sh set PIVILION_MODE onion
echo "Pivilion will start in onion mode after the next reboot."
if [ -s "$PIVILION_DIR/torname" ]; then
printf 'Your onion domain is %s\n' "$(tr -d '\r\n' < "$PIVILION_DIR/torname")"

View file

@ -3,9 +3,6 @@ set -euo pipefail
source /usr/local/lib/pivilion/common.sh
[ "$(id -u)" -eq 0 ] || exec sudo "$0" "$@"
pivilion_load_config
IFACE=$(pivilion_wifi_interface)
[ -n "$IFACE" ] || { echo "No Wi-Fi interface found." >&2; exit 1; }
read -r -p "Wi-Fi SSID: " ssid
read -r -s -p "Wi-Fi password: " password
printf '\n'
@ -14,22 +11,6 @@ printf '\n'
echo "WPA password must contain 8-63 characters." >&2; exit 1;
}
if pivilion_uses_networkmanager; then
nmcli connection delete pivilion-onion >/dev/null 2>&1 || true
nmcli connection add type wifi ifname "$IFACE" con-name pivilion-onion ssid "$ssid" >/dev/null
nmcli connection modify pivilion-onion 802-11-wireless.mode infrastructure \
802-11-wireless-security.key-mgmt wpa-psk 802-11-wireless-security.psk "$password" \
ipv4.method auto ipv6.method auto connection.autoconnect yes
else
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
wpa_passphrase "$ssid" "$password" | sed '/^[[:space:]]*#psk=/d' > "$tmp"
install -d -m 0755 /etc/wpa_supplicant
install -m 0600 "$tmp" /etc/wpa_supplicant/pivilion.conf
touch /etc/wpa_supplicant/wpa_supplicant.conf
grep -Fqx 'include=/etc/wpa_supplicant/pivilion.conf' /etc/wpa_supplicant/wpa_supplicant.conf || \
printf '\ninclude=/etc/wpa_supplicant/pivilion.conf\n' >> /etc/wpa_supplicant/wpa_supplicant.conf
chmod 0600 /etc/wpa_supplicant/wpa_supplicant.conf
fi
/usr/local/lib/pivilion/config-sync.sh set-wifi "$ssid" "$password"
unset password
echo "Wi-Fi credentials saved. Run onion and reboot when ready."
echo "Wi-Fi credentials saved as a derived PSK in the boot configuration. Run onion and reboot when ready."

View file

@ -25,7 +25,7 @@ _pivilion_trim() {
_pivilion_config_value() {
local key=$1 file line name value config_paths
config_paths=${PIVILION_CONFIG_PATHS:-/boot/firmware/pivilion.conf /boot/pivilion.conf /etc/pivilion.conf /etc/pivilion.defaults}
config_paths=${PIVILION_CONFIG_PATHS:-/run/pivilion/effective.conf $(pivilion_boot_config_path) /etc/pivilion.conf /etc/pivilion.defaults}
for file in $config_paths; do
[ -r "$file" ] || continue
while IFS= read -r line || [ -n "$line" ]; do
@ -68,13 +68,29 @@ pivilion_load_config() {
PIVILION_HOTSPOT_SSID=${configured:-pivilion}
configured=$(_pivilion_config_value PIVILION_WIFI_INTERFACE || true)
PIVILION_WIFI_INTERFACE=${configured:-}
configured=$(_pivilion_config_value PIVILION_WIFI_SSID || true)
PIVILION_WIFI_SSID=${configured:-}
configured=$(_pivilion_config_value PIVILION_WIFI_PSK || true)
PIVILION_WIFI_PSK=${configured:-}
configured=$(_pivilion_config_value PIVILION_WIFI_PSK_FOR_SSID || true)
PIVILION_WIFI_PSK_FOR_SSID=${configured:-}
configured=$(_pivilion_config_value PIVILION_WIFI_COUNTRY || true)
PIVILION_WIFI_COUNTRY=${configured:-HR}
configured=$(_pivilion_config_value PIVILION_HOTSPOT_CHANNEL || true)
PIVILION_HOTSPOT_CHANNEL=${configured:-6}
configured=$(_pivilion_config_value PIVILION_HOSTNAME || true)
PIVILION_HOSTNAME=${configured:-$(hostname -s 2>/dev/null || uname -n)}
configured=$(_pivilion_config_value PIVILION_GENERATOR_ENABLED || true)
PIVILION_GENERATOR_ENABLED=${configured:-no}
configured=$(_pivilion_config_value PIVILION_UPLOAD_MAX_SIZE || true)
PIVILION_UPLOAD_MAX_SIZE=${configured:-256M}
case "$PIVILION_MODE" in onion|hotspot) ;; *) echo "PIVILION_MODE must be onion or hotspot" >&2; return 1 ;; esac
ssid_bytes=$(LC_ALL=C printf '%s' "$PIVILION_HOTSPOT_SSID" | wc -c)
[ "$ssid_bytes" -ge 1 ] && [ "$ssid_bytes" -le 32 ] || {
echo "PIVILION_HOTSPOT_SSID must contain 1-32 bytes" >&2; return 1;
}
case "$PIVILION_HOME$PIVILION_DIR$PIVILION_WEBROOT$PIVILION_WIFI_INTERFACE$PIVILION_HOTSPOT_SSID" in
case "$PIVILION_HOME$PIVILION_DIR$PIVILION_WEBROOT$PIVILION_WIFI_INTERFACE$PIVILION_HOTSPOT_SSID$PIVILION_WIFI_SSID$PIVILION_WIFI_PSK" in
*$'\n'*|*$'\r'*) echo "Invalid control character in Pivilion configuration" >&2; return 1 ;;
esac
case "$PIVILION_HOME:$PIVILION_DIR:$PIVILION_WEBROOT" in
@ -86,9 +102,32 @@ pivilion_load_config() {
[ -z "$PIVILION_WIFI_INTERFACE" ] || [[ "$PIVILION_WIFI_INTERFACE" =~ ^[A-Za-z0-9._:-]+$ ]] || {
echo "Invalid PIVILION_WIFI_INTERFACE" >&2; return 1;
}
[[ "$PIVILION_WIFI_COUNTRY" =~ ^[A-Z]{2}$ ]] || { echo "PIVILION_WIFI_COUNTRY must be a two-letter uppercase country code" >&2; return 1; }
[[ "$PIVILION_HOTSPOT_CHANNEL" =~ ^[0-9]+$ ]] && [ "$PIVILION_HOTSPOT_CHANNEL" -ge 1 ] && [ "$PIVILION_HOTSPOT_CHANNEL" -le 13 ] || {
echo "PIVILION_HOTSPOT_CHANNEL must be between 1 and 13" >&2; return 1;
}
[[ "$PIVILION_HOSTNAME" =~ ^[A-Za-z0-9][A-Za-z0-9.-]{0,62}$ ]] || { echo "Invalid PIVILION_HOSTNAME" >&2; return 1; }
case "$PIVILION_GENERATOR_ENABLED" in yes|no) ;; *) echo "PIVILION_GENERATOR_ENABLED must be yes or no" >&2; return 1 ;; esac
[[ "$PIVILION_UPLOAD_MAX_SIZE" =~ ^[1-9][0-9]*M$ ]] || { echo "PIVILION_UPLOAD_MAX_SIZE must use a value such as 256M" >&2; return 1; }
if [ -n "$PIVILION_WIFI_PSK" ] && [[ ! "$PIVILION_WIFI_PSK" =~ ^[0-9A-Fa-f]{64}$ ]] && { [ "${#PIVILION_WIFI_PSK}" -lt 8 ] || [ "${#PIVILION_WIFI_PSK}" -gt 63 ]; }; then
echo "PIVILION_WIFI_PSK must be an 8-63 character password or 64 hexadecimal PSK" >&2; return 1
fi
[ -z "$PIVILION_WIFI_PSK" ] || [ -n "$PIVILION_WIFI_SSID" ] || { echo "PIVILION_WIFI_SSID is required when a PSK is set" >&2; return 1; }
export PIVILION_USER PIVILION_GROUP PIVILION_HOME PIVILION_DIR PIVILION_WEBROOT PIVILION_MODE PIVILION_HOTSPOT_SSID PIVILION_WIFI_INTERFACE
export PIVILION_WIFI_SSID PIVILION_WIFI_PSK PIVILION_WIFI_PSK_FOR_SSID PIVILION_WIFI_COUNTRY PIVILION_HOTSPOT_CHANNEL
export PIVILION_HOSTNAME PIVILION_GENERATOR_ENABLED PIVILION_UPLOAD_MAX_SIZE
}
pivilion_boot_root() {
if [ -n "${PIVILION_BOOT_ROOT:-}" ]; then printf '%s\n' "$PIVILION_BOOT_ROOT"; return; fi
if command -v mountpoint >/dev/null 2>&1 && mountpoint -q /boot/firmware; then printf '/boot/firmware\n'; return; fi
if [ -d /boot/firmware ] && { [ -e /boot/firmware/config.txt ] || [ -e /boot/firmware/cmdline.txt ]; }; then printf '/boot/firmware\n'; return; fi
printf '/boot\n'
}
pivilion_boot_config_path() { printf '%s/pivilion.conf\n' "$(pivilion_boot_root)"; }
pivilion_boot_error_path() { printf '%s/pivilion-error.txt\n' "$(pivilion_boot_root)"; }
pivilion_wifi_interface() {
local iface
if [ -n "${PIVILION_WIFI_INTERFACE:-}" ]; then printf '%s\n' "$PIVILION_WIFI_INTERFACE"; return; fi
@ -116,9 +155,7 @@ pivilion_set_mode() {
}
pivilion_current_mode() {
local mode
mode=$(head -n1 "$PIVILION_DIR/mode" 2>/dev/null || true)
case "$mode" in onion|hotspot) printf '%s\n' "$mode" ;; *) printf '%s\n' "$PIVILION_MODE" ;; esac
printf '%s\n' "$PIVILION_MODE"
}
pivilion_require_root() {

View file

@ -0,0 +1,286 @@
#!/bin/bash
set -Eeuo pipefail
source "${PIVILION_COMMON_PATH:-/usr/local/lib/pivilion/common.sh}"
pivilion_require_root
BOOT_ROOT=$(pivilion_boot_root)
BOOT_CONFIG=$(pivilion_boot_config_path)
BOOT_ERROR=$(pivilion_boot_error_path)
LAST_GOOD=${PIVILION_LAST_GOOD:-/var/lib/pivilion/pivilion.conf.last-good}
LOCK_FILE=${PIVILION_CONFIG_LOCK:-/run/pivilion-config.lock}
ACTION=${1:-apply}
install -d -m 0755 "$(dirname "$LOCK_FILE")" /var/lib/pivilion
exec 9>"$LOCK_FILE"
flock -x 9
fail_boot() {
local message=$1 tmp
printf 'Pivilion configuration error: %s\n' "$message" >&2
if [ -d "$BOOT_ROOT" ] && [ -w "$BOOT_ROOT" ]; then
tmp=$(mktemp "$BOOT_ROOT/.pivilion-error.XXXXXX")
printf '%s\n' "$message" > "$tmp"
mv -f "$tmp" "$BOOT_ERROR"
sync -f "$BOOT_ROOT" 2>/dev/null || sync
fi
}
require_writable_boot() {
[ -d "$BOOT_ROOT" ] && [ -w "$BOOT_ROOT" ] && touch "$BOOT_ROOT/.pivilion-write-test.$$" 2>/dev/null || {
fail_boot "The boot partition root $BOOT_ROOT is missing or read-only"
exit "$PIVILION_E_CONFIG"
}
rm -f "$BOOT_ROOT/.pivilion-write-test.$$"
}
atomic_copy() {
local source=$1 destination=$2 mode=${3:-0600} tmp
install -d -m 0700 "$(dirname "$destination")"
tmp=$(mktemp "$(dirname "$destination")/.pivilion.XXXXXX")
install -m "$mode" "$source" "$tmp"
mv -f "$tmp" "$destination"
}
derive_psk() {
local ssid=$1 password=$2
if command -v wpa_passphrase >/dev/null 2>&1; then
wpa_passphrase "$ssid" "$password" | awk -F= '/^[[:space:]]*psk=[0-9a-f]{64}$/ {print $2; exit}'
elif command -v python3 >/dev/null 2>&1; then
printf '%s\n%s\n' "$ssid" "$password" | python3 -c 'import hashlib,sys; s=sys.stdin.buffer.readline().rstrip(b"\n"); p=sys.stdin.buffer.readline().rstrip(b"\n"); print(hashlib.pbkdf2_hmac("sha1",p,s,4096,32).hex())'
else
fail_boot "wpa_passphrase or python3 is required to sanitize the Wi-Fi password"
return 1
fi
}
detect_wifi() {
local connection file
[ -n "${PIVILION_WIFI_SSID:-}" ] && return
if command -v nmcli >/dev/null 2>&1; then
connection=$(nmcli -t -f NAME,TYPE connection show --active 2>/dev/null | awk -F: '$2 ~ /wireless|wifi/ {print $1; exit}')
if [ -n "$connection" ]; then
PIVILION_WIFI_SSID=$(nmcli -g 802-11-wireless.ssid connection show "$connection" 2>/dev/null || true)
PIVILION_WIFI_PSK=$(nmcli --show-secrets -g 802-11-wireless-security.psk connection show "$connection" 2>/dev/null || true)
fi
fi
if [ -z "${PIVILION_WIFI_SSID:-}" ]; then
for file in /etc/wpa_supplicant/pivilion.conf /etc/wpa_supplicant/wpa_supplicant.conf; do
[ -r "$file" ] || continue
PIVILION_WIFI_SSID=$(sed -n 's/^[[:space:]]*ssid="\(.*\)"/\1/p' "$file" | head -n1)
PIVILION_WIFI_PSK=$(sed -n 's/^[[:space:]]*psk="\(.*\)"/\1/p; s/^[[:space:]]*psk=\([0-9a-fA-F]\{64\}\)$/\1/p' "$file" | head -n1)
[ -n "$PIVILION_WIFI_SSID" ] && break
done
fi
}
sanitize_wifi() {
local derived
[ -n "$PIVILION_WIFI_SSID" ] || { PIVILION_WIFI_PSK=""; PIVILION_WIFI_PSK_FOR_SSID=""; return; }
if [[ "$PIVILION_WIFI_PSK" =~ ^[0-9A-Fa-f]{64}$ ]]; then
if [ -n "$PIVILION_WIFI_PSK_FOR_SSID" ] && [ "$PIVILION_WIFI_PSK_FOR_SSID" != "$PIVILION_WIFI_SSID" ]; then
fail_boot "Wi-Fi SSID changed but its stored derived PSK belongs to a different SSID"
return 1
fi
PIVILION_WIFI_PSK=${PIVILION_WIFI_PSK,,}
elif [ -n "$PIVILION_WIFI_PSK" ]; then
derived=$(derive_psk "$PIVILION_WIFI_SSID" "$PIVILION_WIFI_PSK") || return 1
[ -n "$derived" ] || { fail_boot "Could not derive the Wi-Fi PSK"; return 1; }
PIVILION_WIFI_PSK=$derived
fi
PIVILION_WIFI_PSK_FOR_SSID=$PIVILION_WIFI_SSID
}
render_config() {
local active onion error
active=$(pivilion_state_value active_mode none)
onion=$(tr -d '\r\n' < "$PIVILION_DIR/torname" 2>/dev/null || true)
error=$(pivilion_state_value failure none)
cat <<EOF
# Pivilion boot configuration. Edit this file while the boot partition is mounted.
# A 64-character Wi-Fi PSK grants network access just like the original password.
# With no saved upstream network, leave the next three Wi-Fi fields empty.
# To add one offline, set SSID and an 8-63 character password in PIVILION_WIFI_PSK.
# Last applied: $(date --iso-8601=seconds)
# Active mode: $active
# Detected interface: $(pivilion_wifi_interface || printf unknown)
# Onion hostname: ${onion:-unknown}
# Last error: ${error:-none}
PIVILION_MODE=$PIVILION_MODE
PIVILION_WIFI_SSID=$PIVILION_WIFI_SSID
PIVILION_WIFI_PSK=$PIVILION_WIFI_PSK
PIVILION_WIFI_PSK_FOR_SSID=$PIVILION_WIFI_PSK_FOR_SSID
PIVILION_WIFI_COUNTRY=$PIVILION_WIFI_COUNTRY
PIVILION_WIFI_INTERFACE=$PIVILION_WIFI_INTERFACE
PIVILION_HOTSPOT_SSID=$PIVILION_HOTSPOT_SSID
PIVILION_HOTSPOT_CHANNEL=$PIVILION_HOTSPOT_CHANNEL
PIVILION_HOSTNAME=$PIVILION_HOSTNAME
PIVILION_USER=$PIVILION_USER
PIVILION_HOME=$PIVILION_HOME
PIVILION_DIR=$PIVILION_DIR
PIVILION_WEBROOT=$PIVILION_WEBROOT
PIVILION_GENERATOR_ENABLED=$PIVILION_GENERATOR_ENABLED
PIVILION_UPLOAD_MAX_SIZE=$PIVILION_UPLOAD_MAX_SIZE
EOF
}
write_canonical() {
local tmp
require_writable_boot
tmp=$(mktemp "$BOOT_ROOT/.pivilion-conf.XXXXXX")
render_config > "$tmp"
chmod 0600 "$tmp"
mv -f "$tmp" "$BOOT_CONFIG"
sync -f "$BOOT_ROOT" 2>/dev/null || sync
atomic_copy "$BOOT_CONFIG" "$LAST_GOOD" 0600
atomic_copy "$BOOT_CONFIG" /run/pivilion/effective.conf 0600
rm -f "$BOOT_ERROR"
}
load_boot_or_detect() {
if [ -e "$BOOT_CONFIG" ]; then
PIVILION_CONFIG_PATHS=$BOOT_CONFIG pivilion_load_config || return 1
else
pivilion_load_config
if [ -s "$PIVILION_DIR/mode" ]; then
case "$(head -n1 "$PIVILION_DIR/mode")" in onion|hotspot) PIVILION_MODE=$(head -n1 "$PIVILION_DIR/mode") ;; esac
fi
PIVILION_WIFI_INTERFACE=${PIVILION_WIFI_INTERFACE:-$(pivilion_wifi_interface || true)}
PIVILION_HOSTNAME=${PIVILION_HOSTNAME:-$(hostname -s)}
if command -v a2query >/dev/null 2>&1 && a2query -s 000-upload >/dev/null 2>&1; then PIVILION_GENERATOR_ENABLED=yes; fi
if command -v php >/dev/null 2>&1; then
detected_upload=$(php -r 'echo ini_get("upload_max_filesize");' 2>/dev/null || true)
[[ "$detected_upload" =~ ^[1-9][0-9]*M$ ]] && PIVILION_UPLOAD_MAX_SIZE=$detected_upload
fi
detect_wifi
fi
PIVILION_WIFI_INTERFACE=${PIVILION_WIFI_INTERFACE:-$(pivilion_wifi_interface || true)}
sanitize_wifi
}
migrate_paths() {
local old_dir old_webroot common=${PIVILION_COMMON_PATH:-/usr/local/lib/pivilion/common.sh}
[ -r "$LAST_GOOD" ] || return 0
old_dir=$(PIVILION_CONFIG_PATHS=$LAST_GOOD bash -c 'source "$1"; pivilion_load_config >/dev/null && printf %s "$PIVILION_DIR"' _ "$common" 2>/dev/null || true)
old_webroot=$(PIVILION_CONFIG_PATHS=$LAST_GOOD bash -c 'source "$1"; pivilion_load_config >/dev/null && printf %s "$PIVILION_WEBROOT"' _ "$common" 2>/dev/null || true)
if [ -n "$old_dir" ] && [ "$old_dir" != "$PIVILION_DIR" ] && [ -d "$old_dir" ] && [ ! -e "$PIVILION_DIR" ]; then
install -d -m 0755 -o "$PIVILION_USER" -g "$PIVILION_GROUP" "$PIVILION_DIR"
cp -a "$old_dir/." "$PIVILION_DIR/"
chown -R "$PIVILION_USER:$PIVILION_GROUP" "$PIVILION_DIR"
fi
if [ -n "$old_webroot" ] && [ "$old_webroot" != "$PIVILION_WEBROOT" ] && [ -d "$old_webroot" ] && [ ! -e "$PIVILION_WEBROOT" ]; then
install -d -m 2775 -o www-data -g www-data "$PIVILION_WEBROOT"
cp -a "$old_webroot/." "$PIVILION_WEBROOT/"
fi
if [ -n "$old_webroot" ] && [ "$old_webroot" != "$PIVILION_WEBROOT" ]; then
for file in /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-upload.conf /etc/apache2/conf-available/pivilion.conf; do
[ -f "$file" ] || continue
sed "s|$old_webroot|$PIVILION_WEBROOT|g" "$file" > "$file.pivilion.tmp"
install -m 0644 "$file.pivilion.tmp" "$file"
rm -f "$file.pivilion.tmp"
done
fi
}
apply_runtime() {
local php_version post_mb escaped_ssid
migrate_paths
if [ "$(hostname -s)" != "$PIVILION_HOSTNAME" ] && command -v hostnamectl >/dev/null 2>&1; then hostnamectl set-hostname "$PIVILION_HOSTNAME"; fi
command -v iw >/dev/null 2>&1 && iw reg set "$PIVILION_WIFI_COUNTRY" 2>/dev/null || true
if [ -n "$PIVILION_WIFI_SSID" ] && [ -n "$PIVILION_WIFI_PSK" ]; then
if command -v nmcli >/dev/null 2>&1 && { systemctl is-enabled --quiet NetworkManager 2>/dev/null || systemctl is-active --quiet NetworkManager 2>/dev/null; }; then
install -d -m 0700 /etc/NetworkManager/system-connections
cat > /etc/NetworkManager/system-connections/.pivilion-onion.tmp <<EOF
[connection]
id=pivilion-onion
type=wifi
interface-name=$PIVILION_WIFI_INTERFACE
autoconnect=true
[wifi]
mode=infrastructure
ssid=$PIVILION_WIFI_SSID
[wifi-security]
key-mgmt=wpa-psk
psk=$PIVILION_WIFI_PSK
[ipv4]
method=auto
[ipv6]
method=auto
EOF
install -m 0600 /etc/NetworkManager/system-connections/.pivilion-onion.tmp /etc/NetworkManager/system-connections/pivilion-onion.nmconnection
rm -f /etc/NetworkManager/system-connections/.pivilion-onion.tmp
elif command -v wpa_passphrase >/dev/null 2>&1; then
install -d -m 0755 /etc/wpa_supplicant
escaped_ssid=${PIVILION_WIFI_SSID//\\/\\\\}; escaped_ssid=${escaped_ssid//\"/\\\"}
printf 'country=%s\nnetwork={\n ssid="%s"\n psk=%s\n}\n' "$PIVILION_WIFI_COUNTRY" "$escaped_ssid" "$PIVILION_WIFI_PSK" > /etc/wpa_supplicant/.pivilion.tmp
install -m 0600 /etc/wpa_supplicant/.pivilion.tmp /etc/wpa_supplicant/pivilion.conf
rm -f /etc/wpa_supplicant/.pivilion.tmp
fi
fi
install -d -m 0755 -o "$PIVILION_USER" -g "$PIVILION_GROUP" "$PIVILION_DIR"
printf '%s\n' "$PIVILION_MODE" | install -m 0644 -o "$PIVILION_USER" -g "$PIVILION_GROUP" /dev/stdin "$PIVILION_DIR/mode"
if command -v php >/dev/null 2>&1; then
printf "<?php\ndefine('PIVILION_DIR', '%s');\ndefine('PIVILION_WEBROOT', '%s');\n" "$PIVILION_DIR" "$PIVILION_WEBROOT" | install -m 0644 /dev/stdin /etc/pivilion.php
fi
if command -v php >/dev/null 2>&1; then
php_version=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
post_mb=$((${PIVILION_UPLOAD_MAX_SIZE%M} + 16))
install -d -m 0755 "/etc/php/$php_version/apache2/conf.d"
printf 'upload_max_filesize = %s\npost_max_size = %sM\nmax_file_uploads = 100\nmax_execution_time = 300\nmemory_limit = 512M\n' "$PIVILION_UPLOAD_MAX_SIZE" "$post_mb" \
| install -m 0644 /dev/stdin "/etc/php/$php_version/apache2/conf.d/99-pivilion.ini"
fi
if command -v a2ensite >/dev/null 2>&1; then
if [ "$PIVILION_GENERATOR_ENABLED" = yes ]; then a2ensite 000-upload.conf >/dev/null; else a2dissite 000-upload.conf >/dev/null 2>&1 || true; fi
fi
}
set_value() {
local key=${2:-} value=${3-} tmp
case "$key" in
PIVILION_MODE|PIVILION_WIFI_SSID|PIVILION_WIFI_PSK|PIVILION_WIFI_PSK_FOR_SSID|PIVILION_WIFI_COUNTRY|PIVILION_WIFI_INTERFACE|PIVILION_HOTSPOT_SSID|PIVILION_HOTSPOT_CHANNEL|PIVILION_HOSTNAME|PIVILION_USER|PIVILION_HOME|PIVILION_DIR|PIVILION_WEBROOT|PIVILION_GENERATOR_ENABLED|PIVILION_UPLOAD_MAX_SIZE) ;;
*) echo "Unsupported configuration key: $key" >&2; exit "$PIVILION_E_CONFIG" ;;
esac
[ -r "$BOOT_CONFIG" ] || { echo "Boot configuration is not initialized." >&2; exit "$PIVILION_E_CONFIG"; }
tmp=$(mktemp)
awk -v key="$key" -v value="$value" 'BEGIN{done=0} $0 ~ "^" key "=" {if(!done){print key "=" value; done=1}; next} {print} END{if(!done) print key "=" value}' "$BOOT_CONFIG" > "$tmp"
PIVILION_CONFIG_PATHS=$tmp pivilion_load_config || { rm -f "$tmp"; exit "$PIVILION_E_CONFIG"; }
sanitize_wifi || { rm -f "$tmp"; exit "$PIVILION_E_CONFIG"; }
write_canonical
rm -f "$tmp"
}
case "$ACTION" in
apply|initialize)
if ! load_boot_or_detect; then
fail_boot "Invalid pivilion.conf; the last-known-good settings were retained"
[ -r "$LAST_GOOD" ] || exit "$PIVILION_E_CONFIG"
PIVILION_CONFIG_PATHS=$LAST_GOOD pivilion_load_config || exit "$PIVILION_E_CONFIG"
atomic_copy "$LAST_GOOD" /run/pivilion/effective.conf 0600
[ "$ACTION" = initialize ] || apply_runtime
exit 0
fi
[ "$ACTION" = initialize ] || apply_runtime
write_canonical ;;
set) set_value "$@" ;;
set-wifi)
[ "$#" -eq 3 ] || { echo "Usage: config-sync.sh set-wifi SSID PASSWORD" >&2; exit 2; }
[ -r "$BOOT_CONFIG" ] || { echo "Boot configuration is not initialized." >&2; exit "$PIVILION_E_CONFIG"; }
PIVILION_CONFIG_PATHS=$BOOT_CONFIG pivilion_load_config || exit "$PIVILION_E_CONFIG"
case "$2$3" in *$'\n'*|*$'\r'*) echo "Wi-Fi values may not contain newlines" >&2; exit "$PIVILION_E_CONFIG" ;; esac
ssid_bytes=$(LC_ALL=C printf '%s' "$2" | wc -c)
[ "$ssid_bytes" -ge 1 ] && [ "$ssid_bytes" -le 32 ] || { echo "Wi-Fi SSID must contain 1-32 bytes" >&2; exit "$PIVILION_E_CONFIG"; }
PIVILION_WIFI_SSID=$2
PIVILION_WIFI_PSK=$3
PIVILION_WIFI_PSK_FOR_SSID=$2
sanitize_wifi || exit "$PIVILION_E_CONFIG"
write_canonical
;;
sync-status)
PIVILION_CONFIG_PATHS=$BOOT_CONFIG pivilion_load_config || exit "$PIVILION_E_CONFIG"
write_canonical ;;
*) echo "Usage: config-sync.sh apply|initialize|set KEY VALUE|set-wifi SSID PASSWORD|sync-status" >&2; exit 2 ;;
esac

View file

@ -118,7 +118,7 @@ interface=$IFACE
driver=nl80211
ssid=$PIVILION_HOTSPOT_SSID
hw_mode=g
channel=6
channel=$PIVILION_HOTSPOT_CHANNEL
auth_algs=1
wmm_enabled=0
EOF
@ -198,6 +198,7 @@ start_hotspot() {
if [ "$BACKEND" = networkmanager ]; then
nmcli connection add type wifi ifname "$IFACE" con-name "$NM_HOTSPOT" ssid "$PIVILION_HOTSPOT_SSID"
nmcli connection modify "$NM_HOTSPOT" 802-11-wireless.mode ap 802-11-wireless.band bg \
802-11-wireless.channel "$PIVILION_HOTSPOT_CHANNEL" \
ipv4.method manual ipv4.addresses 10.1.1.1/24 ipv4.never-default yes ipv6.method disabled connection.autoconnect no
nmcli connection up "$NM_HOTSPOT"
else
@ -215,6 +216,7 @@ start_hotspot() {
logger -t pivilion-mode "Hotspot active but degraded; run pivilion diagnose" || true
fi
refresh_login_banner
/usr/local/lib/pivilion/config-sync.sh sync-status || logger -t pivilion-mode "Could not mirror hotspot status to the boot partition"
echo "Pivilion hotspot '$PIVILION_HOTSPOT_SSID' is active on $IFACE."
}
@ -240,6 +242,7 @@ start_onion() {
logger -t pivilion-mode "Onion mode active but degraded: ${failure:-diagnostics failed}" || true
fi
refresh_login_banner
/usr/local/lib/pivilion/config-sync.sh sync-status || logger -t pivilion-mode "Could not mirror onion status to the boot partition"
echo "Pivilion onion mode activation completed."
}