#!/bin/sh
#(c) Copyright Barry Kauler, 15 March 2014. Licence: GPL3 (/usr/share/doc/legal).
#simple mechanism to boot Quirky as live-CD, totally in RAM.
#150317 frugal: if file BOOT_SPECS exists, has BOOT_DEV, BOOT_FS, BOOT_FOLDER, with q.sfs separate from initrd. refer: /usr/sbin/installquirky, savesession
#150318 /var is a symlink into /tmp, ditto for /run. 151105 removed.
#151105 complete rewrite, create a layered f.s. with q.sfs underneath, zram on top.
#151106 handle low-RAM situation, maybe not run entirely in RAM. load a saved session. specs on commandline. 151109
#151111 bug fix, low-ram test.
#151122 support BOOT_DEV=UUID=<uuid>. ex kernel cmdline: boot_specs=UUID=1234-4567-6789-4321:ext2:
#151124 scan loop for usb drives (requires my usb-storage patch). 151125 nah, just sleep.
#151127 replace BOOT_ with INSTALL_, ex BOOT_DEV with INSTALL_DEV

mount -t proc none /proc
mount -t sysfs none /sys
mount -t rootfs -o remount,rw rootfs /
ln -s /proc/mounts /etc/mtab 2> /dev/null
PATH="/bin:/sbin"

#allow boot specs to be on kernel commandline...
[ $install_specs ] && INSTALL_SPECS="$install_specs"
if [ "$INSTALL_SPECS" ];then
 #format: $INSTALL_DEV:$INSTALL_FS:$INSTALL_FOLDER
 INSTALL_DEV="$(echo -n "$INSTALL_SPECS" | cut -f 1 -d ':')"
 INSTALL_FS="$(echo -n "$INSTALL_SPECS" | cut -f 2 -d ':')"
 INSTALL_FOLDER="$(echo -n "$INSTALL_SPECS" | cut -f 3 -d ':')"
 echo -e "INSTALL_DEV=${INSTALL_DEV}\nINSTALL_FS=${INSTALL_FS}\nINSTALL_FOLDER=${INSTALL_FOLDER}" > /INSTALL_SPECS
fi

#create zram on /q_rw (takes about 0.8sec)...
FREEK=`grep '^MemFree:' /proc/meminfo | tr -s ' ' | cut -f 2 -d ' '`
#allocate 3/4 of free ram times 2 (as compression is approx 2:1)...
HALFK=$(($FREEK/2))
QTRK=$(($HALFK/2))
USEK=$(($HALFK+$QTRK)) #3/4
ALLOCK=$(($USEK*2))
echo "Creating compressed zram, using ${USEK}K of RAM"
echo "${ALLOCK}K" > /sys/block/zram0/disksize
echo "${USEK}K" > /sys/block/zram0/mem_limit
mkfs.ext2 -m 0 -L qrw /dev/zram0 > /dev/null 2>&1
sync
mount -t ext2 /dev/zram0 /q_rw

QPATH=''; KEEPMNT=0; xINSTALL_DEV=''
if [ -f /INSTALL_SPECS ];then
. /INSTALL_SPECS
 mkdir /partition
 if [ "${INSTALL_DEV:0:4}" == "UUID" ];then #151122. 151124. 151125
  #refer: http://bkhome.org/news/?viewDetailed=00297
  while [ ! "$xINSTALL_DEV" ];do
   sleep 0.5
   xINSTALL_DEV="$(blkid | grep "\"${INSTALL_DEV:5}\"" | cut -f 1 -d ':' | cut -f 3 -d '/')"
  done
 else
  xINSTALL_DEV="$INSTALL_DEV"
 fi
 mount -o rw -t $INSTALL_FS /dev/$xINSTALL_DEV /partition
 QPATH="/partition/${INSTALL_FOLDER}"
fi

#setup bottom layer, with q.sfs mounted in it...
echo "Setting up layered filesystem, zram on top, Quirky SFS underneath"
QSFSbytes0=`ls -l ${QPATH}/q.sfs | tr -s ' ' | cut -f 5 -d ' '`
QSFSbytes1=$(($QSFSbytes0+500000))
mount -t tmpfs -o size=${QSFSbytes1} tmpfs /q_ro
mkdir /q_ro/q_sfs
if [ $FREEK -lt 1000000 -a "$QPATH" != "" ];then #151106 low ram. 151111 change 1000 to 1000000
 #do not copy q.sfs into ram, mount where it is...
 mount -r -t squashfs -o noatime,loop ${QPATH}/q.sfs /q_ro/q_sfs
 KEEPMNT=1
else
 if [ "$QPATH" ];then
  cp -a ${QPATH}/q.sfs /q_ro/
 else
  mv -f /q.sfs /q_ro/ #save ram space by moving
 fi
 mount -r -t squashfs -o noatime,loop /q_ro/q.sfs /q_ro/q_sfs
fi

#151106 load a saved session...
if [ -f ${QPATH}/s.sfs ];then
 echo "Loading session from ${xINSTALL_DEV}, folder ${INSTALL_FOLDER}, into RAM"
 mkdir -p ${QPATH}/s_sfs
 mount -r -t squashfs -o noatime,loop ${QPATH}/s.sfs ${QPATH}/s_sfs
 cp -a ${QPATH}/s_sfs/* /q_rw/
 sync
 umount ${QPATH}/s_sfs
fi

sync
[ $KEEPMNT -eq 0 ] && [ "$QPATH" ] && umount /dev/$xINSTALL_DEV

#setup the layered f.s...
mount -t aufs -o udba=reval,diropq=w,dirs=/q_rw=rw:/q_ro/q_sfs=ro layerfs /q_new

echo "Performing a switch_root onto the layered filesystem"
#move the mount points...
if [ ! -d /q_new/initrd ];then
 mkdir /q_new/initrd
 mkdir /q_new/initrd/q_ro
 mkdir /q_new/initrd/q_rw
 mkdir /q_new/initrd/partition
fi
[ $KEEPMNT -eq 1 ] && mount -o move /partition /q_new/initrd/partition
mount -o move /q_ro /q_new/initrd/q_ro
mount -o move /q_rw /q_new/initrd/q_rw

#copy all of initrd-tree, for use by script 'savesession':
if [ ! -d /q_new/boot/initrd-tree ];then
 mkdir -p /q_new/boot/initrd-tree
 cp -a /bin /q_new/boot/initrd-tree/
 cp -a /dev /q_new/boot/initrd-tree/
 cp -a /etc /q_new/boot/initrd-tree/
 cp -a /sbin /q_new/boot/initrd-tree/
 cp -a /init /q_new/boot/initrd-tree/
 mkdir /q_new/boot/initrd-tree/lib
 mkdir /q_new/boot/initrd-tree/mnt
 mkdir /q_new/boot/initrd-tree/proc
 mkdir /q_new/boot/initrd-tree/q_new
 mkdir /q_new/boot/initrd-tree/q_ro
 mkdir /q_new/boot/initrd-tree/q_rw
 mkdir /q_new/boot/initrd-tree/sys
 mkdir /q_new/boot/initrd-tree/tmp
 mkdir /q_new/boot/initrd-tree/var
fi
[ -f /INSTALL_SPECS ] && cp -a -f /INSTALL_SPECS /q_new/boot/initrd-tree/

#need to do this before switch_root...
mount -t devtmpfs devtmpfs /q_new/dev

sync
umount /sys
umount /proc
exec switch_root /q_new /sbin/init

###END###
