#!/bin/sh

# Where to debootstrap system
dbdir=
# URI of a LSL mirror
mirror="http://www.lslinux.org/packages"
# Debootstrap architecture
architecture="x86_64"
# Debootstrap branch
branch="stable"
# name of the core packages list
corepacks="corepacks"
# Additional list of packages to install in debootstrap
addpacks=
# Verbosity level
verbose=0
# Force mode?
force=false
# Some colors
red='\e[1;31m'; grn='\e[1;32m'; ylw='\e[1;33m'; wht='\e[1;37m'; nrm='\e[0m'

# Where temporary files are stored
tmpdir="$(mktemp -d)"
# If mirror is of type file://, path is stored in localm
localm=

### Sysconfig infos
# Hostname
sys_hostname=
# IP (dhcp or XXX.XXX.XXX.XXX)
sys_ip=dhcp
# Default gateway (optional if ip=dhcp)
sys_gateway=
# Nameserver(s) ip(s) (optional if ip=dhcp)
sys_nameserver=
# Search domain (optional if ip=dhcp)
sys_search=
# Keymap to load on system startup
sys_keymap=



# Things to do before exiting...
cleanup() {
    rm -rf $tmpdir
    if [ -n "$localm" ] && mountpoint -q "$dbdir$localm"; then
        umount "$dbdir$localm" || warn "$dbdir$localm may still be mounted..."
    fi
    rmdir "$dbdir$localm" &>/dev/null
}
trap cleanup EXIT


# msg level message
#   display message if level is >= verbose
msg() {
    [ $1 -gt $verbose ] 2>/dev/null && return 0
    local h="[${wht}Debug${nrm}]"
    case "$1" in
        0) h="${grn}>>${nrm}";;
        1) h="${ylw}**${nrm}";;
        2) h="${wht}**${nrm}";;
    esac
    echo -e "$h $2"
}

# err message [errcode]
#   display an error message and exit with errcode if specified
err() {
    echo -e "${red}Error${nrm} : $1"
    [ $2 -ge 0 ] 2>/dev/null && exit $2
}

# warn message
#   display a warning message
warn() {
    echo -e "${ylw}Warning${nrm} : $@" >&2
}

# yesno [default] question
#   ask a question, return 0 for yes, 1 for no
yesno() {
    local d="$1" p="(${grn}y${nrm}|${red}n${nrm})" a
    case "$d" in
        0|y) shift; d=0; p="([${grn}y${nrm}]|${red}n${nrm})";;
        1|n) shift; d=1; p="(${grn}y${nrm}|[${red}n${nrm}])";;
        *)   d=;;
    esac
    $force && [ -n "$d" ] && return $d

    while true; do
        echo -en " ${ylw}?${nrm} $@ $p "; read -n1 a
        case "$a" in
            0|y|Y|o|O) return 0;;
            1|n|N)     return 1;;
            "")        [ -n "$d" ] && return $d; echo -e "\nsorry, no default answer is available...";;
            *)         echo -e "\nsorry, unsupported answer '$a'";;
        esac
        echo -e "please answer with y or n...\n"; sleep 1
    done
}

# mywget wget options
#   wget wrapper
mywget() {
    local s="$1" d="$2"
    case "$@" in
        file://*) s="$(echo "$s" | sed 's/^file:\/\///')"; [ -d "$(dirname "$d")" ] || mkdir -p "$(dirname "$d")" &>/dev/null; cp "$s" "$d";;
        *)        if [ $verbose -gt 0 ]; then wget "$s" -O "$d"; else wget "$s" -O "$d" &>/dev/null; fi;;
    esac
}

# usage
#   display usage message and exit
usage() {
    echo -e "${wht}Usage${nrm} : $(basename "$0") [options] directory"
    echo -e "    debootstrap a LSL environnement into directory"
    echo -e "  ${wht}Options${nrm} :"
    echo -e "    -${wht}a${nrm} 'arch'          : install arch compiled packages [$architecture]"
    echo -e "    -${wht}b${nrm} 'branch'        : use packages from 'branch' branch [$branch]"
    echo -e "    -${wht}m${nrm} 'mirror'        : download packages from mirror [$mirror]"
    echo -e "    -${wht}p${nrm} 'packages list' : install specified additional packages"
    echo -e "    -${wht}f${nrm}                 : force mode, do not ask any question"
    echo -e "    -${wht}v${nrm}                 : increase verbosity level"
    echo -e "  ${wht}Sysconfig${nrm}"
    echo -e "    -${wht}hostname${nrm}=hname               : set hostname to 'hname'"
    echo -e "    -${wht}ip${nrm}='ip[:netmask[:broadcast]] : to use dhcp, set ip to 'dhcp'.  Else,  specify at least an ip,"
    echo -e "                                     and optionally a netmask and a broadcast address. Additionally"
    echo -e "                                     you may want to use the following options"
    echo -e "        -${wht}gateway${nrm}=gateway_ip       : set default gateway ip adress to 'gateway_ip'"
    echo -e "        -${wht}nameserver${nrm}='ns1[:ns2]    : set primary dns seerver to ns1, optionally secondary dns to ns2"
    echo -e "        -${wht}search${nrm}=domain            : set search domain to 'domain'"
    echo -e "    -${wht}keymap${nrm}=keycode               : set default keymap to keycode. keycode is a two letter code,"
    echo -e "                                     default value is 'us'. this feature requires at least"
    echo -e "                                     keymaps-base if keycode is one of fr,de,es,it, keymaps else"
    echo
    exit 1
}

dbdir_naska_init() {
    mv "$dbdir/etc/resolv.conf" "$dbdir/etc/resolv.conf.bkp" && cp /etc/resolv.conf "$dbdir/etc/resolv.conf" || err "can't set temporary resolv configuration" 8
    if ! grep -q "0;install;" "$dbdir/etc/naska.conf"; then
        cp "$dbdir/etc/naska.conf"  "$dbdir/etc/naska.conf.bkp"  && echo -e "repositories=\"0;install;$mirror/$architecture/$branch\"" >> "$dbdir/etc/naska.conf" || err "failed to set temporary naska mirror" 8
    fi
    case "$mirror" in
        file://*) localm="$(echo "$mirror" | sed 's/^file:\/\///')"
                  [ -d "$dbdir$localm" ] || mkdir -p "$dbdir$localm"
                  mount -o bind "$localm" "$dbdir$localm" || err "failed to mount (bind) $localm in debootstrap dir" 8;;
    esac
    chroot "$dbdir" naska sync || err "an error occured while initializing NaSKa" 8
}


starttime="$(date +%s)"
while getopts a:b:fp:vh:i:g:m:n:s:k: opt; do case "$opt" in
    a) architecture="$OPTARG";;
    b) branch="$OPTARG";;
    f) force=true;;
    p) addpacks="$OPTARG";;
    v) let verbose=$verbose+1;;
    h) case "$OPTARG" in
           ostname=*)   sys_hostname="$(echo "$OPTARG" | sed -e "s/^ostname=[\"']\?//" -e "s/[\"']\?$//")";;
       esac;;
    i) case "$OPTARG" in
           p=*)         sys_ip="$(echo "$OPTARG" | sed -e "s/^p=[\"']\?//" -e "s/[\"']\?$//")";;
       esac;;
    g) case "$OPTARG" in
           ateway=*)    sys_gateway="$(echo "$OPTARG" | sed -e "s/^ateway=[\"']\?//" -e "s/[\"']\?$//")";;
       esac;;
    m) mirror="$OPTARG";;
    n) case "$OPTARG" in
           ameserver=*) sys_nameserver="$(echo "$OPTARG" | sed -e "s/^ameserver=[\"']\?//" -e "s/[\"']\?$//")";;
       esac;;
    s) case "$OPTARG" in
           earch=*)     sys_search="$(echo "$OPTARG" | sed -e "s/^earch=[\"']\?//" -e "s/[\"']\?$//")";;
       esac;;
    k) case "$OPTARG" in
           eymap=*)     sys_keymap="$(echo "$OPTARG" | sed -e "s/^eymap=[\"']\?//" -e "s/[\"']\?$//")";;
       esac;;
    *) usage;;
esac; done
for i in $(seq 2 $OPTIND); do shift; done
dbdir="$1"
[ -n "$dbdir" ] || usage

case "$sys_keymap" in
    fr|de|it|es) kmp_pack="keymaps-base";;
    '')          kmp_pack="";;
    *)           kmp_pack="keymaps";;
esac
addpacks="$(echo -e "${addpacks} $kmp_pack" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
eval corepacks=\"$corepacks\"


msg 0 "Debootstraping LSL to $dbdir"
if [ -d "$dbdir" ]; then
    if [ "$(ls -a "$dbdir")" != "$(echo -e ".\n..")" ] && yesno y "$dbdir, directory is not empty... do you want to remove all its content?"; then
        rm -rf "$dbdir/"* || err "failed to empty $dbdir" 2
    fi
else
    yesno y "$dbdir, directory does not exist, create it?" \
        || err "please specify a correct value for debootstrap directory" 1
    install -d -m755 "$dbdir" || err "failed to create $dbdir directory" 3
fi


msg 0 "Fetching core packages"
msg 1 "getting core packages list and URI"
mywget "$mirror/$architecture/$branch/$corepacks" "$tmpdir/corepacks" || err "failed to retrieve core packages list ($corepacks)" 4
while read p v; do
   msg 2 "fetching $p-$v"
   mywget "$mirror/$architecture/$branch/$p-$v.nsk" "$tmpdir/$(basename "$p-$v.nsk")" || err "failed to retrieve core package $p" 5
done < "$tmpdir/corepacks"


msg 0 "Extracting core packages"
while read p v; do
   msg 2 "extracting $p"
   tar xjf "$tmpdir/$(basename "$p")-$v.nsk" -C "$dbdir" 2>/dev/null || err "failed to extract core package $p" 6
done < "$tmpdir/corepacks"
msg 2 "installing busybox symlinks"
chroot "$dbdir" /sbin/bbox_symlinks.sh -r || err "failed to install busybox symlinks..." 7


msg 0 "Installing core packages"
dbdir_naska_init
l=$(cat "$tmpdir/corepacks" | while read p v; do echo -n "$p "; done)
chroot "$dbdir" naska -x -f install $l || err "an error occured while installing core packages" 9


msg 0 "Customizing debootstrap"
# Set hostname
if [ -n "$sys_hostname" ]; then
    msg 1 "setting hostname to $sys_hostname"
    sed -i 's/^hostname=.*$/hostname="'$sys_hostname'"/' $dbdir/etc/hostname || warn "failed to set hostname"
fi

# Configure network
if [ -n "$sys_ip" ]; then
    msg 1 "configuring network"
    netconf="#Autoadded debootstrap configuration"
    resconf=
    if [ "$sys_ip" = "dhcp" ]; then
        netconf="${netconf}\nconfig_eth0=\"dhcp\""
    else
        netconf="${netconf}\nconfig_eth0=\"$sys_ip"
        [ -n "$sys_netmask" ]   && netconf="${netconf} netmask=$sys_netmask"
        [ -n "$sys_broadcast" ] && netconf="${netconf} broadcast=$sys_broadcast"
        netconf="${netconf}\""
        [ -n "$sys_gateway" ]   && netconf="${netconf}\nroutes_eth0=\"default via $sys_gateway\""

        [ -n "$sys_search" ] && resconf="search $sys_search"
        ns1="$(echo -e "$sys_nameserver" | cut -d":" -f1)"
        ns2=""
        [ "$ns1" = "$sys_nameserver" ] || ns2="$(echo -e "$sys_nameserver" | cut -d":" -f2)"
        [ -n "$ns1" ] && resconf="${resconf}\nnameserver $ns1"
        [ -n "$ns2" ] && resconf="${resconf}\nnameserver $ns2"
    fi
    echo -e "\n$netconf" >> "$dbdir/etc/conf.d/net" || warn "failed to configure eth0"
    [ -z "$resconf" ] || echo -e "$resconf" > "$dbdir/etc/resolv.conf" || warn "failed to create resolv.conf file"
    [ -e "$dbdir/etc/init.d/net.eth0" ] || ln -s net.lo "$dbdir/etc/init.d/net.eth0"
    [ -e "$dbdir/etc/rc.default.d/net.eth0" ] || ln -s /etc/init.d/net.eth0 "$dbdir/etc/rc.default.d/net.eth0"
fi

# Configure default keymap
if [ -n "$sys_keymap" -a "$sys_keymap" != "us" ]; then
    msg 1 "setting default keymap to $sys_keymap"
    [ "$kmp_pack" = "keymaps" ] && msg 1 "keymaps package was installed, which could waste a lot of space... you may want to delete unused keymaps in /usr/share/keymap"
    sed -i 's/^keymap=.*$/keymap="'$sys_keymap'"/' "$dbdir/etc/conf.d/keymap" || warn "failed to set default keymap"
fi

if [ -n "$addpacks" ]; then
    msg 0 "Installing additional packages"
    dbdir_naska_init
    chroot "$dbdir" naska sync || err "an error occured while synchronizing NaSKa default repos" 10
    chroot "$dbdir" naska -x -f install $addpacks || err "an error occured while installing additional packages" 10
fi


if [ -z "$sys_ip" ]; then
    mv "$dbdir/etc/resolv.conf.bkp" "$dbdir/etc/resolv.conf" || warn "failed to restore resolv configuration"
fi
mv "$dbdir/etc/naska.conf.bkp" "$dbdir/etc/naska.conf" || warn "failed to restore naska configuration" 11
if [ -n "$localm" ]; then
    umount "$dbdir$localm" || warn "failed to umount (bind) $dbstrap$localm" 11
    rmdir "$dbdir$localm" &>/dev/null
fi

date +%s > "$dbdir/etc/debootstrap_timestamp"
let length=$(date +%s)-$starttime
msg 0 "All done! Your LSL environnement is now available in $dbdir (build time : ${length}s)"
