#!/bin/sh

# setup: muLinux profile  manager
# by M. Andreoli


. /etc/path.conf
. /etc/utils
. /setup/lib/basic

VERSION=$(cat /etc/version 2>/dev/null)

#set -x

# Syntax

if [ $# -eq 0 ] && [ "`which vsetup`" ]; then
	exec vsetup
fi


if [ "Z$1" = "Z-h" ]; then
clear
echo -e $BRIGHT
echo "muLinux Resource Manager -- (C) M. Andreoli"
echo -e $NORMAL
cat <<END
Syntax:

setup -f resource 		# force "resource" (re)config 
setup  -a  	 		# (re)config all
setup  -a  list-file 		# (re)config res mapped in [list-file] 
setup resource -filename	# read values from "filename"
setup -R			# interactive choice of profile 
setup -[r|s|e] [profile-name]	# read,save and deleter profiles
setup -m class/module 		# load a compressed module from floppy 
setup -l			# list config & resource installed
setup -h			# this
setup resource x= y= ...	# command-line mode
setup -f XYZ from=/path/to/XYZ.tgz  # load an addon from a file
setup 				# full-screen front-end


Add a first (separated) -v for (more,more) verbose log.

END
exit 0
fi

# Local env.

startup=/startup
modules=${startup}/modules
cache=no
limit_for_caching=150
TMP=/tmp
kernel=`uname -r`
[ -z "$kernel" ] && kernel=2.0.36

# initialize 

Init()
{

if [ ! -d /tmp ] ; then
        mkdir -m 777 /tmp
fi

mkdir -p /setup/cnf/store
mkdir -p /tmp/modules/preferred

# Check space in /tmp

cache=no
set -- `df | rgrep /tmp`
if [ $# -eq 0 ] || [ "$4" -gt ${limit_for_caching} ] ; then
        cache=yes
fi

# Check spase in /

set -- `df / | rgrep /`
if [ $# -ne 0 ] && [ "$4" -gt ${limit_for_caching} ] ; then
        cache=yes
fi

}


probe_startup()
{
mkdir -p /startup
# probe startup device 
[ -d /startup/init ] && return 0

# floppy already mounted on /startup?
mount | rgrep fd0 > /dev/null && mounted=1

# probe

list="/dev/fd0H1722 /dev/fd0H1440"

setlevel 1
for f in $list
do
mount $f /startup 2>/dev/null || continue
[ -d /startup/init ]  && setlevel 5 &&  return 0 
umount $f 2>/dev/null
done
setlevel 5

(wave -c 440 2; wave -c 440 2) 2>/dev/null
read -p "`tell Insert startup floppy and press -ENTER- or [a]bort` " ans
case "$ans" in
a*) return 1;;
esac
probe_startup
}


# mount/umount is /startup 

mount_startup()
{
probe_startup
}


umount_startup()
{

if [  "`mount | rgrep "/startup" | rgrep fd0`" ] ; then
        umount /startup  # umount if floppy
        #echo "You can extract the diskette" 
fi

}

list_conf()
{
        cd $startup/init
	last=NONE
        if [ -r conf.last ] ; then
                last=`cat conf.last`
        fi

        echo
        echo "-----------------"

        sp=`mount | rgrep startup`
        [ -z "$sp" ] && sp="/startup directory"
        echo "`tell Startup partition:` $sp"

        if [ -r conf.tgz ] ; then
        list="NONE.tar `gzip -dc conf.tgz | tar -tf - 2>&1`"
        else
        list="NONE.tar"
        fi
	list=`echo $list | sed s/\.tar//g`
        list=`echo $list | sed s/$last/[$last]/g`
        
        echo -e "$(tell Availables profiles): $BRIGHT$GREEN${list}$NORMAL"
        return 0
}

# Local funtions


# remove from input illegal assignments 
# and quote the right side

fix_input()
{
rgrep -v VAR_LIST | rgrep -v RESOURCE | rgrep -v HIDDEN_LIST \
| rgrep -v MOD_LIST | rgrep -v resource | \
sed "s/=\([^\"]\)\(.*\)/=\"\1\2\"/g"
}


parse_param()
{

# nothing to do
[ $#  = 0 ] && return

# function called?

case $1 in
-)	# read from stdin, save and exit
        cat | fix_input > /tmp/in ;
	. /tmp/in ; rm /tmp/in
	#parse_file /tmp/in
        save -n $resource $ACTION 
	exit
	;;
-*)	# read from a file, save and exit
        f=$(echo $1 | tr -d '-')
        if [ -f "$f" ] ; then
	cat $f | fix_input > /tmp/in
	#parse_file /tmp/in
        . /tmp/in; rm -r /tmp/in 
        else
	tell "Input file [%s] non-existent" | printf -r "$f"; exit
        fi
        save -n $resource $ACTION 
	exit
        ;;
*=*)	# Read x= y=  ... from cmdline, save and execute
	SplitArgs $@
        save -n $resource  $ACTION 
	[ -z "$noconfig" ] && configure; exit
        ;;
*)	# assume  "setup resource function"
	eval $1 $resource ; exit
	;;
esac

}



# check a prerequisite command

check()
{
if [ "`which $1`" ]; then
	return 0
else
	tell "Command [%s] not found. Abort setup" | printf -r "$f"
	return 1
fi
}

locate_module()
{
m=$1
list=`cat /etc/modules.path`

for TOP in $list
do
echo $TOP | rgrep /startup/modules > /dev/null  && mount_startup 

# module unpacked

if [ -r $TOP/preferred/${m}.o ] ; then
	echo $TOP/preferred
	return 0
fi

# unpack module

found=`cat $TOP/LIST 2>/dev/null | rgrep ${m}.o 2>/dev/null`
if [ "$found" ] ; then

	extract=
	[ "$cache" = no ] && extract="${m}.o" 

	cat ${TOP}/archive.tbz| bzip2 -ds \
	| (cd /tmp/modules/preferred; tar -xf - $extract)
	rc=$?
	# cache the module in /tmp/modules
	echo /tmp/modules/preferred
	return $rc
fi
done

tell "not found" 
return 1

}

#
# insmod a module 
#

load_module()
{
[ $# = 0 ] && return
m=$1; p=$2
[ "$1" ] && echo "$(tell Loading module): $1" 

rmmod `basename $m` 2>/dev/null

dir=`locate_module ${m}`
rc=$?

if [ ${rc} != 0 ]
then
tell "failed loadling module %s, raison: %s" | printf -r "${m}" "$dir"
return 1
fi

	param=

	if [ -r /startup/modules/$m.param ]; then
		param=`cat /startup/modules/$m.param`
	fi

	[ "$p" ] && param=$p
		
	insmod ${dir}/${m}.o ${param}
	[ "$cache" = no ] && rm /tmp/modules/preferred/$m.o 2>/dev/null
}

#-----------------
# Global Function 
#------------------

# Uso "part v i"; ritrova ${v$i}

part()
{
var=$1$2
cmd="val=\$$var"
eval $cmd
echo ${val}
}


#-----------------------------------------------
# "Virtual" functions: implemented in some .fun 
#  call order:  
#	status ask_the_user: help, prepare->save,configure
#	status configure: configure
#-----------------------------------------------

# (status) overloaded: Set user preferences

configure()
{
for m in ${MOD_LIST}
do
load_module $m
done

return 0
}

# Called at "ask_the_usr", if user answer YES 

# overloaded: this is the basic form

prepare()
{
save $1 configure
}

# (status) overloaded: If user answer "no" to prompt

unwanted()
{
return 1
}

# overloaded: called when setup call "save", for user's files, etc.

store()
{
return 1
}

# overloaded    

info()
{
echo
tell "info not available."
}

stop()
{
}

restart()
{
[ $ACTION = configure ] || return 1 
raison=`requirement`
if [ $? -ne 0 ] ; then
	tell "%s postposta %s" | printf -r "$resource" "$raison"
	return 1
fi

[ $ACTION = configure ] && stop
tell "Restarting %s ..." | printf -r $resource
configure
}

status()
{
case $ACTION in
configure) echo up;;
*)	echo down;;
esac
}

# this, in the native form, put the resource in the
# ask_the_user state. The real function is in the .fun
# library. Its scope is to remove critical data from setup
# before of cloning
 
sanitize()
{
default
save -n $1 $ACTION 
}


moreinfo()
{
echo
echo "Not available. See muLinux documentation."
echo
}

AreYouHappy()
{
prompt happy "n" "Are you happy with this configuration (y/n)?"

if [ -z "$happy" ] || [ "$happy" = n ] ; then
	return 1
else
	return 0
fi 
}

print_info()
{
echo -e $BRIGHT$GREEN
info| sed 's/^.*$/     &/'
echo -e $NORMAL
}

# if return false(1), this resource is skipped
# Can output the *raison* for skipping
# [overloaded] 

requirement()
{
return 0	# default true 
}

# $1=resource; called for skipped resources
skipped()
{
save -n $1 skipped
return 0
}

#----------------------------
# User setup 
#-----------------------------
ask_the_user()
{
# $1.cnf: resource file

echo
print_info	# print help

case $STATE in
configure)
        want=y
        ;;
*)
        want=n
        ;;
esac


prompt want $want "Do you want ${RESOURCE}? (y/n)"

case ${want} in
n|N)
	tell "Excellent!"
	save -n $1 unwanted
	unwanted
	echo
	return 1
;;
y|Y)
	prepare $1
	save -n $1 configure
	echo
	[ -z "$noconfig" ] && configure
	rc=$?
	return $rc 
	;;
*)
	ask_the_user $*
	;;
esac

}


#  SAVE parameters  & save conf

save()
{
# $1: cnf; $2: action
# save -n cnf action:	save silently 
# save -c cnf action:	save  with confirmation 

silent=
confirm=

case "Z$1Z" in
Z-nZ ) silent=yes; shift ;;
Z-cZ ) confirm=yes; shift ;;
esac

while [ 1 ] ; do

cat > /setup/cnf/$1.cnf <<EOF
# Setup version $VERSION
ACTION="$2"
EOF

# user variables

for v in ${VAR_LIST}
do
def=`part $v`

# variable with def="-" are not applicable

if [ "$silent" != yes ] ; then
	eval prompt $v \'$def\'
fi

echo "${v}='`part $v`'" >> /setup/cnf/$1.cnf

done

# hidden variables

for v in ${HIDDEN_LIST}
do
def=`part $v`
echo "${v}='`part $v`'" >> /setup/cnf/$1.cnf
done

[ "${silent}" = yes ]  && break
[ -z "${confirm}" ] && break 

echo
prompt ok "y" "Is correct?   y)es n)o h)elp s)hell "

[ "$ok" = y ] && break
[ "$ok" = h ] && moreinfo 
[ "$ok" = s ] && tell "type exit when finish." && /bin/-ash
 
done # main while
}


# load overloaded functions and go

process()
{
# $1: force(yes/) ; $2: resource-name; $3-$4...: "param=value; ..."

case "Z$1Z" in
Z-fZ) 
        force="-f"
        shift        
;;
esac

resource=$1
shift

if [ -z "`ls /setup/fun|rgrep ${resource}`" ]; then
tell "Resource %s non found. Exit." | printf -r "${resource}"
exit 1
fi


# "Overloading"  with local resource functions 

if [ -f /setup/fun/$resource.fun ]; then
	. /setup/fun/$resource.fun
	default		# new!
fi 

# Overwrites with resource data (if any)

if [ -f /setup/cnf/$resource.cnf ]; then
        . /setup/cnf/$resource.cnf
fi

# previous state

STATE=${ACTION}

# Reset with param

parse_param $@

raison=`requirement`
rc=$?
case "$ACTION" in
skipped)
	[ $rc -eq 0 ] && ACTION=ask_the_user
	;;
*)	
	if [ $rc -ne 0 ] ; then
		ACTION=skipped
		save -n ${resource} $ACTION
	else
	[ "Z${force}Z" = "Z-fZ" ] && ACTION=ask_the_user
	fi
	;;
esac

echo -e "$(tell Setting up) $BRIGHT${resource}$NORMAL: `tell ${ACTION}` ${raison}"
eval ${ACTION} ${resource}

}


#-----------------
# Main 
#-----------------

if [ ! -d /tmp ] ; then
	mkdir -m 777 /tmp
fi

TMP=/tmp
Init 

force=
verbose=

while [ $# != 0 ]; do
case "$1" in
-f)
	force="-f"
	shift
	;;
-v)
	shift
	verbose="-v"
	set -x
	;;
-noconfig)
        shift
        noconfig="-noconfig"
        ;;
-probe)
	shift
	probe_startup
        exit	
	;;
-R)	# ask for conf
	mount_startup

        cd $startup/init
        if [ -r conf.last ] ; then
                last=`cat conf.last`
        else
                last="NONE"
                exit 1
        fi

	list_conf

	# If last saved conf is named "lock", load without confirm

	if [ "$last" = lock ] ; then
		exec setup -r $last
	fi

	# Only "NONE" found in archive
	
	if [ $? -eq 0 ] ; then
	read -p "`tell Enter profile name to load` [$last]> " cnf
	[ -z "$cnf" ] && cnf=$last
	else
		cnf=NONE
	fi

	if [ $cnf != NONE ] ; then
		exec setup -r $cnf
	fi
        exit 0
;;
-r)	# read conf $2
	mount_startup
        
	cnf=$2	
        [ -z "$cnf" ] && echo "`Specify a name.`" && exit
	shift
	echo -n "$(tell Reading \"%s\" profile from startup ...)" \
		|printf -r "$cnf"

	cd $TMP
	gzip -dc $startup/init/conf.tgz | tar -xf- $cnf.tar 2>/dev/null 1>&2

        if [ $? -ne 0 ]  ; then
        tell "Configuration [%s] not exist - Abort." | printf -r "$cnf"
        exit 1
        fi

	cd /setup/cnf
	tar -xf $TMP/$cnf.tar
	rm -f $TMP/$cnf.tar

	echo $cnf >/$startup/init/conf.last
	tell "done."
        exit 0
;;
-e)	# remove a config file
	mount_startup
	dead=$2
	shift
	echo -n "`tell Removing \"%s\" profile from archive ...`" \
		| printf -r "$dead"

        current=`cat $startup/init/conf.last 2>/dev/null`
        current=${current:-NONE}

	tmp=/tmp/conf$$
	mkdir -m 777 $tmp

	# extract all conf.
	cd $tmp
	if [ -r $startup/init/conf.tgz ] ; then
                gzip -dc $startup/init/conf.tgz | tar -xf-
        fi
	
	# rebuild arch.
	cd $tmp
	rm $dead.tar 2>/dev/null || (tell "not found"; exit 1)
	
        if [ "`/bin/ls`" ] ; then
        tar -cf - * | gzip -9 -c > $startup/init/conf.tgz 
        else
                rm -f $startup/init/conf.tgz
        fi
        cd /
	rm -r $tmp 

        if [ $current = $dead ] ; then
                rm -f $startup/init/conf.last
        fi

	sync
	tell "done."
        umount_startup
        exit 0
;;

-s)	# save a conf.

	# execute store() for any resource configured

        list=`cat /setup/model/order`
        for r in $list
        do
        (
        . /setup/fun/$r.fun ; default
        [ -f /setup/cnf/$r.cnf ] && . /setup/cnf/$r.cnf
        [ "$ACTION" = configure ] && store
        )
        done

	# tar and copy in /startup /setup/cnf
	tell "Storing setup environment ..."
	mount_startup
	new=$2
	shift
	[ -z "$new" ] && new=`cat $startup/init/conf.last 2>/dev/null`

	if [ -z "$new" ] ; then	
                read -p "`tell Enter a name for this profile` > " new 
	fi
	
if [ "$new" = "lock" ] ; then
tell <<END

** WARNING: saving with this name, you lock the floppy
** to this specific not-portable profile. 
** You can fix, (re)saving with another name.

END
fi

	echo $new > $startup/init/conf.last
	echo -n "`tell Saving \"%s\" profile on startup ...`" \
		| printf -r "$new"
	tmp=/tmp/conf$$
	mkdir -m 777 $tmp

	# extract all conf.
	cd $tmp
	if [ -r $startup/init/conf.tgz ] ; then
                gzip -dc $startup/init/conf.tgz | tar -xf-
        fi
	
        # create new conf
	cd /setup/cnf
	tar -cf $tmp/$new.tar *  	

	# rebuild arch.
	cd $tmp
	tar -cf - * | gzip -9 -c > $startup/init/conf.tgz 
        cd /
	rm -r $tmp 

	sync
	tell "done."
        umount_startup
        exit 0
;;
-l)	# LIST RESOURCES status

	mount_startup
	shift
	list_conf
	echo
	tell "Resource status:"
	echo "---------------"
	echo
	for r in $(cat /setup/model/order) 
	do
	include $r
	status=${ACTION}

	case ${ACTION} in
	configure)	status="configured";;
	esac

	#echo -e "${BRIGHT}${r}${GREEN}:${status}${NORMAL}"
	printf "%-15s %s" $r "`tell $status`"; echo
	done |  more 
	echo
	exit 0
;;
-sa)

	list=`cat /setup/model/order`
	for r in $list
	do
	(
	. /setup/fun/$r.fun ; default
	. /setup/cnf/$r.cnf
	[ "$ACTION" = configure ] && store
	)
	done
	setup -s
	exit
	;;
-a)	
	# -a list_file : process /setup/model/[list-file]
	# -a : process all /setup/model/order
	
	shift	
	
	if [ -z "$1" ] ; then
		list=`cat /setup/model/order`
	else
		list=`cat /setup/model/$1`
		shift
	fi

	if [ -z "${list}" ] ; then 
		tell "No resources listed found: abort"
		exit 1
	fi

	action=$@

        for r in ${list}
        do
        setup ${verbose} ${force} ${noconfig} ${r} ${action}
        done
        exit 0

	;;
-m)	# load a single module
	# $1=module $2=param
	shift 1
	load_module $*
	exit 0
	;;
*)
	resource=$1
	shift
	param="$@"
	#mount_startup
	break
	;;
esac
done

process $force $resource $param

# End Main 

