134 lines
3.2 KiB
Bash
Executable File
134 lines
3.2 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# Check that everything is present
|
|
for bin in mktemp sha256sum rm rmdir curl printf chmod cat uci; do
|
|
if ! which "$bin" >/dev/null 2>&1; then
|
|
echo "Failed to find $bin. Make sure it resides in \$PATH" >&2
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
CONFDIR="$(mktemp -p /tmp -d "configsync.XXXXXXXXX")" || return 1
|
|
CFGPATH="$CONFDIR/config"
|
|
CSUMPATH="$CONFDIR/checksum"
|
|
CAPATH="$CONFDIR/ca.crt"
|
|
CERTPATH="$CONFDIR/cert.crt"
|
|
KEYPATH="$CONFDIR/key.crt"
|
|
ROLLBACKPATH="/etc/uci-defaults/00-rollback-config"
|
|
CONFIGSAVE="configsync.configdata"
|
|
TIMEOUT="10"
|
|
|
|
cleanup() {
|
|
trap - EXIT
|
|
rm -v "$CFGPATH" "$CSUMPATH" "$CAPATH" "$CERTPATH" "$KEYPATH"
|
|
rmdir "$CONFDIR"
|
|
}
|
|
|
|
trap 'cleanup' EXIT INT HUP
|
|
|
|
exp_cfg() {
|
|
# Export config for rollback
|
|
EXPORT="$(uci export)" || return
|
|
printf '%s\n%s\n%s\n%s\n%s\n' \
|
|
'#!/bin/sh' \
|
|
'uci import <<EOF' \
|
|
"$EXPORT" \
|
|
'EOF' \
|
|
'reload_config' > "$ROLLBACKPATH"
|
|
chmod +x "$ROLLBACKPATH"
|
|
}
|
|
|
|
run_cfg() {
|
|
chmod +x "$CFGPATH"
|
|
uci set "$CONFIGSAVE".currentcsum="$(cat "$CSUMPATH")"
|
|
"$CFGPATH"
|
|
}
|
|
|
|
rollback() {
|
|
local badcsum="$(uci -q get "$CONFIGSAVE".currentcsum)"
|
|
|
|
# Rollback if config commit has been attempted
|
|
if [ -x "$ROLLBACKPATH" ]; then
|
|
rm -rv /tmp/.uci # Clean up any pending changes not commited yet
|
|
if "$ROLLBACKPATH"; then
|
|
echo "rolled back last known working config" >&2
|
|
uci set "$CONFIGSAVE".lastbadcsum="$badcsum" # Mark current checksum as bad
|
|
uci commit
|
|
rm -v "$ROLLBACKPATH"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ret=1 ca="" cert="" key=""
|
|
uci get "$CONFIGSAVE".ca > "$CAPATH" && ca="$CAPATH"
|
|
uci get "$CONFIGSAVE".cert > "$CERTPATH" && cert="$CERTPATH"
|
|
uci get "$CONFIGSAVE".key > "$KEYPATH" && key="$KEYPATH"
|
|
|
|
currentcsum="$(uci -q get "$CONFIGSAVE".currentcsum)"
|
|
badcsum="$(uci -q get "$CONFIGSAVE".lastbadcsum)"
|
|
|
|
for endpoint in $(uci get "$CONFIGSAVE".endpoints); do
|
|
if ! curl -sSfL \
|
|
${ca:+'--cacert' "$ca"} \
|
|
${cert:+'--cert' "$cert"} \
|
|
${key:+'--key' "$key"} \
|
|
-m "$TIMEOUT" \
|
|
"$endpoint/checksum" -o "$CSUMPATH"; then
|
|
echo "${endpoint}: failed to fetch csum, trying next endpoint" >&2
|
|
continue
|
|
fi
|
|
expcsum="$(cat "$CSUMPATH")"
|
|
|
|
if [ "$expcsum" == "$badcsum" ]; then
|
|
echo "${endpoint}/${expcsum}: known bad config, not re-fetching" >&2
|
|
ret=0
|
|
break
|
|
fi
|
|
if [ "$expcsum" == "$currentcsum" ]; then
|
|
echo "${endpoint}/${expcsum}: config already applied, not re-fetching" >&2
|
|
ret=0
|
|
break
|
|
fi
|
|
|
|
if ! curl -sSfL \
|
|
${ca:+'--cacert' "$ca"} \
|
|
${cert:+'--cert' "$cert"} \
|
|
${key:+'--key' "$key"} \
|
|
-m "$TIMEOUT" \
|
|
"$endpoint/config" -o "$CFGPATH"; then
|
|
echo "${endpoint}/${expcsum}: failed to fetch cfg, trying next endpoint" >&2
|
|
continue
|
|
fi
|
|
cfgcsum="$(sha256sum "$CFGPATH" | cut -d' ' -f1)"
|
|
|
|
if [ "$expcsum" != "$cfgcsum" ]; then
|
|
echo "${endpoint}/${expcsum}: sha256 checksum mismatched, discarding" >&2
|
|
ret=0
|
|
break
|
|
fi
|
|
|
|
if ! exp_cfg; then
|
|
echo "failed to export current config, exiting" >&2
|
|
break
|
|
fi
|
|
|
|
if ! run_cfg; then
|
|
echo "${endpoint}/${expcsum}: failed to apply new config, attempting rollback" >&2
|
|
break
|
|
fi
|
|
|
|
echo "${endpoint}/${expcsum}: applied" >&2
|
|
ret=0
|
|
break
|
|
done
|
|
|
|
if [ "$ret" -ne 0 ]; then
|
|
if ! rollback; then
|
|
echo "failed to rollback previous config, resetting to factory" >&2
|
|
firstboot -y
|
|
reboot
|
|
fi
|
|
fi
|
|
|
|
return $ret
|