#!/bin/zsh
#
# mknest - script to NEST dyne:II in various forms
#
#  * Copyright (C) 2003-2007 Denis "jaromil" Rojo - RASTASOFT.org
#
#  * freely distributed in dyne:bolic GNU/Linux http://dynebolic.org
#
#  * This source code is free software; you can redistribute it and/or
#  * modify it under the terms of the GNU Public License as published 
#  * by the Free Software Foundation; either version 2 of the License,
#  * or (at your option) any later version.
#  *
#  * This source code is distributed in the hope that it will be useful,
#  * but WITHOUT ANY WARRANTY; without even the implied warranty of
#  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#  * Please refer to the GNU Public License for more details.
#  *
#  * You should have received a copy of the GNU Public License along with
#  * this source code; if not, write to:
#  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# dynebol.cfg is allways in the root of the filesystem
# DYNEBOL_CRYPT=encryption algorithm (if there is one, only AES128 supported)

source /lib/dyne/utils.sh

source /boot/dynenv

export PATH="$PATH:/usr/X11R6/bin"

report_success() {
# $1 success string
# $2 optional icon
    msg=$1
    icon=$2

    if [ -z "$msg" ]; then
	return 0
    fi
    if [ -z $DISPLAY ]; then
    # if no display, just write on console
	notice "$msg"
	return
    fi

    if [ -z $icon ]; then
    # if none specified use default icon
	icon="/usr/share/icons/graphite/48x48/emblems/emblem-cool.png"
    fi


  export MAIN_DIALOG="
<vbox>
  <frame Success creating nest>
    <hbox>
      <pixmap>
        <input file>${icon}</input>
      </pixmap>
      <text>
        <label>${msg}</label>
      </text>
    </hbox>
  </frame>
  <button>
    <input file stock=\"gtk-ok\"></input>
    <label>OK!</label>
  </button>

</vbox>
"

  gtkdialog --program=MAIN_DIALOG >/dev/null

}

report_error() {
    error_dialog ${1} "/usr/share/dyne/taschino/error.png"
    return 1
}


############################
### main()
###

notice "nidifica  - create dyne:II nest"
act "(c)2003-2007 by Jaromil - RASTASOFT.org"
act "invoked with args \"$*\" "
act "running on `date`"

# save the cmdline
CMDLINE="${@}"
OPTS=`getopt -o hvf:ex --long help,version,file:,encrypt,xterm -n 'nidifica' -- "$@"`

eval set -- "$OPTS"

while true; do
    case "$1" in
	-h)
	    echo " .  nidifica [-hv] [-p part ] [-f file,mbytes]"
	    echo " .  -v, --version   print out application info"
	    echo " .  -h, --help      print this small usage guide"
	    echo " .  -f, --file      create specified file,size as nest"
            echo " .  -e, --encrypt   secure the nest with encryption"
            echo " .  -x, --xterm     run this script in a new xterm"
	    exit 2
	    ;;
	-v)
	    exit 2
	    ;;
	-f)
	    LOOPBACK=$2
	    shift 2
	    ;;
        -e)
            ENCRYPT=true
            shift 1
            ;;
        -x)
            XTERM=true
            shift 1
            ;;
	--) shift; break ;;
	*) error "error in given options"; exit 1 ;;
    esac
done

# with -x we start this script in a terminal 
if [ $XTERM ]; then
        act "spawning a visual terminal for mknest ${CMDLINE}"
        cmdline="-f ${LOOPBACK}"
        if [ $ENCRYPT ]; then
           cmdline="$cmdline -e"
        fi
	( `/usr/X11R6/bin/xterm \
           -fn "-*-lucidatypewriter-*-*-*-*-18-*-*-*-*-*-*-*" -geometry 76x15 \
           -bg black -fg green \
           -T "creating dyne:bolic nest ${LOOPBACK}MB" -e \
           "mknest ${cmdline}"` )&
        exit
fi


#########################################
# check presence of all needed parameters
FATAL=0

if [ $PARTITION ]; then
  PART_VOL="`cat /boot/volumes | grep $PARTITION`"
  if ! [ $PART_VOL ]; then
     error "partition $PARTITION has not been detected"
     FATAL=1
  else
     notice "nesting on partition $PART_VOL"
  fi
fi

if [ $LOOPBACK ]; then
  NSTFILE="`echo $LOOPBACK|cut -d, -f1`"
  NSTSIZE="`echo $LOOPBACK|cut -d, -f2`"
  if ! [ $NSTSIZE ]; then
     error "argument of -f missing size specification"
     error "usage: -f filename,size (in bytes)"
     FATAL=1
  elif [ `is_writable $NSTFILE` = false ]; then
     error "file $NSTFILE is not writable"
     error "cannot create nest"
     FATAL=1
  elif [ -e $NSTFILE ]; then
     notice "file $NSTFILE already exists"
     ask_yesno 10 "A nest is already present on this partition. Do you want to overwrite the existing nest?"
     if [ $? = 1 ]; then echo " yes"
     else
       echo " no"
       report_error "User aborted operation: should not overwrite existing nest"
       exit 1
     fi
  fi
fi

if [ $FATAL = 1 ]; then
    report_error "nidifica called with wrong arguments, operation aborted."
    exit 1
fi

## parameters ok here
####################################################################

PATH=/usr/bin:/usr/sbin:/bin:/sbin   

#### nest in a loopback file to be created

if [ $LOOPBACK ]; then

    # put a busy watch on the cursor
    # xsetroot -cursor_name watch

    SIZE_4k=`expr \( $NSTSIZE \* 1000 \) / 4`
    notice "generating file of ${NSTSIZE}Mb (${SIZE_4k} blocks of 4Kb)"
    act "dd if=/dev/zero of=${NSTFILE} bs=4k count=$SIZE_4k"
#    dd if=/dev/zero of=${NSTFILE} bs=4k count=${SIZE_4k}
#   now with progress bar!
    dd if=/dev/zero bs=4k count=${SIZE_4k} | cbar -s ${SIZE_4k} -bl 4k -of ${NSTFILE} -de -nb -np
    
    if [ $? = 0 -a -e ${NSTFILE} ]; then
	act "OK: `ls -l ${NSTFILE}`"
    else
	report_error "Error creating the nest file ${NSTFILE} : (dd if=/dev/zero of=${NSTFILE} bs=4k count=$SIZE_4k)"
	sleep 4
	exit 1
    fi

    mkdir -p /tmp/nest    
    
    if [ $ENCRYPT ]; then
	
	encrypt=true

	notice "Creating a cryptographically encrypted nest"

	loadmod dm-crypt
	loadmod aes-i586

	nstloop=`losetup -f`
	
	losetup -f ${NSTFILE}
	act "Generating secret key..."

	dd if=/dev/urandom bs=1 count=1024 | strings | cbar -s 32 -bl 1 -of /var/run/secret.tmp -de -nb -np

        clear

        notice "Setup your secret key file dyne.nst.gpg"
	gpg -o "${NSTFILE}.gpg" --no-options --openpgp -c -a /var/run/secret.tmp
	while [ $? = 2 ]; do
	  gpg -o "${NSTFILE}.gpg" --no-options --openpgp -c -a /var/run/secret.tmp
	done
	# here user is prompted for password

	act "formatting Luks mapped device"
        # dm-crypt only supports sha1
        # but we can use aes-cbc-essiv with sha256 for better security
        # see http://clemens.endorphin.org/LinuxHDEncSettings
	cryptsetup --batch-mode --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat ${nstloop} /var/run/secret.tmp

	act "formatting Ext3 filesystem"

        cryptsetup --key-file /var/run/secret.tmp --batch-mode --cipher aes luksOpen ${nstloop} dyne.mknest

	rm -f /var/run/secret.tmp

        cryptsetup luksDump ${nstloop}

	mkfs.ext3 -F -j -L "dyne:nest" /dev/mapper/dyne.mknest

	if [ $? = 0 ]; then
	    act "OK, encrypted nest succesfully formatted"
	else
	    act "error formatting nest with Ext3 filesystem"
	fi

	mount -t ext3 /dev/mapper/dyne.mknest /tmp/nest

	if [ $? != 0 ]; then
	    error "cannot mount the nest"
	    report_error "Error mounting the nest (mount -t ext2 ${NSTFILE} /tmp/nest)"
	    cryptsetup luksClose dyne.mknest
	    losetup -d ${nstloop}
	    sleep 4
	    exit 1
	fi


    else ####################### no encryption
	
	notice "Creating the EXT2 internal filesystem"
	
    # format the nest with journaled ext3
	mkfs.ext3 -F -j -L "dyne:nest" ${NSTFILE}
	
	if [ $? = 0 ]; then
	    act "OK, loopback device succesfully formatted"
	else
	    report_error "Error formatting the nest (mkfs $LODEV)"
	    rm ${NSTFILE}
	    sleep 4
	    exit 1
	fi
	

	mount -o loop -t ext3  ${NSTFILE} /tmp/nest
	if [ $? != 0 ]; then
	    error "cannot mount the nest"
	    report_error "Error mounting the nest (mount -t ext2 ${NSTFILE} /tmp/nest)"
	    rm $NSTFILE
	    sleep 4
	    exit 1
	fi
    fi

    act "please wait while populating the nest...."
    
    mkdir -p /tmp/nest/home/luther
    cp -ra /etc/skel/*     /tmp/nest/home/luther
    cp -ra /etc/skel/.*    /tmp/nest/home/luther
    ln -s /lib/dyne/configure /tmp/nest/home/luther/Configure
    ln -s /mnt /tmp/nest/home/luther/Volumes
    chown -R luther:users  /tmp/nest/home/luther

    mkdir -p /tmp/nest/root
    cp -ra /etc/skel/*     /tmp/nest/root
    cp -ra /etc/skel/.*    /tmp/nest/root
    ln -s /lib/dyne/configure /tmp/nest/root/Configure
    ln -s /mnt /tmp/nest/root/Volumes
    chmod -R go-rwx        /tmp/nest/root
    
    mkdir -p /tmp/nest/local
    cp -ra /usr/local/*    /tmp/nest/local

    cp -ra /etc /tmp/nest

    umount /tmp/nest

    if [ "$encrypt" = "true" ]; then
	act "unmounting encrypted partition"
	cryptsetup luksClose dyne.mknest
	losetup -d ${nstloop}
    fi

    notice "done!"
    
    sync
    
    act "here is your new dyne:bolic nest:"
    stat ${NSTFILE} | tee -a $DYNEBOLIC_LOG

    if [ "$encrypt" = "true" ]; then
	act "encryption key is stored in file ${NSTFILE}.gpg"
	act "the key is sealed by your secret passphrase"
    fi	

    # restore the cursor
    # xsetroot -cursor_name arrow

    report_success "Dynebolic nest succesfully created in ${NSTFILE} :: It will be active starting from the next boot."
    

fi # end nest in loopback

if [ $PARTITION ]; then

  notice "nesting in partition yet to be implemented"

fi

exit 0
