summaryrefslogtreecommitdiff
path: root/package/cfgfs/src/fwcf.sh
diff options
context:
space:
mode:
Diffstat (limited to 'package/cfgfs/src/fwcf.sh')
-rw-r--r--package/cfgfs/src/fwcf.sh384
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