mirror of
https://github.com/OpenSolo/OpenSolo.git
synced 2025-04-29 22:24:32 +02:00
286 lines
7.8 KiB
Bash
Executable File
286 lines
7.8 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# SoloLink Configuration file validate/restore
|
|
#
|
|
# Called at init time before any config files are used via an entry in
|
|
# /etc/rcS.d.
|
|
|
|
cd /etc
|
|
|
|
verbose=false
|
|
|
|
# arguments
|
|
# -v verbose
|
|
until [ -z "$1" ]; do
|
|
case $1 in
|
|
-v) verbose=true;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
dmsg() {
|
|
if ${verbose}; then echo "$@"; fi
|
|
}
|
|
|
|
# Test mode: Ubuntu md5sum is a bit different from busybox md5sum
|
|
# /usr/bin/md5sum is a symlink if it points to busybox
|
|
if [ -h `which md5sum` ]; then
|
|
# assume busybox
|
|
# not test mode
|
|
MD5SUM="md5sum -cs"
|
|
ETC="/etc"
|
|
ROFS="/mnt/rootfs.ro"
|
|
kmsg() {
|
|
echo "$@" > /dev/kmsg
|
|
}
|
|
else
|
|
# assume not busybox; correct for ubuntu but not tested on os-x
|
|
# test mode
|
|
MD5SUM="md5sum -c --status"
|
|
ETC="./etc"
|
|
ROFS="./rootfs.ro"
|
|
kmsg() {
|
|
echo "$@"
|
|
}
|
|
fi
|
|
|
|
kmsg -n "Checking SoloLink configuration... "
|
|
dmsg ""
|
|
|
|
config_names="hostapd wpa_supplicant sololink shotmanager"
|
|
|
|
# For each file "file" in ${config_names}:
|
|
#
|
|
# A new FS contains only "file.orig"
|
|
#
|
|
# First boot:
|
|
# 1. file.conf does not exist
|
|
# 2. file.back does not exist
|
|
# 3. copy file.orig to file.base (used for upgrade merge)
|
|
# 4. copy file.orig to file.conf
|
|
# 5. create file.conf.md5
|
|
#
|
|
# Subsequent boots:
|
|
# 1. file.conf exists
|
|
# 2. file.conf.md5 is good
|
|
#
|
|
# Program modification of a config file (not in this script):
|
|
# 1. copy file.conf to file.back
|
|
# 2. create file.back.md5
|
|
# 3. modify file.conf
|
|
# 4. create file.conf.md5
|
|
#
|
|
# Manual modification of a config file (e.g. via console or ssh):
|
|
# 1. edit file.conf
|
|
# 2. md5sum <full-path-to-file.conf> > <full-path-to-file.conf.md5>
|
|
#
|
|
# During the modification process, a shutdown can result in any of the
|
|
# following (numbers match completion of steps above):
|
|
# 1. file.conf valid, file.back invalid (file.conf is used)
|
|
# 2. file.conf valid, file.back valid (file.conf used)
|
|
# 3. file.conf invalid, file.back valid (file.conf rollback)
|
|
# 4. file.conf valid, file.back valid (file.conf used)
|
|
#
|
|
# Example recovery:
|
|
# 1. file.conf exists
|
|
# 2. file.conf.md5 is not good
|
|
# 3. file.back exists
|
|
# 4. file.back.md5 is good
|
|
# 5. copy file.back to file.conf
|
|
# 6. create file.conf.md5
|
|
#
|
|
# Example upgrade:
|
|
# 1. file.conf exists
|
|
# 2. file.conf.md5 is good
|
|
# 3. file.orig.md5 exists
|
|
# 4. file.orig.md5 is not good (because file.orig changed)
|
|
# 5. patch = file.base -> file.conf; previous changes (e.g. setting ssid)
|
|
# 6. apply patch to new file.orig, creating file.conf
|
|
# 7. create file.conf.md5
|
|
# 8. create file.orig.md5
|
|
# 9. copy file.orig to file.base
|
|
# 10. create file.base.md5
|
|
#
|
|
# Example upgrade (merge fails):
|
|
# 1. file.conf exists
|
|
# 2. file.conf.md5 is good
|
|
# 3. file.orig.md5 exists
|
|
# 4. file.orig.md5 is not good (because file.orig changed)
|
|
# 5. file.base is not good (does not exist)
|
|
# 6. copy file.orig to file.conf
|
|
# 7. create file.conf.md5
|
|
# 8. create file.orig.md5
|
|
# 9. copy file.orig to file.base
|
|
# 10. create file.base.md5
|
|
|
|
# Return true if file exists, md5 exists, and the md5 is correct
|
|
valid() {
|
|
[ -f ${1} ] && [ -f ${1}.md5 ] && ${MD5SUM} ${1}.md5
|
|
}
|
|
|
|
# Return true if orig.md5 does not exist, or it exists but is not correct
|
|
upgraded() {
|
|
[ ! -f ${1}.orig.md5 ] || ! ${MD5SUM} ${1}.orig.md5
|
|
}
|
|
|
|
# Create backup of .conf
|
|
do_backup() {
|
|
dmsg "backup ${1}.conf -> ${1}.back"
|
|
cp ${1}.conf ${1}.back
|
|
md5sum `realpath ${1}.back` > ${1}.back.md5
|
|
}
|
|
|
|
# Restore one file to another, i.e. .back or .orig to .conf
|
|
do_restore() {
|
|
dmsg "copy ${1} -> ${2}"
|
|
cp ${1} ${2}
|
|
md5sum `realpath ${2}` > ${2}.md5
|
|
}
|
|
|
|
# Note that the busybox 'patch' we are using is relatively limited:
|
|
# patch [-p NUM] [-i DIFF] [-R] [-N]
|
|
# -p NUM Strip NUM leading components from file names
|
|
# -i DIFF Read DIFF instead of stdin
|
|
# -R Reverse patch
|
|
# -N Ignore already applied patches
|
|
#
|
|
# Busybox patch's return status is not documented. GNU patch's return is this:
|
|
# patch's exit status is 0 if all hunks are applied successfully, 1 if some
|
|
# hunks cannot be applied or there were merge conflicts, and 2 if there is
|
|
# more serious trouble.
|
|
# We assume here it is zero on success, nonzero on any failure.
|
|
do_patch() {
|
|
#dmsg "patch ${1}.conf"
|
|
patch ${1}.conf < ${1}.patch
|
|
# patch's return code is this function's return code
|
|
}
|
|
|
|
# Merge changes.
|
|
#
|
|
# config.base is a copy of the previous config.orig (before this update)
|
|
# config.conf is that, plus any changes the user has made
|
|
# config.orig is the _new_ config for this update
|
|
#
|
|
# 1. config.base -> config.conf is what has changed from the previous
|
|
# config.orig to the previous config.conf. Create a patch from that.
|
|
#
|
|
# 2. Attempt to apply the patch to the _new_ config.orig.
|
|
#
|
|
# a. If the patch applies cleanly, the new config.conf is the new
|
|
# config.orig plus patch.
|
|
#
|
|
# b. If the patch does not apply cleanly, the new config.conf is just
|
|
# copied from the new config.orig (changes are lost).
|
|
#
|
|
# Argument is the config file name root, e.g. "hostapd" means we are working
|
|
# with hostapd.base, hostapd.conf, and hostapd.orig.
|
|
#
|
|
do_merge() {
|
|
dmsg "merge ${1}"
|
|
|
|
# config.conf is known to be valid at this point
|
|
|
|
if valid ${1}.base; then
|
|
# config.base is valid; try to merge changes into new config
|
|
|
|
# config.patch is the user's changes in the pre-upgrade system
|
|
diff -au ${1}.base ${1}.conf > ${1}.patch
|
|
|
|
# start with upgraded config.conf...
|
|
do_backup ${1}
|
|
cp ${1}.orig ${1}.conf
|
|
|
|
# apply user's changes
|
|
if ! do_patch ${1}; then
|
|
# some hunks failed - partial patching seems confusing, so revert it all
|
|
dmsg "patch ${1}.conf failed"
|
|
dmsg "copy ${1}.orig -> ${1}.conf"
|
|
cp ${1}.orig ${1}.conf
|
|
fi
|
|
|
|
# .conf is good now, either updated or just copied
|
|
md5sum `realpath ${1}.conf` > ${1}.conf.md5
|
|
rm -f ${1}.patch ${1}.back* ${1}.conf.orig
|
|
|
|
else
|
|
# config.base is not valid, can't merge
|
|
dmsg "${1}.base not valid; can't merge"
|
|
dmsg "copy ${1}.orig -> ${1}.conf"
|
|
cp ${1}.orig ${1}.conf
|
|
md5sum `realpath ${1}.conf` > ${1}.conf.md5
|
|
fi
|
|
|
|
# this is how we detect when the next upgrade happens
|
|
md5sum `realpath ${1}.orig` > ${1}.orig.md5
|
|
|
|
# new config.base will be used in the next upgrade
|
|
cp ${1}.orig ${1}.base
|
|
md5sum `realpath ${1}.base` > ${1}.base.md5
|
|
}
|
|
|
|
# Loop over all config files, validating and perhaps restoring each one
|
|
for config_name in ${config_names}; do
|
|
config=${ETC}/${config_name}
|
|
|
|
# skip any that are not in the read-only FS (e.g. shotmanager on controller)
|
|
if [ ! -f ${ROFS}/etc/${config_name}.orig ]; then
|
|
continue
|
|
fi
|
|
|
|
dmsg ""
|
|
dmsg "${config_name}... "
|
|
|
|
if valid ${config}.conf; then
|
|
dmsg "${config}.conf is valid"
|
|
|
|
if upgraded ${config}; then
|
|
kmsg -n "merging ${config}... "
|
|
dmsg ""
|
|
# typical just after an upgrade if .orig file changes
|
|
do_merge ${config}
|
|
else
|
|
# typical startup
|
|
dmsg "done"
|
|
fi
|
|
|
|
elif valid ${config}.back; then
|
|
dmsg "${config}.back is valid"
|
|
|
|
# previous shutdown corrupted the .conf file
|
|
kmsg -n "restoring ${config}.conf... "
|
|
dmsg ""
|
|
do_restore ${config}.back ${config}.conf
|
|
if upgraded ${config}; then
|
|
kmsg -n "merging ${config}... "
|
|
dmsg ""
|
|
# edge case: previous shutdown prepared update and corrupted .conf file
|
|
do_merge ${config}
|
|
else
|
|
dmsg "done"
|
|
fi
|
|
|
|
else
|
|
dmsg "neither ${config}.conf nor ${config}.back is valid"
|
|
|
|
# typical on first boot
|
|
kmsg -n "initializing ${config}.conf... "
|
|
dmsg ""
|
|
if [ ! -f ${config}.orig ]; then
|
|
kmsg -n "${config}.orig not found; retrieving from ${ROFS}/etc/${config_name}.orig... "
|
|
dmsg ""
|
|
cp ${ROFS}/etc/${config_name}.orig ${config}.orig
|
|
fi
|
|
dmsg "copy ${config}.orig -> ${config}.base"
|
|
cp ${config}.orig ${config}.base
|
|
md5sum `realpath ${config}.base` > ${config}.base.md5
|
|
do_restore ${config}.orig ${config}.conf
|
|
md5sum `realpath ${config}.orig` > ${config}.orig.md5
|
|
dmsg "done"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
dmsg ""
|
|
kmsg "OK"
|