#!/bin/sh
# sysconf
#
# utility to manipulate system configuration information help
# in a RedBoot SysConf partition
#
# load the utility functions (unless this is being called just
# to load these functions!)
test "$1" != sysconf && . /etc/default/functions

case "$(machine)" in
nslu2)
	kpart="Kernel"
	syspart="SysConf"
	ffspart="Flashdisk";;
*)
	kpart="kernel"
	syspart="sysconfig"
	ffspart="filesystem";;
esac
#
# sysconf_valid
#  return true if the SysConf partition exists and seems to be
#  potentially valid (it starts with a reasonable length).
sysconf_valid(){
	local sysdev
	sysdev="$(mtblockdev $syspart)"
	test -n "$sysdev" -a -b "$sysdev" &&
		devio "<<$sysdev" '!! b.10>s32768<&!'
}

#
# sysconf_read [prefix]
#  read the $syspart partition (if present) writing the result into
#  /etc/default/sysconf, if the result is empty it will be removed.
sysconf_read(){
	local sysdev sedcmd mac config_root
	config_root="$1"
	rm -f /tmp/sysconf.new
	sysdev="$(mtblockdev $syspart)"
	if sysconf_valid
	then
		# Read the defined part of $syspart into /etc/default/sysconf.
		# $syspart has lines of two forms:
		#
		#  [section]
		#  name=value
		#
		# In practice $syspart also contains other stuff, use the command:
		#
		#  devio '<</dev/mtd1;cpb'
		#
		# to examine the current settings.  The badly formatted stuff
		# is removed (to be exact, the sed script selects only lines
		# which match one of the two above).  The lan interface, which
		# on NSLU2 defaults to ixp0, is changed to the correct value for
		# slugos, eth0.  The bootproto, which LinkSys sets to static in
		# manufacturing, is reset to dhcp if the IP is still the
		# original (192.168.1.77)
		sedcmd='/^\[[^][]*\]$/p;'
		# only do the ip_addr and lan_interface fixups on NSLU2
		if test "$(machine)" = nslu2
		then
			sedcmd="$sedcmd"'
				s/^lan_interface=ixp0$/lan_interface=eth0/;
				/^ip_addr=192\.168\.1\.77$/,/^bootproto/s/^bootproto=static$/bootproto=dhcp/;'
		fi
		# always fix up the hardware addr if it is present
		mac="$(config mac)"
		if test -n "$mac"
		then
			sedcmd="$sedcmd"'
				s/^hw_addr=.*$/hw_addr='"$mac"'/;'
		fi
		# and only print lines of the correct form
		sedcmd="$sedcmd"'
			/^[-a-zA-Z0-9_][-a-zA-Z0-9_]*=/p'

		devio "<<$sysdev" cpb fb1,10 | sed -n "$sedcmd" >/tmp/sysconf.new
	fi
	#
	# test the result - sysconf must be non-empty
	if test -s /tmp/sysconf.new
	then
		mv /tmp/sysconf.new "$config_root/etc/default/sysconf"
	else
		rm -f /tmp/sysconf.new
		return 1
	fi
}

#
# sysconf_default [prefix]
#  Provde a default /etc/default/sysconf when there is no $syspart partition,
#  or when it is invalid, this function will read from an existing sysconf,
#  copying the values into the new one.
# sysconf_line tag config-tag
#  write an appropriate line if the config value is non-empty
sysconf_line(){
	config "$2" | {
		local value
		read value
		test -n "$value" && echo "$1"="$value"
	}
}
#
sysconf_default(){
	local config_root
	config_root="$1"
	{	echo '[network]'
		sysconf_line hw_addr mac
		sysconf_line disk_server_name host
		sysconf_line w_d_name domain
		sysconf_line lan_interface iface
		sysconf_line ip_addr ip
		sysconf_line netmask netmask
		sysconf_line gateway gateway
		sysconf_line dns_server1 dns
		sysconf_line dns_server2 dns2
		sysconf_line dns_server3 dns3
		sysconf_line bootproto boot
	} >/tmp/sysconf.new
	mv /tmp/sysconf.new "$config_root/etc/default/sysconf"
}

#
# sysconf_reload [prefix]
#  read the values from /etc/default/sysconf and use these values to set
#  up the following system files:
#
#   /etc/hostname
#   /etc/defaultdomain
#   /etc/resolv.conf
#   /etc/network/interfaces
#   /etc/motd
#
sysconf_reload(){
	local config_root host domain iface boot ip netmask gateway ifname iftype
	config_root="$1"
	host="$(config host)"
	test -n "$host" && echo "$host" >"$config_root/etc/hostname"
	domain="$(config domain)"
	test -n "$domain" && echo "$domain" >"$config_root/etc/defaultdomain"
	#
	# The DNS server information gives up to three nameservers,
	# but this currently only binds in the first.
	{
		test -n "$domain" && echo "search $domain"
		test -n "$(config dns)" && echo "nameserver $(config dns)"
		test -n "$(config dns2)" && echo "nameserver $(config dns2)"
		test -n "$(config dns3)" && echo "nameserver $(config dns3)"
	} >"$config_root/etc/resolv.conf"
	#
	# Ethernet information.  This goes into /etc/network/interfaces,
	# however this is only used for static setup (and this is not
	# the default).  With dhcp the slugos udhcp script,
	# /etc/udhcpc.d/50default, loads the values from sysconf.
	iface="$(config iface)"
	boot="$(config boot)"
	# Only dhcp and static are supported at present - bootp
	# support requires installation of appropriate packages
	# dhcp is the fail-safe
	case "$boot" in
	dhcp|static) ;;
	*) boot=dhcp;;
	esac
	#
	ip="$(config ip)"
	netmask="$(config netmask)"
	gateway="$(config gateway)"
	{
		echo "# /etc/network/interfaces"
		echo "# configuration file for ifup(8), ifdown(8)"
		echo "#"
		echo "# The loopback interface"
		echo "auto lo"
		echo "iface lo inet loopback"
		echo "#"
		echo "# The interface used by default during boot"
		echo "auto $iface"
		echo "# Automatically generated from /etc/default/sysconf"
		echo "# address, netmask and gateway are ignored for 'dhcp'"
		echo "# but required for 'static'"
		echo "iface $iface inet $boot"
		# The following are ignored for DHCP but are harmless
		test -n "$ip"      && echo "	address $ip"
		test -n "$netmask" && echo "	netmask $netmask"
		test -n "$gateway" && echo "	gateway $gateway"
		#
		# Now read all the other ARPHRD_ETHER (type=1) interfaces
		# and add an entry for each.
		for ifname in $(test -d /sys/class/net && ls /sys/class/net)
		do
			if test -r "/sys/class/net/$ifname/type" -a "$ifname" != "$iface"
			then
				read iftype <"/sys/class/net/$ifname/type"
				case "$iftype" in
				1)	echo "#"
					echo "# /sys/class/net/$ifname:"
					echo "auto $ifname"
					echo "iface $ifname inet dhcp";;
				esac
			fi
		done
	} >"$config_root/etc/network/interfaces"
	#
	# Finally rewrite /etc/motd
	{	echo "Host name:           $host"
		echo "Domain name:         $domain"
		echo "Host MAC:            $(config mac)"
		echo "Network boot method: $boot"
		case "$boot" in
		static) echo "Host IP address:     $ip";;
		esac
		echo "Use 'turnup init' to reset the configuration"
		echo "Use 'turnup preserve' to save the configuration permanently"
		echo "Use 'turnup restore' to restore a previously saved configuration"
		echo "Use 'turnup disk|nfs -i <device> options to initialise a non-flash root"
		echo "Use 'turnup help' for more information"
	} >"$config_root/etc/motd"
}

#
# sysconf_save_conffiles <flash-directory> <dest> <list>
#  preserve the configuration files in a directory or in a CPIO archive
#  (which is *not* compressed).  If <dest> is a directory the files are
#  copied, otherwise a CPIO archive is made with that name.  <list> is
#  the listing file giving the preserved files and the processing option.
sysconf_save_conffiles(){
	local ffsdir dest list file
	ffsdir="$1"
	saved="$2"
	list="$3"
	test -n "$ffsdir" -a -r "$ffsdir/etc/default/conffiles" -a -n "$saved" -a -n "$list" || {
		echo "sysconf_save_conffiles: invalid arguments: '$*'" >&2
		echo " usage sysconf_save_conffiles <flash-directory> <dest> <list>" >&2
		return 1
	}
	#
	(	cd "$ffsdir"
		find etc/*.conf $(sed 's!^/!!' usr/lib/opkg/info/*.conffiles) ! -type d -newer etc/.configured -print |
			sed 's/^/diff /'
		exec sed 's/#.*$//;/^[ 	]*$/d' etc/default/conffiles
	) | sed 's!^/*!!' |
	awk '{ op=$1; $1=""; file[$0]=op }
		END{ for (f in file) if (file[f] != "ignore") print file[f] f }' |
	while read op file
	do
		if test -e "$ffsdir/$file"
		then
			echo "$op $file" >&3
			echo "$file"
		fi
	done 3>"$list" | (
		cd "$ffsdir"
		if test -d "$saved"
		then
			exec cpio -p -d -m -u "$saved"
		else
			exec cpio -o -H crc >"$saved"
		fi
	)
}

#
# sysconf_verify file
#  this is called with the name of a 'diff' file which is, indeed,
#  different and with all the std streams connected to the tty.  It
#  returns a status code to say whether (0) or not (1) to copy the
#  file over.
#
# globals: the following must be defined in the calling context!
#  saved:  the directory containing the unpacked saved files
#  ffsdir: the flash directory to which the files are being restored (/)
#
sysconf_verify_help() {
	echo "Please specify how to handle this file or link, the options are as follows,"
	echo "two character abbreviations may be used:"
	echo
	echo " keep:    retain the old file, overwrite the new flash image file"
	echo " upgrade: retain the new file, the old (saved) file is not used"
	echo " diff:    display the differences between the old and the new using diff -u"
	echo " shell:   temporarily start an interactive shell (sh -i), exit to continue"
	echo " skip:    ignore this file for the moment.  The file is left in the directory"
	echo "          $saved and many be handled after this script has completed"
}
#
sysconf_verify() {
	local command file

	# return 1 here causes the file not to be overwritten,
	# control should never get here!
	test -n "$sysconf_noninteractive" && {
		echo "$0: $*: changed file cannot be handled non-interactively" >&2
		return 1
	}

	file="$1"
	echo "$0: $file: configuration file changed."
	sysconf_verify_help "$file"
	while :
	do
		echo -n "option: "
		read command
		case "$command" in
		ke*)	return 0;;
		up*)	rm "$saved/$file"
			return 1;;
		di*)	echo "DIFF OLD($saved) NEW($ffsdir)"
			diff -u "$saved/$file" "$ffsdir/$file";;
		sh*)	PS1="$file: " sh -i;;
		sk*)	return 1;;
		*)	sysconf_verify_help "$file";;
		esac
	done
}
# the same, but for a link
sysconf_verify_link() {
	local command link

	# return 1 here causes the file not to be overwritten,
	# control should never get here!
	test -n "$sysconf_noninteractive" && {
		echo "$0: $*: changed link cannot be handled non-interactively" >&2
		return 1
	}

	link="$1"
	echo "reflash: $link: configuration link changed."
	sysconf_verify_help "$link"
	while :
	do
		echo -n "option: "
		read command
		case "$command" in
		ke*)	return 0;;
		up*)	rm "$saved/$link"
			return 1;;
		di*)	echo "DIFF:"
			echo "OLD($saved): $link -> $(readlink "$saved/$link")"
			echo "NEW($ffsdir): $link -> $(readlink "$ffsdir/$link")";;
		sh*)	PS1="$link: " sh -i;;
		sk*)	return 1;;
		*)	sysconf_verify_help "$link";;
		esac
	done
}

#
# sysconf_restore_conffiles <flash-directory> <source-dir> <restore>
#  restore the configuration files from a directory.  'source-dir'
#  If <source> is a directory of files from sysconf_save_conffiles.  The
#  list of files restored is written to the third argument (restore),
#  but is not required (/dev/null would be ok).
#
#  the list of files to restore is read from stdin, along with the
#  processing option for each file (the format is as produced by
#  sysconf_save_conffiles in the 'list' output).
sysconf_restore_conffiles(){
	local ffsdir saved restore
	# these are the globals used by the above function
	ffsdir="$1"
	saved="$2"
	restore="$3"
	test -n "$ffsdir" -a -r "$ffsdir/etc/default/conffiles" -a -d "$saved" -a -n "$restore" || {
		echo "restore_conffiles: invalid arguments: '$*'" >&2
		echo " usage sysconf_restore_conffiles <flash-directory> <source-dir> <list>" >&2
		return 1
	}
	#
	# read the list and process each given file
	while read op file
	do
		# handle .configured specially (to preserve the original datestamp)
		if test "$file" = "etc/.configured"
		then
			# this should definately not fail because of the test above!
			if cp -a "$saved/$file" "$ffsdir/$file"
			then
				echo "$file" >&3
			else
				echo "sysconf_restore_conffiles: $file: timestamp copy failed (ignored)" >&2
			fi
		elif test -h "$saved/file" -o -h "$ffsdir/$file"
		then
			# new or old symbolic link
			if test -h "$saved/$file" -a -h "$ffsdir/$file" &&
				test "$(readlink "$saved/$file")" = "$(readlink "$ffsdir/$file")"
			then
				# no change
				echo "$file" >&3
			else
				# assume a change regardless
				case "$op" in
				preserve)
					echo "$file"
					echo "$file" >&3;;
				diff)	# need user input
					if sysconf_verify_link "$file" <>/dev/tty >&0 2>&0
					then
						echo "$file"
						echo "$file" >&3
					fi;;
				esac
			fi
		else
			# only overwrite if necessary
			if test -e "$ffsdir/$file" && cmp -s "$saved/$file" "$ffsdir/$file"
			then
				# do not overwrite
				echo "$file" >&3
			elif test ! -e "$ffsdir/$file"
			then
				# always preserve
				echo "$file"
				echo "$file" >&3
			else
				case "$op" in
				preserve)
					echo "$file"
					echo "$file" >&3;;
				diff)	# the files are different, get user input
					if sysconf_verify "$file" <>/dev/tty >&0 2>&0
					then
						echo "$file"
						echo "$file" >&3
					fi;;
				esac
			fi
		fi
	done 3>"$restore" | (cd "$saved"; exec cpio -p -d -u "$ffsdir")
}

#
# sysconf_test_restore <flash-directory> <source-dir>
#  return true only if the restore does not need to do an interactive
#  compare
sysconf_test_restore(){
	local ffsdir saved
	# these are the globals used by the above function
	ffsdir="$1"
	saved="$2"
	# this is an error case, but return 0 so that the error is
	# detected later
	test -n "$ffsdir" -a -r "$ffsdir/etc/default/conffiles" -a -d "$saved" ||
		return 0
	#
	# read the list and check each diff file (this is just a copy of the
	# logic above with all the work removed!)
	while read op file
	do
		# handle .configured specially (to preserve the original datestamp)
		if test "$op" != diff
		then
			: # no diff required
		elif test "$file" = "etc/.configured"
		then
			: # special handling
		elif test -h "$saved/file" -o -h "$ffsdir/$file"
		then
			# new or old symbolic link
			if test -h "$saved/$file" -a -h "$ffsdir/$file" &&
				test "$(readlink "$saved/$file")" = "$(readlink "$ffsdir/$file")"
			then
				: # no change
			else
				# assume a change regardless
				return 1
			fi
		else
			# only overwrite if necessary
			if test -e "$ffsdir/$file" && cmp -s "$saved/$file" "$ffsdir/$file"
			then
				: # do not overwrite
			elif test ! -e "$ffsdir/$file"
			then
				: # always preserve
			else
				# a change
				return 1
			fi
		fi
	done

	return 0
}

#
# sysconf_save
#  save the system configuration to $syspart - $syspart must exist and
#  there must be a writeable device for it.
sysconf_save(){
	local sysdev ffsdev ffsdir saved list size status
	ffsdev="$(mtblockdev $ffspart)"
	[ -n "$ffsdev" ] || \
	ffsdev="$(mtblockdev rootfs)"
	sysdev="$(mtblockdev $syspart)"
	status=1
	if test -n "$sysdev" -a -b "$sysdev" -a -n "$ffsdev" -a -b "$ffsdev"
	then
		# this will succeed silently if the flash device is on /
		umountflash "$ffsdev" || exit 1
		#
		# Everything is umounted, now remount on a temporary directory.
		ffsdir="/tmp/flashdisk.$$"
		mkdir "$ffsdir" || {
			echo "$0: $ffsdir: failed to create temporary directory" >&2
			exit 1
		}
		#
		mountflash "$ffsdev" "$ffsdir" -o ro || {
			rmdir "$ffsdir"
			exit 1
		}
		# need temporary files for the cpio output and the listing
		saved=/tmp/cpio.$$
		list=/tmp/preserve.$$
		rm -rf "$saved" "$list"
		sysconf_save_conffiles "$ffsdir" "$saved" "$list" || {
			echo "$0: $saved: archive of saved configuration files failed" >&2
			rm -rf "$saved"
			rm "$list"
			umount "$ffsdir" && rmdir "$ffsdir" ||
				echo "$0: $ffsdir: temporary directory cleanup failed" >&2
			return 1
		}
		# ignore the error in this case:
		umount "$ffsdir" && rmdir "$ffsdir" ||
			echo "$0: $ffsdir: temporary directory cleanup failed" >&2
		#
		# we now have:
		#  /etc/default/sysconf	the basic config
		#  /tmp/preserve.$$	the list of saved files
		#  /tmp/cpio.$$		the CPIO archive of those files
		#
		# make one big file with the sysconf data followed by the
		# compressed archive in /tmp/sysconf.$$
		{	{	cat /etc/default/sysconf
				echo '[preserve]'
			} | sed -n '1,/^\[preserve\]^/p'
			while read op file
			do
				echo "$op"="$file"
			done <"$list"
		} >/tmp/sysconf.$$
		size="$(devio "<</tmp/sysconf.$$" 'pr$')"
		gzip -9 <"$saved" >>/tmp/sysconf.$$
		#
		# more cleanup, then try to write the new sysconf to $syspart
		# the format is a 4 byte big-endian length then the text data
		# if the data won't fit exit with error code 7
		rm "$saved" "$list"
		devio -p "<</tmp/sysconf.$$" ">>$sysdev" '
			$( $4+ # >
			!! 7
			$) 0
			wb '"$size"',4
			cp $'
		case $? in
		0)	echo " done" >&2
			status=0;;
		1)	echo " failed" >&2
			echo " $syspart could not be written (no changes made)" >&2;;
		3)	echo " failed" >&2
			echo " $syspart partially written, you may want to reset it" >&2;;
		7)	echo " failed" >&2
			echo " $syspart is too small: $size bytes required" >&2
			echo " No change made" >&2;;
		*)	echo " failed" >&2
			echo " Internal error writing $syspart" >&2;;
		esac
		#
		rm -f /tmp/sysconf.$$
	else
		echo "sysconf save: $syspart or $ffspart partition not found" >&2
		echo " A RedBoot partition named '$syspart' must exist in the system" >&2
		echo " flash memory for this command to work, and there must be a" >&2
		echo " block device to access this partition (udev will normally" >&2
		echo " create this automatically.  The flash partition contents must" >&2
		echo " also be accessible in a partition called '$ffspart'" >&2
		echo
		echo " To create the $syspart partition use the 'fis create' command" >&2
		echo " in the RedBoot boot loader, it is sufficient to make the" >&2
		echo " partition one erase block in size unless you have substantially" >&2
		echo " increased the size of the files listed in /etc/default/conffiles" >&2
	fi

	return $status
}

#
# sysconf_restore [auto]
#  restore previously saved configuration information from $syspart
sysconf_restore_error(){
	local root
	root="$1"
	shift
	#       -------------------------------------------------------------------------------
	{	echo "          WARNING: saved configuration files not restored"
		test -n "$1" && echo "$*"
		echo
		echo "The configuration of this machine has been reinitialised using the values"
		echo "from /etc/default/sysconf, however configuration files saved in the $syspart"
		echo "partition have not been restored."
		echo
		echo "You can restore these files by correcting any reported errors then running"
		echo
		echo "  sysconf restore"
		echo
		echo "from the command line.  This will completely reinitialise the configuration"
		echo "using the information in the $syspart partition."
	} >"$root/etc/motd"
	cat "$root/etc/motd" >&2
}
#
sysconf_restore(){
	local sysdev ffsdev ffsdir saved restore size status sysconf_noninteractive config_root

	# if set this means 'do no diff' - this avoids the code above which
	# would open /dev/tty and therefore allows this stuff to be done from
	# an init script
	sysconf_noninteractive=
	test "$1" = auto && sysconf_noninteractive=1

	ffsdev="$(mtblockdev $ffspart)"
	[ -n "$ffsdev" ] || \
	ffsdev="$(mtblockdev rootfs)"
	sysdev="$(mtblockdev $syspart)"
	status=1
	if test -n "$sysdev" -a -b "$sysdev" -a -n "$ffsdev" -a -b "$ffsdev" &&
		sysconf_valid
	then
		# this will succeed silently if the flash device is on /
		umountflash "$ffsdev" || exit 1
		#
		# Everything is umounted, now remount on a temporary directory.
		ffsdir="/tmp/flashdisk.$$"
		config_root="$ffsdir"
		mkdir "$ffsdir" || {
			echo "$0: $ffsdir: failed to create temporary directory" >&2
			exit 1
		}
		#
		mountflash "$ffsdev" "$ffsdir" || {
			rmdir "$ffsdir"
			exit 1
		}
		#
		# first restore the $syspart section
		sysconf_read "$ffsdir" || sysconf_default "$ffsdir"
		#
		# now use this to regenerate the system files
		sysconf_reload "$ffsdir"
		#
		# now examine the [preserve] section, if it is there restore
		# it if possible.
		if test -n "$(syssection preserve)"
		then
			# 'saved' is a directory, 'restore' is a file (which is
			# used to detect unrestored files).  The directory needs
			# to be populated with files.
			saved=/tmp/cpio.$$
			restore=/tmp/restore.$$
			rm -rf "$saved" "$restore"
			#
			mkdir "$saved" || {
				sysconf_restore_error "$ffsdir" "$saved: failed to create temporary directory"
				umount "$ffsdir" && rmdir "$ffsdir" ||
					echo "$0: $ffsdir: temporary directory cleanup failed" >&2
				return 1
			}
			#
			# the CPIO archive is gzip compressed after the text part
			# of sysconf, gzip will handle the LZ stream termination
			# correctly (and break the pipe) so we don't need to know
			# the real length of the data
			devio "<<$sysdev" '<=b4+.' 'cp $s-' | gunzip | (
				cd "$saved"
				exec cpio -i -d -m -u
			) || {
				rm -rf "$saved"
				sysconf_restore_error "$ffsdir" "$saved: cpio -i failed"
				umount "$ffsdir" && rmdir "$ffsdir" ||
					echo "$0: $ffsdir: temporary directory cleanup failed" >&2
				return 1
			}
			# either there must be no 'diff' files or it must
			# be possible to interact with a real user.
			if test -z "$sysconf_noninteractive" ||
				syssection preserve | sysconf_test_restore "$ffsdir" "$saved"
			then
				#
				# remove the 'init' motd from sysconf_reload
				rm "$ffsdir/etc/motd"
				#
				# now restore from the directory, using the information in
				# the preserve section, if this fails in a non-interactive
				# setting the system might not reboot
				syssection preserve |
					sysconf_restore_conffiles "$ffsdir" "$saved" "$restore" || {
					# there is a chance of the user cleaning this up
#------------------------------------------------------------------------------
					sysconf_restore_error "$ffsdir" \
"$0: $saved: restore of saved configuration files failed.
  The flash file system is mounted on $ffsdir.
  The saved files are in $saved and the list of files selected for
  restore is in $restore.
  You should restore any required configuration from $saved, then umount
  $ffsdir and reboot."
  						# this prevents cleanup/umount
						return 1
				}
				#
				# remove the copied files (i.e. the ones which were preserved)
				(	cd "$saved"
					exec rm $(cat "$restore")
				)
				rm "$restore"
				#
				# clean up, files left in $saved need to be handled by the user
				files="$(find "$saved" ! -type d -print)"
				if test -n "$files"
				then
#------------------------------------------------------------------------------
					sysconf_restore_error "$ffsdir" \
"$0: some saved configuration files have not been handled:

$files

These files can be examined in $saved and restored to
$ffsdir if required.  The saved files are in a temporary
directory and will not be retained across a reboot - copy then elsewhere if
you are unsure whether they are needed."
					return 1
				fi
				#
				# so this is safe now (no files, links etc)
				rm -rf "$saved"
			else
				rm -rf "$saved"
				# non-interactive and some changed diff files
				sysconf_restore_error "$ffsdir" \
"$0: some of the saved configuration files must be
examined before restoration"
				# but continue to the umount
			fi
		fi
		#
		# ignore the error in this case:
		umount "$ffsdir" && rmdir "$ffsdir" ||
			echo "$0: $ffsdir: temporary directory cleanup failed" >&2
		status=0
	else
		echo "sysconf restore: $syspart or $ffspart partition not found" >&2
		echo " You must have used 'sysconf save' to save configuration data" >&2
		echo " into the $syspart partition before using this command.  The command" >&2
		echo " will restore the configuration data to the flash root partition" >&2
		echo " named '$ffspart' - this must also be accessible." >&2
	fi

	return $status
}

#
# sysconf_help
#  help text
sysconf_help(){
	#     -------------------------------------------------------------------------------
	echo "sysconf: usage: sysconf read|default|reload|save|restore" >&2
	echo " read:    the current $syspart partition is read into /etc/default/sysconf" >&2
	echo " default: a default /etc/default/sysconf is created" >&2
	echo " reload:  system configuration files are recreated from /etc/default/sysconf" >&2
	echo " save:    /etc/default/sysconf and the files listed in /etc/default/conffiles" >&2
	echo "          are written to the $syspart partition" >&2
	echo " restore: the configuration information in the $syspart partition saved by" >&2
	echo "          'sysconf save' is restored" >&2
}

#
# the real commands
sysconf_command="$1"
test $# -gt 0 && shift
case "$sysconf_command" in
read)	sysconf_read "$@";;
default)sysconf_default "$@";;
reload)	sysconf_reload "$@";;
save)	sysconf_save "$@";;
restore)sysconf_restore "$@";;
valid)  sysconf_valid "$@";;

sysconf)# just load the functions
	;;

*)	# help text
	sysconf_help "$@";;
esac