diff options
Diffstat (limited to 'package/cfgfs/src/fwcf.sh')
-rw-r--r-- | package/cfgfs/src/fwcf.sh | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/package/cfgfs/src/fwcf.sh b/package/cfgfs/src/fwcf.sh new file mode 100644 index 000000000..ad75ee79e --- /dev/null +++ b/package/cfgfs/src/fwcf.sh @@ -0,0 +1,384 @@ +#!/bin/sh +#- +# Copyright (c) 2006, 2007 +# Thorsten Glaser <tg@mirbsd.de> +# Copyright (c) 2009 +# Waldemar Brodkorb <openadk@waldemar-brodkorb.de> +# +# Provided that these terms and disclaimer and all copyright notices +# are retained or reproduced in an accompanying document, permission +# is granted to deal in this work without restriction, including un- +# limited rights to use, publicly perform, distribute, sell, modify, +# merge, give away, or sublicence. +# +# This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to +# the utmost extent permitted by applicable law, neither express nor +# implied; without malicious intent or gross negligence. In no event +# may a licensor, author or contributor be held liable for indirect, +# direct, other damage, loss, or other issues arising in any way out +# of dealing in the work, even if advised of the possibility of such +# damage or existence of a defect, except proven that it results out +# of said person's immediate fault when using the work as intended. +#- +# Possible return values: +# 0 - everything ok +# 1 - syntax error +# 1 - no 'cfgfs' mtd/cf partition found +# 1 - cfgfs erase: failed +# 1 - cfgfs setup: already run +# 3 - cfgfs setup: mount --bind problems +# 4 - cfgfs setup: can't create or write to temporary filesystem +# 5 - cfgfs setup: can't bind the tmpfs to /etc +# 6 - cfgfs commit: cannot write to partition +# 6 - cfgfs restore: cannot write to partition +# 7 - cfgfs commit: won't write to flash because of unclean setup +# 8 - cfgfs status: differences found +# 9 - cfgfs status: old status file not found +# 10 - cfgfs dump: failed +# 11 - cfgfs commit: cfgfs setup not yet run (use -f to force) +# 11 - cfgfs status: cfgfs setup not yet run +# 12 - cfgfs restore: cannot read the backup +# 255 - cfgfs erase: failed +# 255 - internal error + +export PATH=/bin:/sbin:/usr/bin:/usr/sbin +wd=$(pwd) +cd / +what='Configuration Filesystem (cfgfs), Version 1.06' + +usage() { + cat >&2 <<EOF +$what +Usage: + { halt | poweroff | reboot } [-Ffn] [-d delay] + cfgfs { commit | erase | setup | status | dump | restore } [flags] +EOF + exit 1 +} + +case $0 in +(*cfgfs*) me=cfgfs ;; +(*halt*) me=halt ;; +(*poweroff*) me=poweroff ;; +(*reboot*) me=reboot ;; +(*) usage ;; +esac + +if [[ $me != cfgfs ]]; then + integer dflag=0 + dval= + integer fflag=0 + integer nocfgfs=0 + integer nflag=0 + while getopts ":d:Ffn" ch; do + case $ch in + (d) dflag=1; dval=$OPTARG ;; + (F) nocfgfs=1 ;; + (f) fflag=1 ;; + (n) nflag=1 ;; + (*) usage ;; + esac + done + shift $((OPTIND - 1)) + + (( nocfgfs == 0 && fflag == 0 )) && if ! cfgfs status -q; then + echo "error: will not $me: unsaved changes in /etc found!" + echo "Either run 'cfgfs commit' before trying to $me" + echo "or retry with '$me -F${*+ }$*' to force a ${me}." + echo "Run 'cfgfs status' to see which files are changed." + exit 2 + fi + + (( fflag )) && me="$me -f" + (( nflag )) && me="$me -n" + (( dflag )) && me="$me -d '$dval'" + eval exec busybox $me +fi + +case $1 in +(commit|erase|setup|status|dump|restore) ;; +(*) cat >&2 <<EOF +$what +Syntax: + $0 commit [-f] + $0 erase + $0 setup [-N] + $0 status [-rq] + $0 { dump | restore } [<filename>] +EOF + exit 1 ;; +esac + +uname=$(uname -m) +if [[ "$uname" = "i586" ]];then + part=/dev/sda2 +else + part=/dev/mtd$(fgrep '"cfgfs"' /proc/mtd 2>/dev/null | sed 's/^mtd\([^:]*\):.*$/\1/')ro +fi + +if [[ ! -e $part ]]; then + echo 'cfgfs: fatal error: no "cfgfs" partition found!' + exit 1 +fi + +if test $1 = erase; then + dd if="$part" 2>&1 | md5sum 2>&1 >/dev/urandom + cfgfs.helper -Me | cfgfs.write + exit $? +fi + +if test $1 = setup; then + if test -e /tmp/.cfgfs; then + echo 'cfgfs: error: "cfgfs setup" already run!' + exit 1 + fi + mkdir /tmp/.cfgfs + if test ! -d /tmp/.cfgfs; then + echo 'cfgfs: error: cannot create temporary directory!' + exit 4 + fi + chown 0:0 /tmp/.cfgfs + chmod 700 /tmp/.cfgfs + mkdir /tmp/.cfgfs/root + mount --bind /etc /tmp/.cfgfs/root + mkdir /tmp/.cfgfs/temp + mount -t tmpfs -o size=960k cfgfs /tmp/.cfgfs/temp + (cd /tmp/.cfgfs/root; tar cf - .) | (cd /tmp/.cfgfs/temp; tar xpf -) + unclean=0 + if [[ $1 = -N ]]; then + unclean=2 + else + x=$(dd if="$part" bs=4 count=1 2>/dev/null) + [[ "$x" = "FWCF" ]] || cfgfs.helper -Me | cfgfs.write + if ! cfgfs.helper -U /tmp/.cfgfs/temp <"$part"; then + unclean=1 + echo 'cfgfs: error: cannot extract' + echo unclean startup | logger -t 'cfgfs setup' + fi + if test -e /tmp/.cfgfs/temp/.cfgfs_deleted; then + while IFS= read -r file; do + rm -f "/tmp/.cfgfs/temp/$file" + done </tmp/.cfgfs/temp/.cfgfs_deleted + rm -f /tmp/.cfgfs/temp/.cfgfs_deleted + fi + fi + test $unclean = 0 || echo -n >/tmp/.cfgfs/temp/.cfgfs_unclean + rm -f /tmp/.cfgfs/temp/.cfgfs_done + if test -e /tmp/.cfgfs/temp/.cfgfs_done; then + echo 'cfgfs: fatal: this is not Kansas any more' + umount /tmp/.cfgfs/temp + umount /tmp/.cfgfs/root + rm -rf /tmp/.cfgfs + exit 3 + fi + echo -n >/tmp/.cfgfs/temp/.cfgfs_done + if test ! -e /tmp/.cfgfs/temp/.cfgfs_done; then + echo 'cfgfs: fatal: cannot write to tmpfs' + umount /tmp/.cfgfs/temp + umount /tmp/.cfgfs/root + rm -rf /tmp/.cfgfs + exit 4 + fi + chmod 755 /tmp/.cfgfs/temp + mount --bind /tmp/.cfgfs/temp /etc + if test ! -e /etc/.cfgfs_done; then + umount /etc + echo 'cfgfs: fatal: binding to /etc failed' + if test $unclean = 0; then + echo 'cfgfs: configuration is preserved' \ + in /tmp/.cfgfs/temp + else + umount /tmp/.cfgfs/temp + fi + exit 5 + fi + umount /tmp/.cfgfs/temp + echo complete, unclean=$unclean | logger -t 'cfgfs setup' + cd /etc + rm -f .rnd + find . -type f | grep -v -e '^./.cfgfs' -e '^./.rnd$' | sort | \ + xargs md5sum | sed 's! ./! !' | \ + cfgfs.helper -Z - /tmp/.cfgfs/status.asz + exit 0 +fi + +if test $1 = commit; then + umount /tmp/.cfgfs/temp >/dev/null 2>&1 + if test ! -e /tmp/.cfgfs; then + cat >&2 <<-EOF + cfgfs: error: not yet initialised + explanation: "cfgfs setup" was not yet run + EOF + [[ $1 = -f ]] || exit 11 + fi + if test -e /etc/.cfgfs_unclean; then + cat >&2 <<-EOF + cfgfs: error: unclean startup (or setup run with -N)! + explanation: during boot, the cfgfs filesystem could not + be extracted; saving the current /etc to flash will + result in data loss; to override this check, remove + the file /etc/.cfgfs_unclean and try again. + EOF + [[ $1 = -f ]] || exit 7 + fi + mount -t tmpfs -o size=960k swap /tmp/.cfgfs/temp + (cd /etc; tar cf - .) | (cd /tmp/.cfgfs/temp; tar xpf -) + cd /tmp/.cfgfs/temp + find . -type f | grep -v -e '^./.cfgfs' -e '^./.rnd$' | sort | \ + xargs md5sum | sed 's! ./! !' | \ + cfgfs.helper -Z - /tmp/.cfgfs/status.asz + cd /tmp/.cfgfs/root + rm -f /tmp/.cfgfs/temp/.cfgfs_* /tmp/.cfgfs/temp/.rnd + find /tmp/.cfgfs/temp -type d -empty -delete + find . -type f | while read f; do + f=${f#./} + if [[ ! -e /tmp/.cfgfs/temp/$f ]]; then + [[ $f = .rnd ]] && continue + printf '%s\n' "$f" >>/tmp/.cfgfs/temp/.cfgfs_deleted + continue + fi + x=$(md5sum "$f" 2>/dev/null) + y=$(cd ../temp; md5sum "$f" 2>/dev/null) + [[ "$x" = "$y" ]] && rm "../temp/$f" + done + rv=0 + if ! ( cfgfs.helper -M /tmp/.cfgfs/temp | cfgfs.write ); then + echo 'cfgfs: error: cannot write to $part!' + rv=6 + fi + umount /tmp/.cfgfs/temp + exit $rv +fi + +if test $1 = status; then + if test ! -e /tmp/.cfgfs; then + cat >&2 <<-EOF + cfgfs: error: not yet initialised + explanation: "cfgfs setup" was not yet run + EOF + [[ $1 = -f ]] || exit 11 + fi + rm -f /tmp/.cfgfs/*_status /tmp/.cfgfs/*_files + rflag=0 + q=printf # or : (true) if -q + shift + while getopts "rq" ch; do + case $ch in + (r) rflag=1 ;; + (q) q=: ;; + esac + done + shift $((OPTIND - 1)) + if test $rflag = 1; then + f=/tmp/.cfgfs/rom_status + cd /tmp/.cfgfs/root + find . -type f | grep -v -e '^./.cfgfs' -e '^./.rnd$' | sort | \ + xargs md5sum | sed 's! ./! !' >$f + else + f=/tmp/.cfgfs/status + cfgfs.helper -Zd $f.asz $f || rm -f $f + fi + if [[ ! -e $f ]]; then + echo 'cfgfs: error: old status file not found' + exit 9 + fi + cd /etc + find . -type f | grep -v -e '^./.cfgfs' -e '^./.rnd$' | sort | \ + xargs md5sum | sed 's! ./! !' >/tmp/.cfgfs/cur_status || exit 255 + cd /tmp/.cfgfs + sed 's/^[0-9a-f]* //' <$f >old_files + sed 's/^[0-9a-f]* //' <cur_status >cur_files + # make *_status be of exactly the same length, for benefit of the + # while ... read <old, read <new loop below, and sort it + comm -23 old_files cur_files | while read name; do + echo "<NULL> $name" >>cur_status + done + comm -13 old_files cur_files | while read name; do + echo "<NULL> $name" >>$f + done + # this implementation of sort -o sucks: doesn't do in-place edits + sort -k2 -o sold_status $f + sort -k2 -o snew_status cur_status + gotany=0 + while :; do + IFS=' ' read oldsum oldname <&3 || break + IFS=' ' read newsum newname <&4 || exit 255 + [[ "$oldname" = "$newname" ]] || exit 255 + [[ "$oldsum" = "$newsum" ]] && continue + [[ $gotany = 0 ]] && $q '%-32s %-32s %s\n' \ + 'MD5 hash of old file' 'MD5 hash of new file' 'filename' + gotany=8 + test $q = : && break + $q '%32s %32s %s\n' "$oldsum" "$newsum" "$oldname" + done 3<sold_status 4<snew_status + rm -f /tmp/.cfgfs/*_status /tmp/.cfgfs/*_files + exit $gotany +fi + +if test $1 = dump; then + fn=$2 + [[ -n $fn ]] || fn=- + rm -rf /tmp/.cfgfs.dump + mkdir -m 0700 /tmp/.cfgfs.dump + cd /tmp/.cfgfs.dump + if ! cat "$part" | cfgfs.helper -UD dump; then + cd / + rm -rf /tmp/.cfgfs.dump + exit 10 + fi + dd if=/dev/urandom of=seed bs=256 count=1 >/dev/null 2>&1 + tar -cf - dump seed | (cd "$wd"; cfgfs.helper -Z - $fn) + cd / + rm -rf /tmp/.cfgfs.dump + case $fn in + (-) echo "cfgfs: dump to standard output complete." + ;; + (*) echo "cfgfs: dump to '$fn' complete." + ls -l "$fn" >&2 + ;; + esac + exit 0 +fi + +if test $1 = restore; then + if test -e /tmp/.cfgfs; then + echo 'cfgfs: warning: "cfgfs setup" already run!' + echo 'please reboot after restoring; in no event' + echo 'run "cfgfs commit" to prevent data loss' + echo -n >/etc/.cfgfs_unclean + fi + fn=$2 + [[ -n $fn ]] || fn=- + rm -rf /tmp/.cfgfs.restore + mkdir -m 0700 /tmp/.cfgfs.restore + cd /tmp/.cfgfs.restore + if ! (cd "$wd"; cfgfs.helper -Zd "$fn") | tar -xf -; then + cd / + rm -rf /tmp/.cfgfs.restore + exit 12 + fi + dd if=seed of=/dev/urandom bs=256 count=1 >/dev/null 2>&1 + if test ! -e dump; then + echo 'cfgfs: error: invalid backup' + cd / + rm -rf /tmp/.cfgfs.restore + exit 12 + fi + if ! ( cfgfs.helper -MD dump | cfgfs.write ); then + echo 'cfgfs: error: cannot write to $part!' + exit 6 + fi + cd / + rm -rf /tmp/.cfgfs.restore + case $fn in + (-) echo "cfgfs: restore from standard output complete." + ;; + (*) echo "cfgfs: restore from '$fn' complete." + ls -l "$fn" >&2 + ;; + esac + exit 0 +fi + +echo 'cfgfs: cannot be reached...' +exit 255 |