#!/bin/sh -e

lilo_conf="/etc/lilo.conf"
libdir=/usr/share/predator

PROG="${0##*/}" #program name

#TODO: check are edit options valid

exit_handler()
{
	local rc=$?
	trap - EXIT
	rm -rf -- $TEMPFILE
	exit $rc
}

trap exit_handler SIGHUP SIGPIPE SIGINT SIGQUIT SIGTERM EXIT

list_conf()
{
    cat $lilo_conf| sed -r 's,^([[:space:]]*)([^n][^o][[:alnum:]-]+)[[:space:]]*$,\1\2=true,
    s,^([[:space:]]*)no([[:alnum:]-]+)[[:space:]]*$,\1\2=false,'|awk -f $libdir/lilo_sections.awk 
}

print_version()
{
	cat <<EOF
$PROG version 0.0.2

Written by Stanislav Ievlev

Copyright (C) 2003-2004 ALT Linux Team
EOF
	exit
}


print_usage()
{
	[ "$1" = 0 ] || exec >&2
	cat <<EOF
Usage: $PROG [options] 
or: $PROG --edit <image-name> option=value option=value ...
or: $PROG --add  <image-name> [--chain] --kernel image-file 

utility to manipulate lilo config file:
add,delete or edit entries

Valid options are:
  -h, --help	display help screen
  -v, --version	display version information
  -i, --images	get full list of the images
  -d, --delete  delete image from config
  -a, --add  	add new image to config
  -l, --list	list image options
  -e, --edit	edit some image option

List options are:
  -n, --names-only	display only names of the options

Add options are:
  -k, --kernel	kernel image name
  -c, --chain	chain-loaded image

Report bugs to <inger@altlinux.org>
EOF
	[ -n "$1" ] && exit "$1" || exit
}

get_images()
{
    echo '%global%'
    cat $lilo_conf|grep '^[[:space:]]*label='|sed 's/^[[:space:]]*label=//'
}

get_options()
{
    list_conf|grep "^$1:"|sed "s,^$1:[[:space:]]*,,"|sed -r "$names_pattern"
}

decode_truefalse()
{
    sed -r "s,^([[:space:]]*)([[:alnum:]-]+)=true,\1\2,
            s,^([[:space:]]*)([[:alnum:]-]+)=false,\1no\2,"
}

del_image()
{
    TEMPFILE=`mktemp -t $PROG.XXXXXX`
    list_conf|egrep -v "$1:"|cut -f2 -d: |decode_truefalse >$TEMPFILE
    mv -f $TEMPFILE $lilo_conf
}

add_image()
{
    if list_conf|grep -qs "$1:"; then
	echo "same image already exists"
    else
	if [ $chain -ne 0 ]; then
	    prefix="other"
	else
	    prefix="image"
	fi
	tmp=${kernel:?path to kernel file must be defined}
	echo "$prefix=$kernel" >>$lilo_conf
	echo "	label=$1" >>$lilo_conf
	if [ $chain -ne 0 ]; then
	    echo "	unsafe" >>$lilo_conf
	else
	    echo "	read-only" >>$lilo_conf
	    echo "	optional" >>$lilo_conf
	fi
    fi
}

update_option()
{
    TEMPFILE=`mktemp -t $PROG.XXXXXX`
    local name="$1"
    local value="$2"
    local label="$3"
    list_conf| sed -r "s,(^$label:[[:space:]]*$name)[[:space:]]*=.*,\1=$value,"| cut -f2 -d: |decode_truefalse>$TEMPFILE
    mv -f $TEMPFILE $lilo_conf
}

insert_option()
{
    local name="$1"
    local value="$2"
    local label="$3"

    local sep="	";
    
    [ "$label" = "%global%" ] && sep="";

    TEMPFILE=`mktemp -t $PROG.XXXXXX`
    list_conf|
    (
	local under_section=0
    while read line
    do
	if echo "$line"|grep -qs "^$label:" ; then
	    under_section=1;
	else
	    if [ "$under_section" -eq "1" ]; then
		under_section=0;
		echo "$label:$sep$name=$value"
	    fi
	fi
	echo "$line"
    done
    #append if this is a latest section if the file
    if [ "$under_section" -eq "1" ]; then
	under_section=0;
	echo "$label:$sep$name=$value"
    fi
    )|cut -f2 -d:|decode_truefalse>$TEMPFILE
    
    mv -f $TEMPFILE $lilo_conf
}

TEMP=`getopt -n $PROG -o h,v,l:,i,d:,a:,e:,c,k:,n \
 -l help,version,list:,images,delete:,add:,edit:,chain,kernel:,names-only -- "$@"` || print_usage
eval set -- "$TEMP"

chain=0
kernel=
label=
names_pattern="s,.*,&,"
action=
while :; do
	case "$1" in
		-h|--help) print_usage 0
			;;
		-v|--version) print_version; exit 0
			;;
		-i|--images) get_images; exit 0
			;;
		-d|--delete) 
			shift
			del_image $1;
			exit 0
			;;
		-a|--add) 
			shift; label=$1
			action="add"
			;;
		-e|--edit) 
			shift; label=$1
			action="edit"
			;;
		-l|--list) 
			shift ;label=$1
			action="list"
			;;
		-c|--chain)
			chain=1
			;;
		-k|--kernel)
			shift; kernel=$1
			;;
		-n|--names-only)
			names_pattern='s,[[:space:]]*=.*,,'
			;;
		--) shift; break
			;;
		*) Fatal "unrecognized option: $1"
			;;
	esac
	shift
done

[ -z $action ] && exit 0;

if [ $action = "add" ];then
    add_image $label
elif [ $action = "list" ];then
    if [ $# -gt 0 ];then
	for i in "$@"; do
	    get_options $label|grep $i|sed "s,^$i[[:space:]]*=,,"
	done
    else
	get_options $label
    fi
elif [ $action = "edit" ];then
    #determine update or append option
    for i in "$@"
    do
	option_value=${i##*=}
	option_name=${i%%=*}
	if list_conf|grep -qs "^$label:[[:space:]]*$option_name"
	then
	    update_option "$option_name" "$option_value" "$label"
	    
	else
	    insert_option "$option_name" "$option_value" "$label"
	fi
    done
else
    echo "unknown action"
fi
