#!/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. 151129 again need patch.
#151127 replace BOOT_ with INSTALL_, ex BOOT_DEV with INSTALL_DEV
#151127 introducing auto-probing for installed files. /Q_ID has unique ID, can be used to find matching installed files.
#151129 blkid returns scd0 instead of sr0. fix scanning optical. 151201
#151203 faster scan drives. ha ha, why not? -- load any more sfs files found in QPATH.
#151205 had /partition/mnt/home a symlink to /, which caused kernel panic. ref: http://tldp.org/LDP/abs/html/string-manipulation.html
#151206 support "half-full" install (q.sfs, and session in entire partition). work-in-progress. 151208
#160418 hybrid-iso booting from usb, uefi pc, find q.sfs.
#160422 more efficient blkid.
#160427 call /sbin/fs-check if .fsckme.flg exists. set local time from hw clock.

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_FS="$(echo -n "$INSTALL_SPECS" | cut -f 2 -d ':')"
 echo -e "INSTALL_DEV=${INSTALL_SPECS%%:*}\nINSTALL_FS=${INSTALL_FS}\nINSTALL_FOLDER=${INSTALL_SPECS##*:}" > /INSTALL_SPECS
fi

hwclock --hctosys --localtime #160427 from util-linux. assuming hw clock set to local time.

#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=''; HALF_FULL=0
if [ -f /INSTALL_SPECS -o -f /Q_ID ];then #151127 Q_ID has unique ID, can be used to find matching installed files.
 mkdir /partition
 sleep 1
 while [ 1 ];do
  sleep 0.25
  DMESG="$(dmesg)"
  CNTfound=$(echo "$DMESG" | grep 'usb-storage: device found at ' | wc -l)
  CNTscanned=$(echo "$DMESG" | grep 'usb-storage: device scan complete' | wc -l)
  [ $CNTscanned -ge $CNTfound ] && break
 done
 if [ -f /INSTALL_SPECS ];then
. /INSTALL_SPECS
  if [ "${INSTALL_DEV:0:4}" == "UUID" ];then #151122. 151124. 151125
   xINSTALL_DEV="$(blkid | grep "\"${INSTALL_DEV:5}\"" | cut -f 1 -d ':' | cut -f 3 -d '/')"
  else
   xINSTALL_DEV="$INSTALL_DEV"
  fi
  mount -o rw -t $INSTALL_FS /dev/$xINSTALL_DEV /partition
  QPATH="/partition/${INSTALL_FOLDER}"
  [ ! "$INSTALL_FOLDER" ] && [ -d /partition/audit ] && HALF_FULL=1 #151206 let this mean a half-full installation.
 else
  echo -n "Scanning drives:"
  QID="$(cat /Q_ID)"
  BLKID="$(blkid)" #160422
  while read APART
  do
   [ "$APART" == "ADEV=" ] && continue #160418
   eval "$APART" #ex: ADEV=/dev/sda3 LABEL="Acer" UUID="BC8CBA188CB9CD60" TYPE="ntfs"
   xINSTALL_DEV="${ADEV##*/}"; echo -n " ${xINSTALL_DEV}"
   mount -t $TYPE $ADEV /partition
   [ $? -ne 0 ] && continue
   if [ "${xINSTALL_DEV:0:2}" == "sr" -o "${TYPE}" == "iso9660" ];then #160418 see also blkid below.
    if [ -f /partition/initrd.q ];then
     #echo -e "INSTALL_DEV=${xINSTALL_DEV}\nINSTALL_FS=${TYPE}\nINSTALL_FOLDER=" > /INSTALL_SPECS
     QPATH="/partition"
     [ -f /partition/vmlinuz ] && cp -a /partition/vmlinuz ./ #160419
     break
    fi
   else
    [ -f /partition/.fsckme.flg ] && /sbin/fs-check $ADEV $TYPE #160427 f.s. check.
    #for FQID in `find /partition -maxdepth 3 -type f -name Q_ID | tr '\n' ' '`
    for FQID in /partition/*/Q_ID /partition/*/*/Q_ID #151203 faster?
    do
     [ "${FQID:0:12}" == "/partition/*" ] && break #151203
     [ -h ${FQID%/*} ] && continue #151205 had /partition/mnt/home a symlink to /, which caused kernel panic.
     if [ "$(cat $FQID)" == "$QID" ];then
      INSTALL_FOLDER="$(dirname "$FQID" | sed -e 's%^/partition/%%')"
      echo -e "INSTALL_DEV=UUID=${UUID}\nINSTALL_FS=${TYPE}\nINSTALL_FOLDER=${INSTALL_FOLDER}" > /INSTALL_SPECS
      QPATH="/partition/${INSTALL_FOLDER}"
      break 2
     fi
    done
   fi
   umount /partition
  done<<_END1
$(echo "$BLKID" | sed -e 's%/scd%/sr%' | sort -k 1,1 -t ' ' | grep -E '"ext2"|"ext3"|"ext4"|"f2fs"|"vfat"|"ntfs"' | sed -e 's%^%ADEV=%' | tr -d ':')
$(echo "$BLKID" | sed -e 's%/scd%/sr%' | grep -E '"iso9660"' | sed -e 's%^%ADEV=%' | tr -d ':')
_END1
  echo
 fi
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
else
 if [ $HALF_FULL -eq 1 ];then #151206 this is a hack for now...
  echo "Mounting session partition ${INSTALL_DEV}"
  umount /q_rw
  echo 1 > /sys/block/zram0/reset
  mount -o move /partition /q_rw
 fi
fi

#151203 load any more sfs files...
EXTRASFS=''
for ASFS in `ls -1 ${QPATH}/*.sfs 2>/dev/null | grep -v '/[qs]\.sfs'`
do
 ANAME="$(basename $ASFS .sfs)"
 mkdir /q_ro/$ANAME
 mount -r -t squashfs -o noatime,loop ${QPATH}/${ANAME}.sfs /q_ro/${ANAME}
 EXTRASFS="${EXTRASFS}:/q_ro/${ANAME}=ro"
 KEEPMNT=1
done

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${EXTRASFS} 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/
[ -f /Q_ID ] && cp -a -f /Q_ID /q_new/boot/initrd-tree/ #151128. 151208 test.
mkdir -p /q_new/dev /q_new/mnt /q_new/proc /q_new/sys /q_new/tmp  #151205 remaster of cd might not have this in q.sfs (see 'savession'). 151208

#160419 iso no longer has vmlinuz in /boot in q.sfs...
[ -f ./vmlinuz ] && [ ! -f /q_new/boot/vmlinuz ] && mv -f ./vmlinuz /q_new/boot/

mount -t devtmpfs devtmpfs /q_new/dev #need to do this before switch_root.
sync
umount /sys
umount /proc
exec switch_root /q_new /sbin/init

###END###
