#!/bin/sh
# see also /sbin scripts: usablefs, set_plang, switch
#
# _FN = _FILENAME
# _MP = _MOUNTPOINT
#

#Aufs layers setup by this script...
#aufs layers:            RW (top)      RO1             RO2              PUPMODE
#First boot (or pfix=ram):  tmpfs                         pup_xxx.sfs      5
#Normal running puppy:      pup_save.3fs                  pup_xxx.sfs      12
#ditto, but flash drive:    tmpfs         pup_save.3fs    pup_xxx.sfs      13
#Multisession cd/dvd:       tmpfs         folders         pup_xxx.sfs      77

######################## localization ########################
#ex: /locale/<locale>/init.mo
L_WINDOWS_HIBERNATED="ERROR: Windows NTFS hibernated partition, cannot mount"
L_DONE="done"
L_FAILED="failed"
L_DUMPING_BOOTINIT_LOG="Dumping last lines of /tmp/bootinit.log..."
L_DUMPING_KERNEL_LOG="Dumping last lines of kernel log..."
L_ERROR_IS_TOO_CRITICAL="Error is too critical, dropping out to console..."
L_PAUSING_60_SECONDS="Pausing for 60 seconds..."
L_LOADING_FILE="Loading the '%s' %s file..." #printf
L_LOADING_SAVE_ARCHIVE='Loading save-archive %s [%s]...' #printf
L_LOADING_PUPSAVE='Loading savefolder %s [%s]...' #printf
L_LOADING_PUPSAVE_FILE='Loading savefile %s [%s] (%s)...' #printf
L_UPGRADE_NO="Backing off, not using personal storage, booting in RAM only, PUPMODE=5..."
L_LOADING_FROM_CD="Loading folder %s from CD/DVD..." #printf
L_RAM_DISK_FULL="RAM disk full, copy failed at %s" #printf
L_ADDING_SAVE_LAYER_FAILED="adding %s to aufs stack failed." #printf
L_WAITING_FOR_DEV='Waiting %s seconds for slow storage devices [%s/%s].' #printf
L_WAITING_FOR_PART='Waiting for partition [%s]' #printf
L_LOADING_KEYBOARD_LAYOUT="Loading '%s' keyboard layout..." #printf
L_COPY_MESSAGE="Copying '%s' to ram..." #printf
L_LOAD_MESSAGE="main"
L_PRE_MESSAGE="Loading puppy main sfs file."
L_ERR_PDRV_INCOMPLETE="%s information is incomplete." #printf
L_ERR_ONEPART_NOT_MOUNTED="%s is not mounted." #printf
L_ERR_ONEPART_NOT_OK="%s %s is not Ok." #printf
L_ERR_ONEPART_MOUNT_SFS_FAILED="%s %s mount of sfs failed." #printf
L_ERR_AUFS_SFS_FAILED="aufs mount of %s failed." #printf
L_ERR_TYPE_PUPSAVE="Type a number to choose which personal file to use:"
L_DROPPED_TO_INITRD_SHELL="Dropped to initramfs shell. Type 'exec switch' to continue booting Puppy."
L_SWITCH_ROOT="Performing a 'switch_root' to the %s filesystem..." #printf
L_FOLDER_MARKED_BAD="Folder %s marked bad." #printf
L_0_NONE="0  none"
L_ERROR_FAILED_AUFS_STACK='Failed to create empty aufs stack'
L_ADDING_MODULE="Adding module %s" #printf
L_NO_DISTRO_SPECS="No DISTRO_SPECS file found, assuming that personal storage is empty."
L_DEBUG_SAVE="To save debug info to a partition, type 'debugsave'"
L_SFFS_ERROR="ERROR: savefile filesystem is not ext2/3/4"

##############################################################

/sbin/usablefs # mount: /proc /sys /dev / (proc sysfs devtmpfs rootfs)

for i in $(cat /proc/cmdline) ; do
  case $i in
    fullinstall) exec ash /sbin/init_full_install ;;
    bootmenu)    ZBOOTMENU=1 ;;
    loglevel=*)  LOGLEVEL=${i##*=}  ;;
    root=*)      GRUB_ROOT=${i#root=} ;;
  esac
done
if [ "$GRUB_ROOT" ]; then
	[ "${GRUB_ROOT%=*}" = 'UUID' ] && GRUB_ROOT=${GRUB_ROOT#*=}
fi
# always call init-bootmenu on ARM devices
case $(uname -m) in arm*) ZBOOTMENU=1 ;; esac

export TERMINFO="/etc/terminfo"
export LANG=C
export INIT_SCRIPT=1

PATH="/bin:/sbin"
export KERNELVER="$(uname -r)"
. /DISTRO_SPECS #v412 has DISTRO_VERSION, DISTRO_FILE_PREFIX
. /etc/rc.d/functions_x
export DISTRODESC="${DISTRO_NAME} ${DISTRO_VERSION} - Linux ${KERNELVER} - `uname -m`"

#precaution - if DISTRO_SPECS was not processed by 3builddistro...
[ ! "$DISTRO_ZDRVSFS" ] && DISTRO_ZDRVSFS="zdrv_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
[ ! "$DISTRO_FDRVSFS" ] && DISTRO_FDRVSFS="fdrv_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
[ ! "$DISTRO_ADRVSFS" ] && DISTRO_ADRVSFS="adrv_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
[ ! "$DISTRO_YDRVSFS" ] && DISTRO_YDRVSFS="ydrv_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
[ ! "$DISTRO_BDRVSFS" ] && DISTRO_BDRVSFS="bdrv_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
[ ! "$DISTRO_PUPPYSFS" ] && DISTRO_PUPPYSFS="puppy_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"

# filenames specified in DISTRO_SPECS: DISTRO_ZDRVSFS, DISTRO_PUPPYSFS...
Z_DEF_FN="$DISTRO_ZDRVSFS"
F_DEF_FN="$DISTRO_FDRVSFS"
A_DEF_FN="$DISTRO_ADRVSFS"
Y_DEF_FN="$DISTRO_YDRVSFS"
B_DEF_FN="$DISTRO_BDRVSFS"
P_DEF_FN="$DISTRO_PUPPYSFS"
KBUILD_DEF_FN="kbuild-$KERNELVER.sfs"
DEVX_DEF_FN="devx_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
DOCX_DEF_FN="docx_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"
NLSX_DEF_FN="nlsx_${DISTRO_FILE_PREFIX}_${DISTRO_VERSION}.sfs"

if [ ! "$LOGLEVEL" ] ; then
  echo '3' > /proc/sys/kernel/printk # '3' is the standard loglevel.
  LOGLEVEL=3
fi

#List the builtin filesystem support
KFILESYSTEMS="$(cat /proc/filesystems | grep -v "nodev" | grep -v "fuseblk" | sed -e 's#ntfs3#ntfs#' -e 's#ntfs-3g#ntfs#' -e "s#\t##g" | tr '\n' '|' | sed -e 's#|$##g')"
#List linux filesystems
LINUXFSLIST="ext2|ext3|ext4|btrfs|minix|f2fs|reiserfs"

#Filesystem to be fsck
FSCKLIST="ext2|ext3|ext4|f2fs|vfat|msdos|exfat"

# Layered file system to use
UNIONFS='aufs'

#=============================================================
#                        FUNCTIONS
#=============================================================

fsck_func() {
# "$1" - partition device - ex: /dev/sdb2
# "$2" - fstype - ex: ext2
 case $2 in
  ext2|ext3|ext4) fsck_app='e2fsck -y' ;;
  f2fs) fsck_app='fsck.f2fs -y' ;;
  #vfat)  fsck_app='fsck.fat -y'  ;;
  #exfat) fsck_app='exfatfsck'    ;;
  *) return ;;
 esac
 if [ "$(echo "$FSCKDPARTS" | grep "${1}|")" = "" ];then
  ${fsck_app} ${1} > /dev/console 2>&1 || sleep 3 #so the user has time to read the error msg..
  FSCKDPARTS="${FSCKDPARTS}${1}|"
 fi
}

check_status() #args: [-critical] $RET_VAL "$ERROR_MSG"
{
  ERROR_CRITICAL=""
  [ "$1" = "-critical" ] && { ERROR_CRITICAL="yes" ; shift; }
  RET_VAL=$1
  shift
  ERROR_MSG="$@"
  if [ $RET_VAL -eq 0 ] ; then
    echo -en "\\033[74G" >/dev/console #move to column 72. 110426: 74
    echo -e "\\033[1;32m${L_DONE}\\033[0;39m" >/dev/console #32=green
  else
    echo -en "\\033[72G" >/dev/console #move to column 72.
    echo -e "\\033[1;31m${L_FAILED}\\033[0;39m" >/dev/console #31=red
    if [ "$FLAG_NO_TIMEOUT" ] ; then
      FLAG_NO_TIMEOUT=
      return
    fi
    echo -e "\\033[1;35m${L_DUMPING_BOOTINIT_LOG}\\033[0;39m" >/dev/console #35=purple
    echo -en "\\033[1;31m" >/dev/console #31=red
    cat /tmp/bootinit.log | tail -n 4 >/dev/console
    echo -en "\\033[0;39m" >/dev/console
    echo -e "\\033[1;35m${L_DUMPING_KERNEL_LOG}\\033[0;39m" >/dev/console #35=purple
    echo -en "\\033[1;31m" >/dev/console #31=red
    dmesg | tail -n 4 >/dev/console
    echo -en "\\033[0;39m" >/dev/console
    #exit to initial ramdisk shell...
    [ "$RDSH" != "" ] && exec /bin/sh >/dev/console 2>&1
    if [ "$ERROR_CRITICAL" = "yes" ] ; then
      echo -en "\\033[1;35m" >/dev/console #35=purple
      [ "$ERROR_MSG" != "" ] && echo "*** $ERROR_MSG" >/dev/console
      echo "*** ${L_ERROR_IS_TOO_CRITICAL}" >/dev/console
      echo -en "\\033[0;39m" >/dev/console
      echo -e "\\033[1;32m*** $L_DEBUG_SAVE\\033[0;39m" >/dev/console
      exec /bin/sh >/dev/console 2>&1
    else
      echo "${L_PAUSING_60_SECONDS}" >/dev/console
      sleep 60
    fi
  fi
}

decode_spec() {
 #${1} = an sfs spec e.g. sdb2:/pup/test_it.sfs
 ONE_BP_ID=""; ONE_BP_FN=""
 [ "${1}" ] || return
 case "${1}" in
  *:*) ONE_BP_ID="${1%%:*}"; ONE_BP_FN="${1#*:}" ;;
  *) ONE_BP_ID="${1}" ;;
 esac
 if [ "$ONE_BP_FN" ];then
  case "$ONE_BP_FN" in
   */*) [ "${ONE_BP_FN:0:1}" != "/" ] && ONE_BP_FN="/$ONE_BP_FN" ;;
   *) ONE_BP_FN="$PSUBDIR/$ONE_BP_FN" ;;
  esac
 fi
}

wait_for_blkid() {
 # $1 value to look for
 BLKID_PART=''
 [ "$1" ] || return
 local PART DIDMSG NUM
 DIDMSG=''
 # use loop to wait for device, if not found immediately
 for NUM in $(seq 1 15); do
  PART="$(blkid | grep "$1" | grep -E "^/dev/$1| LABEL=.$1| UUID=.$1" | cut -f1 -d':' | cut -f3 -d'/')"
  [ "$PART" ] && break
  [ $NUM -eq 1 ] && { echo -n "$(printf "$L_WAITING_FOR_PART" "${1}")" > /dev/console; DIDMSG='yes'; }
  sleep 1
  echo -en "\\033[1;33m.\\033[0;39m" >/dev/console #yellow dot
 done
 [ "$PART" ] && BLKID_PART="$PART"
 if [ "$DIDMSG" ];then
  get_part_info
  if [ "$PART" ];then
   check_status 0
  else
   check_status 1
  fi
 fi
}

decode_id() {
 ONE_PART=''
 [ "${1}" ] || return
 if grep -q " ${1}$" /proc/partitions;then #known partition name
  ONE_PART="$1"
  return
 fi
 wait_for_blkid "$1"
 ONE_PART="$BLKID_PART"
}

decode_other_ids() {
 #get ONE_PART from DEV or ID specified in sfs boot params
 decode_id "$Z_BP_ID"
 [ "$ONE_PART" ] && { Z_PART="$ONE_PART"; Z_BP_ID=""; }
 decode_id "$F_BP_ID"
 [ "$ONE_PART" ] && { F_PART="$ONE_PART"; F_BP_ID=""; }
 decode_id "$A_BP_ID"
 [ "$ONE_PART" ] && { A_PART="$ONE_PART"; A_BP_ID=""; }
 decode_id "$Y_BP_ID"
 [ "$ONE_PART" ] && { Y_PART="$ONE_PART"; Y_BP_ID=""; }
 decode_id "$B_BP_ID"
 [ "$ONE_PART" ] && { B_PART="$ONE_PART"; B_BP_ID=""; }
 decode_id "$SAVE_BP_ID"
 [ "$ONE_PART" ] && { SAVEPART="$ONE_PART"; PSAVEPART="$ONE_PART"; SAVE_BP_ID=""; }
}

log_part_id() {
# "$1" - partition id - ex: Work or sdc4
 echo "Partition ${1} not found."
}

ensure_mounted() {
# "$1" - partition - ex: sda3
# "$2" - mountpoint - ex: /mnt/pdrv
 ONE_MP="$(grep -m1 "^/dev/${1} " /proc/mounts | cut -f 2 -d ' ')"
 if [ "$ONE_MP" ];then
  ONE_FS="$(grep -m1 "^/dev/${1} " /proc/mounts | cut -f 3 -d ' ')"
  return
 fi
 ONE_FS="$(blkid /dev/${1} | grep -o ' TYPE=.*' | cut -f 2 -d '"')"
 ONE_MP="${2}"
 if [ "$PFSCKP" = "yes" ] ; then # pfix=fsckp
   fsck_func /dev/${1} $ONE_FS
 fi
 /sbin/mountpartition /dev/${1} $ONE_MP $ONE_FS #-t $ONE_FS /dev/$ONE_PART $ONE_MP
 if [ $? -ne 0 ] ; then
  sleep 3 # usb optical drive showing as /sys/block/sr0, but won't mount, needs more delay...
  /sbin/mountpartition /dev/${1} $ONE_MP $ONE_FS
  [ $? -ne 0 ] && { echo "${1} on $ONE_MP as $ONE_FS mount failed."; ONE_MP=""; return 1; }
 fi
 # fsckme.flg is created by rc.sysinit and deleted by rc.shutdown
 # this flag will be set for any prior improper shutdown. if have lots of installations
 # of puppy on the pc, the flag may not even be for this install of puppy, however, this is
 # the simplest implementation...
 if [ -f ${ONE_MP}/fsckme.flg ] ; then
  #sda1,ext3,/PUPPYBOOT/precise/precisesave.4fs
  FSCKME="`cat ${ONE_MP}/fsckme.flg`"
  echo -e "${ONE_MP}/fsckme.flg\n  $FSCKME"
  FSCK_PART="$(echo "$FSCKME" | cut -f 1 -d ",")"
  FSCK_EXT="$(echo "$FSCKME" | cut -f 2 -d ",")"
  FSCK_SAVEFILE="$(echo "$FSCKME" | cut -f 3 -d ",")"
  rm -f ${ONE_MP}/fsckme.flg
  [ "$FSCK_SAVEFILE" ] && PFSCK="yes"
  [ "$PFSCKP" = "yes" ] && return # boot param, partition already fsck'ed
  
  if [ "$(echo "$FSCKLIST" | grep "${FSCK_EXT}")" != "" ]; then
    umount ${ONE_MP}
    [ "$FSCKME" ] && fsck_func /dev/${FSCK_PART} ${FSCK_EXT}
    ensure_mounted "$1" "$2"
  fi
  
 fi
}

ensure_save_mounted() {
 SAVE_MP="/mnt/dev_save"
 ensure_mounted "$SAVEPART" "$SAVE_MP"
 if [ "$ONE_MP" ];then
  if [ "$ONE_MP" != "$SAVE_MP" ];then
   #ensure SAVEPART is mounted on /mnt/dev_save
   [ -d "$SAVE_MP" ] || mkdir -p $SAVE_MP
   echo "mount -o move $ONE_MP $SAVE_MP" #debug
   mount -o move $ONE_MP $SAVE_MP
  fi
  SAVE_FS="$ONE_FS"
 else
  SAVE_MP=""
 fi
}

find_drv_file() {
# "$1" - specified filename - ex: /pup/mydrv-1.2.3.sfs
# "$2" - default filename - ex: adrv_tahr_6.0.5.sfs
# "$3" - look under root too - ex. 1
 ONE_FN=""
 [ "${1}" ] || [ "${2}" ] || return
 if [ "${1}" ];then
  case ${1} in
   */) ONE_TRY_FN="${1}${2}" ;;
   *) ONE_TRY_FN="${1}" ;;
  esac
 else
  ONE_TRY_FN="${PSUBDIR}/${2}"
  [ "$3" -a ! -e "${ONE_MP}${ONE_TRY_FN}" ] && ONE_TRY_FN="/$2"
 fi
 if [ -L "${ONE_MP}${ONE_TRY_FN}" ];then
   C_MP="$(readlink -f "$ONE_MP")"
   ONE_TRY_FN="$(readlink -f "${C_MP}${ONE_TRY_FN}")"
   ONE_TRY_FN="${ONE_TRY_FN#${C_MP}}"
 fi
 [ -f "${ONE_MP}${ONE_TRY_FN}" ] && ONE_FN="$ONE_TRY_FN"
}

find_onepupdrv() {
# "$1" - partition - ex: sda3
# "$2" - specified filename - ex: /pup/mydrv-1.2.3.sfs
# "$3" - default filename - ex: adrv_tahr_6.0.5.sfs
# "$4" - prefix for "drv" mountpoint - ex: a
# "$5" - look under root too - ex. 1
 ONE_FN=""
 [ "${2}" ] || [ "${3}" ] || return
 [ "${4}" ] || return
 if [ "${1}" ];then
  ONE_PART="${1}"
 else
  ONE_PART="$P_PART"
 fi
 [ "$ONE_PART" ] || return
 ensure_mounted "$ONE_PART" "/mnt/${4}drv"
 [ "$ONE_MP" ] || return
 find_drv_file "${2}" "${3}" "${5}"
 [ "$ONE_FN" = "" -a "${2}" ] && echo "$ONE_PART, $ONE_TRY_FN file not found."
}

stack_onepupdrv() {
# "$1" - sfs spec - ex: sdb2,ext4,/pup/mydrv-1.2.3.sfs
# "$2" - suffix for "pup_" branch directory - ex: a
# "$3" - prepend after rw layer indicator - ex: p
 ONE_LAYER=""
 ONE_PART="$(echo "${1}" | cut -f 1 -d ',')"
 [ "$ONE_PART" ] || return 1
 ONE_REL_FN="$(echo "${1}" | cut -f 3 -d ',')"
 [ "$ONE_REL_FN" ] || return 1
 ONE_SFX="${2}"
 ONE_PREP="${3}"
 if [ "$ONE_PART" = "rootfs" ];then #humongous initrd.
  ONE_MP="" #actually it's '/'.
 else
  ONE_MP="$(mount | grep -m1 "/dev/$ONE_PART " | cut -f 3 -d ' ')"
  [ "$ONE_MP" ] || return 2
 fi
 ONE_FN="${ONE_MP}${ONE_REL_FN}"
 ONE_BASENAME="$(basename $ONE_REL_FN)"
 if ! [ -s "$ONE_FN" ] ; then
   return 3 #sfs not Ok - empty file
 fi
 # ======= load_sfs_file()
 echo -n "$(printf "${L_LOADING_FILE}" "$ONE_BASENAME" "$LOADMSG")" > /dev/console
 #-
 ONE_LOOP="$(losetup -f)"
 if [ -f /mnt/tmpfs/$ONE_BASENAME ] ; then
   losetup -r $ONE_LOOP /mnt/tmpfs/$ONE_BASENAME
 else
   losetup -r $ONE_LOOP $ONE_FN
   [ "$ONE_PART" != "rootfs" ] && KEEPMOUNTED="${KEEPMOUNTED}${ONE_PART} "
 fi
 SFS_MP="/pup_${ONE_SFX}"
 [ "$ONE_SFX" = "p" ] && SFS_MP="/pup_ro2"
 [ -d "$SFS_MP" ] || mkdir $SFS_MP
 mount -r -t squashfs -o noatime $ONE_LOOP $SFS_MP > /dev/console 2>&1
 STATUS=$? ; check_status $STATUS
 [ $STATUS -eq 0 ] && ONE_LAYER="$SFS_MP=rr"
 # ======= end of load_sfs_file()
 if ! [ "$ONE_LAYER" ] ; then
   return 4 #sfs mount failed
 fi
 if [ -n "$punionfs" ]; then
  UNIONFS="$punionfs"
 elif [ "$UNIONFS" = 'aufs' ]; then
  grep -qm1 aufs /proc/filesystems || UNIONFS="overlay"
 fi
 if [ "$UNIONFS" = 'overlay' ]; then
  if [ "$ONE_PREP" ];then
   remount_overlay -e "s~lowerdir=([^,]+)~lowerdir=${SFS_MP}:\1~" -e "s~lowerdir=,~lowerdir=${SFS_MP},~"
   [ $? -eq 0 ] || return 5
  else
   remount_overlay -e "s~lowerdir=([^,]+)~lowerdir=\1:${SFS_MP}~" -e "s~lowerdir=,~lowerdir=${SFS_MP},~"
   [ $? -eq 0 ] || return 5
  fi
 else
  mountpoint -q /pup_new
  if [ $? -ne 0 ];then
   echo "mount -t aufs -o udba=reval,diropq=w,br=/mnt/tmpfs/pup_rw=rw,xino=/mnt/tmpfs/.aufs.xino unionfs /pup_new" #debug
   mount -t aufs -o udba=reval,diropq=w,br=/mnt/tmpfs/pup_rw=rw,xino=/mnt/tmpfs/.aufs.xino unionfs /pup_new
   [ $? -eq 0 ] || fatal_error "${L_ERROR_FAILED_AUFS_STACK}"
  fi
  if [ "$ONE_PREP" ];then
   echo "mount -o remount,add:1:$ONE_LAYER /pup_new" #debug
   mount -o remount,add:1:$ONE_LAYER /pup_new
   [ $? -eq 0 ] || return 5
  else
   echo "mount -o remount,append:$ONE_LAYER /pup_new" #debug
   mount -o remount,append:$ONE_LAYER /pup_new
   [ $? -eq 0 ] || return 5
  fi
 fi
 NEWUNIONRECORD="${NEWUNIONRECORD}${ONE_BASENAME} "
 return 0
}

copy_onepupdrv() {
# "$1" - sfs spec - ex: sdb2,ext4,/pup/mydrv-1.2.3.sfs
 [ $RAMSIZE -le 1048576 ] && return 0
 ONE_PART="$(echo "${1}" | cut -f 1 -d ',')"
 [ "$ONE_PART" ] || return 1
 [ "$COPY2RAM" = "no" -a "$ONE_PART" != "rootfs" ] && return 0
 ONE_REL_FN="$(echo "${1}" | cut -f 3 -d ',')"
 [ "$ONE_REL_FN" ] || return 1
 ONE_FN="${ONE_MP}${ONE_REL_FN}"
 ONE_BASENAME="$(basename $ONE_REL_FN)"
 [ -s "$ONE_FN" ] || return 3 #sfs not Ok - empty file
 SIZEZK=$(du -k $ONE_FN | cut -f 1)
 TNEEDK=$SIZEZK
 [ "$COPY2RAM" = "" ] && TNEEDK=$(($TNEEDK + 65535)) #some slack.
 TFREEK=$(df | grep -m1 ' /mnt/tmpfs' | tr -s ' ' | cut -f 4 -d ' ')
 if [ $TFREEK -le $TNEEDK ];then
  COPY2RAM="no" # stop copying when running out of ram
  return 0
 fi
 if [ "$ONE_MP" = "" ];then #101101 humongous initrd, actually it is already in ram, but load_sfs_file code puts it in a tmpfs.
  mv -f $ONE_FN /mnt/tmpfs/
 else
  echo -en "\\033[1;35m$(printf "${L_COPY_MESSAGE}" "$ONE_BASENAME")\\033[0;39m" > /dev/console
  TOTAL_SIZEK_SFS_RAM=$(($TOTAL_SIZEK_SFS_RAM + $SIZEZK))
  cp -af $ONE_FN /mnt/tmpfs/
  STATUS=$? ; check_status $STATUS
 fi
 sync
 return 0
}

setup_onepupdrv() {
# "$1" - sfs spec - ex: sdb2,ext4,/pup/mydrv-1.2.3.sfs
# "$2" - suffix for "pup_" branch directory - ex: a
# "$3" - prepend after rw layer indicator - ex: p
 copy_onepupdrv "$1"
 STATUS=$?
 [ $STATUS -gt 0 ] && return $STATUS
 stack_onepupdrv "$1" "$2" "$3"
}

setup_psave(){ # setup savefile or savefolder
 SAVE_REL_FN="$(echo "$PUPSAVE" | cut -f 3 -d ',')"
 if [ -f "${SAVE_MP}${SAVE_REL_FN}" ];then #savefile
  PUPSAVE_SIZE="$(fx_format_bytes $(stat -c %s "${SAVE_MP}${SAVE_REL_FN}"))"
  echo -n "$(printf "${L_LOADING_PUPSAVE_FILE}" "$SAVE_REL_FN" "$SAVEPART" "$PUPSAVE_SIZE")" > /dev/console
 else
  echo -n "$(printf "${L_LOADING_PUPSAVE}" "$SAVE_REL_FN" "$SAVEPART")" > /dev/console
 fi
 rm -r -f "$SAVE_LAYER"
 SAVE_FN="${SAVE_MP}${SAVE_REL_FN}"
 if [ -f "$SAVE_FN" ];then #savefile. ex: stretchsave.4fs
  echo "--SAVEFILE-- $SAVE_FN" #debug
  /sbin/load_ext_file "$SAVE_FN" "$SAVE_MP" #reads $PFSCK
  if [ -f /tmp/savefile_loop ] ; then
    . /tmp/savefile_loop # $SAVEFILE_LOOP $SFFS
    if [ "$UNIONFS" = 'overlay' ]; then
      mkdir /pup_loop
      echo "mount -t $SFFS -o noatime $SAVEFILE_LOOP /pup_loop" #debug
      mount -t $SFFS -o noatime $SAVEFILE_LOOP /pup_loop
      if [ $? -ne 0 ]; then
        PUPSAVE=""
      else
        mkdir -p "/pup_loop/upper" "/pup_loop/work"
        ln -sv "/pup_loop/upper" "$SAVE_LAYER"
        ln -sv "/pup_loop/work" "$WORKDIR"
      fi
    else
      [ -d "$SAVE_LAYER" ] || mkdir $SAVE_LAYER
      echo "mount -t $SFFS -o noatime $SAVEFILE_LOOP $SAVE_LAYER" #debug
      mount -t $SFFS -o noatime $SAVEFILE_LOOP $SAVE_LAYER
      [ $? -ne 0 ] && PUPSAVE=""
    fi
  else # load_ext_file failed
    FLAG_NO_TIMEOUT=1
    PUPSAVE=""
  fi
 elif [ -d "$SAVE_FN" ];then #savefolder
  echo "--SAVEFOLDER-- $SAVE_FN" #debug
  if [ "$UNIONFS" = 'overlay' ]; then
   mkdir -p "$SAVE_FN/upper" "$SAVE_FN/work"
   ln -sv "$SAVE_FN/upper" "$SAVE_LAYER"
   ln -sv "$SAVE_FN/work" "$WORKDIR"
  else
   ln -sv "$SAVE_FN" "$SAVE_LAYER"
  fi
 else
  PUPSAVE=""
 fi
 #[ "$PUPSAVE" ] && decrypt directory at SAVE_LAYER
 if [ "$PUPSAVE" ];then
  SAVE_NAME="$(basename $SAVE_REL_FN)"
  #- fix for empty pupsaves (missing /initrd/DISTRO_SPECS)
  if [ ! -f "$SAVE_LAYER/initrd/DISTRO_SPECS" ] ; then
    touch /tmp/rc_update_force_pm5 # see /etc/rc.d/rc.update
    PCLEAN=""
  fi
  #-
  if [ "$PCLEAN" != "yes" -a -f "$SAVE_LAYER/initrd/DISTRO_SPECS" ];then
    validate_pupsave_upgrade /DISTRO_SPECS $SAVE_LAYER/initrd/DISTRO_SPECS
    case $? in
      0) PCLEAN="yes" ;; # perform upgrade
      1) PUPSAVE=""   ;; # do not perform upgrade
    esac
  fi
  if [ "$PCLEAN" = "yes" ];then
   #do upgrade processing
   touch /tmp/version_update_flag
   CURDIR="$(pwd)"
   cd "$SAVE_LAYER"
   #delete critical system files
   #keep rc.local - user customisations and/or fixes.
   echo "Removing $(ls ./lib/modules/$KERNELVER/modules.*)"
   rm -f ./lib/modules/$KERNELVER/modules.*
   RC_STUFF="$(ls ./etc/rc.d/rc.* | grep -v "/rc.local$" | tr '\n' ' ')"
   rm -fv $RC_STUFF
   rm -fv ./etc/rc.d/funct*
   #iterate over all files in save
   if [ "$UNIONFS" = 'overlay' ]; then
    for ONE_FILE in $(find . -type c -print); do
     [ "`stat -c '%t,%T' "$ONE_FILE" 2>/dev/null`" != '0,0' ] && continue
     [ "${ONE_FILE%/*}" = "./root/.config/autostart" ] && continue #keep autostart changes
     echo "Removing ${ONE_FILE}" 
     rm -f "$ONE_FILE" #remove whiteout file
    done
   else
    for ONE_FILE in $(find . \( -type f -or -type l \) -print); do
     ONE_BASE="${ONE_FILE##*/}" #basename
     if [ "${ONE_BASE:0:4}" = ".wh." ]; then #remove most whiteout files
      [ "${ONE_BASE:4:4}" = ".wh." ] && continue #internal aufs files
      [ "${ONE_FILE%/*}" = "./root/.config/autostart" ] && continue #keep autostart changes
      echo "Removing ${ONE_FILE}"
      rm -f "$ONE_FILE" #remove whiteout file
     fi
    done
   fi
   cd "$CURDIR"
   sync
  fi
  check_status 0
 else
  check_status 1
 fi
 if [ ! "$PUPSAVE" ] ; then
   echo "No pupsave. Setting PUPMODE 5" #debug
   if ! [ -L $SAVE_LAYER ] ; then # $SAVE_LAYER is a true mp
     echo -e "Unmounting savefile\numount -d $SAVE_LAYER" #debug
     umount -d $SAVE_LAYER
   fi
   PUPMODE=5
   SAVE_MP=""
   SAVE_LAYER=""
 fi
}

copy_folders() { #SAVE_LAYER=/pup_ro1
 echo -e "\n-------------------- copy_folders" #debug
 echo "SAVE_MP=$SAVE_MP"
 DESTDIR="/mnt/tmpfs/pup_ro1"
 [ -d "$DESTDIR" ] || mkdir -p $DESTDIR
 rm -r -f "$SAVE_LAYER"
 SAVE_FN="$DESTDIR"
 ln -s $DESTDIR $SAVE_LAYER
 #BKFOLDERS now set in check for pupmode=77
 BKLASTFOLDER="$(echo "${BKFOLDERS}" | head -n 1)"
 #a boot option allows ignore last n sessions, also need to create a badlist...
 if [ "$PIGNORELAST" ];then
  BKBADLIST="$(echo "${BKFOLDERS}" | head -n ${PIGNORELAST})"
  if [ -f ${SAVE_MP}/${BKLASTFOLDER}/.badfolders ];then
   cp ${SAVE_MP}/${BKLASTFOLDER}/.badfolders ${DESTDIR}/
   if [ $? -ne 0 ];then
    #fallback, in case last folder badly corrupted...
    BKPREVFOLDER="$(echo "${BKFOLDERS}" | head -n 2 | tail -n 1)"
    [ -f ${SAVE_MP}/${BKPREVFOLDER}/.badfolders ] && cp ${SAVE_MP}/${BKPREVFOLDER}/.badfolders ${DESTDIR}/
   fi
  fi
  echo "$BKBADLIST" >> ${DESTDIR}/.badfolders
  #note, rc.shutdown and savesession-dvd 'touch' this file so it will get saved.
  sync
 else
  [ -f ${SAVE_MP}/${BKLASTFOLDER}/.badfolders ] && cp ${SAVE_MP}/${BKLASTFOLDER}/.badfolders ${DESTDIR}/
 fi
 [ -f ${DESTDIR}/.badfolders ] && BKBADLIST="$(cat ${DESTDIR}/.badfolders | tr "\n" " ")"
 echo "BKBADLIST=${BKBADLIST}" #debug
 BKFOLDERS="$(echo -n "${BKFOLDERS}" | tr "\n" " ")"
 for ONEFOLDER in ${BKFOLDERS}
 do
  if [ "$(echo -n "$BKBADLIST" | grep "${ONEFOLDER}")" != "" -o -L "${SAVE_MP}/${ONEFOLDER}" ];then
   echo "$(printf "${L_FOLDER_MARKED_BAD}" "${ONEFOLDER}")" >/dev/console
   continue #ignore bad folder.
  fi
  echo "$ONEFOLDER" #debug
  echo -n "$(printf "${L_LOADING_FROM_CD}" "${ONEFOLDER}")" >/dev/console
  #need to be careful not to overfill the ramdisk...
  FREERAMDISK=$(df 2>/dev/null | grep /mnt/tmpfs | head -n 1 | tr -s " " | cut -f 4 -d " ")
  SIZEFOLDER=$(du -k -s ${SAVE_MP}/${ONEFOLDER} | cut -f 1)
  SIZEARCHIVE=0
  if [ -d ${SAVE_MP}/${ONEFOLDER}/archive ];then
   SIZEARCHIVE=$(du -k -s ${SAVE_MP}/${ONEFOLDER}/archive | cut -f 1)
  fi
  SIZESOURCE=$(expr $SIZEFOLDER - $SIZEARCHIVE)
  if [ $FREERAMDISK -gt $SIZESOURCE ];then
   #well, -u will only copy if files newer, so less stuff may get copied than calc'd above.
   #need to copy everything except archive folder...
   [ -d ${SAVE_MP}/${ONEFOLDER}/bin ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/bin ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/sbin ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/sbin ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/etc ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/etc ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/lib ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/lib ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/opt ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/opt ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/var ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/var ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/root ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/root ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/home ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/home ${DESTDIR}/
   [ -d ${SAVE_MP}/${ONEFOLDER}/usr ] && cp -a -u ${SAVE_MP}/${ONEFOLDER}/usr ${DESTDIR}/
   [ -f ${DESTDIR}/root/.XLOADED ] && rm -fv ${DESTDIR}/root/.XLOADED #toxic
   [ -f ${DESTDIR}/var/local/shared/.XLOADED ] && rm -fv ${DESTDIR}/var/local/shared/.XLOADED #toxic
   cp -a -u ${SAVE_MP}/${ONEFOLDER}/*.sfs ${DESTDIR}/ 2>/dev/null
   #delete deleted files (.wh.filename)... 110212 screen out .wh..wh..opq
   WHITEOUTS="$(find ${DESTDIR} -xdev -type f -name .wh.* | grep -v '__dir_opaque' | grep -v '.wh..wh.')" #110212
   echo "$WHITEOUTS" | while read DELWHITE ; do
    DELFILE="$(echo -n "$DELWHITE" | sed -e 's/\.wh\.//g')"
    if [ -e "$DELFILE" ];then
     [ "$PDEBUG" ] && echo "Deleting $DELFILE" #debug
     rm -rf "$DELFILE"
     rm -rf "$DELWHITE"
    fi
   done
   check_status 0 #display 'done' for each folder loaded.
  else
   printf "${L_RAM_DISK_FULL}\n" "${ONEFOLDER}"
   check_status 1
   break
  fi
 done
 sync
 echo -e "--------------------\n" # debug
}

set_fs_linux() {
# "$1" - file system type - ex: ext4
 ONE_FS_IS_LINUX=""
 [ "$(echo "$LINUXFSLIST" | grep "$1")" != "" ] && ONE_FS_IS_LINUX="yes"
}

find_save_file() {
# "$1" - mount point - ex:  /mnt/pdrv
# "$2" - partition name - ex: sdb2
# "$3" - file system type - ex: ext4
 if [ "$SAVE_BP_DIR" ];then
  SAVE_DIR="$SAVE_BP_DIR"
 else
  SAVE_DIR="${PSUBDIR}/"
 fi
 SAVE_FILES="$(ls -d ${1}${SAVE_DIR}${DISTRO_FILE_PREFIX}save* 2>/dev/null)"
 for ONE_SAVE in $SAVE_FILES;do
  #validate savefiles here
  IS_OK=""
  case $ONE_SAVE in
   *.2fs|*.3fs|*.4fs) [ -s "$ONE_SAVE" ] && IS_OK="yes" ;;
   *) [ "$ONE_FS_IS_LINUX" = "yes" ] && [ -d "$ONE_SAVE" ] && IS_OK="yes" ;;
  esac
  [ "$IS_OK" = "yes" ] && PUP_SAVES="${PUP_SAVES}${2},${3},${SAVE_DIR}$(basename $ONE_SAVE)
"
 done
 PUP_SAVES="$(echo "$PUP_SAVES")" #remove trailing newline char
}

search_func() {
 [ "$PDEBUG" -a "$LOOK_SAVE" ] && echo "3: filename=${PSUBDIR}/${DISTRO_FILE_PREFIX}save"
 [ "$PDEBUG" -a "$LOOK_PUP" ] && echo "3: PSUBDIR=$PSUBDIR P_BP_FN=$P_BP_FN P_DEF_FN=$P_DEF_FN"
 echo "HAVE_PARTS='${HAVE_PARTS}'" #debug
 if [ "${1}" ];then
  echo "param='${1}'" #debug
  TRY_PARTS_FIRST="$(echo "$HAVE_PARTS" | grep -E "${1}")"
  TRY_PARTS_LAST="$(echo "$HAVE_PARTS" | grep -Ev "${1}")"
  TRY_PARTS="$TRY_PARTS_FIRST
$TRY_PARTS_LAST"
 else
  TRY_PARTS="$HAVE_PARTS"
 fi
 echo "TRY_PARTS='${TRY_PARTS}'" #debug
 [ "$TRY_PARTS" ] || return
 for ONETRY in $TRY_PARTS;do
  ONE_PART="$(echo -n "$ONETRY" | cut -f 1 -d '|')"
  [ "$PDEBUG" ] && echo "4: ONE_PART=$ONE_PART"
  ensure_mounted "$ONE_PART" "/mnt/pdrv"
  if [ "$ONE_MP" ];then
   if [ "$LOOK_SAVE" -a "$SAVEPART" = "" ];then
    set_fs_linux "$ONE_FS"
    find_save_file "$ONE_MP" "$ONE_PART" "$ONE_FS"
    if [ "$PUP_SAVES" ];then
     SAVEPART="$ONE_PART"
     [ "$PDEBUG" ] && echo "5: ONE_PART=$ONE_PART filename=${PSUBDIR}/${DISTRO_FILE_PREFIX}save"
    fi
   fi
   if [ "$LOOK_PUP" ];then
    find_drv_file "$P_BP_FN" "$P_DEF_FN" ""
    if [ "$ONE_FN" ];then
     PDRV="$ONE_PART,$ONE_FS,$ONE_FN"
     P_MP="$ONE_MP"
     P_PART="$ONE_PART"
     [ "$PDEBUG" ] && echo "5: ONE_PART=$ONE_PART PSUBDIR=$PSUBDIR P_BP_FN=$P_BP_FN P_DEF_FN=$P_DEF_FN"
     break;
    fi
   fi
   umount $ONE_MP
  fi
 done 
}

get_part_info() {
 probepart -hr > /tmp/probepart.log
 probedisk > /tmp/probedisk.log
 sed 's%|.*%% ; s%.*/%%' /tmp/probedisk.log > /tmp/ALLDRVS0
 HAVE_PARTS="$(cat /tmp/probepart.log | grep -E "$KFILESYSTEMS" | cut -f 1-2 -d '|' | sed -e 's%/dev/%%')"
 [ "$PDEBUG" ] && echo "$HAVE_PARTS" > /tmp/HAVE_PARTS
}

wait_for_dev() {
 echo -n "$(printf "$L_WAITING_FOR_DEV" "$WAITDEV")" > /dev/console
 for NUM in $(seq 1 $WAITDEV);do
  sleep 1
  echo -en "\\033[1;33m.\\033[0;39m" >/dev/console #yellow dot
 done
 get_part_info
 echo ""  > /dev/console
}

umount_unneeded() {
 [ "${ISO_LOOP}" ] && umount -d ${ISO_LOOP} # /sbin/isoboot &&&
 MTD_PARTS="$(mount | cut -f1 -d' ' | grep '^/dev' | grep -v loop | cut -f3 -d'/')"
 for ONE_PART in $MTD_PARTS;do
  [ "$(echo -n "$KEEPMOUNTED" | grep "$ONE_PART")" ] || umount /dev/$ONE_PART
 done
}

check_resize_part() { #must be fast, no partitions can be mounted, can't work out pupmode at this stage
 DEVICE=/dev/mmcblk0 # sd card only for now
 fdisk -l $DEVICE | grep -qm1 "using GPT" && return # bale out if GPT
 grep "$DEVICE" /tmp/probedisk.log | grep -q 'card' || return
 FS=`grep "$DEVICE" /tmp/probepart.log | tail -n1 | cut -f 2 -d '|'`
 case $FS in
  ext*|f2fs)
  echo "$FS : checking if it needs resizing"
  ;;
  *)
  return
  ;;
 esac
 DEVICE_SIZE=`fdisk -l $DEVICE | grep -om1 '[KMG]*B,.*bytes' | cut -f 2 -d ' '`
 DEVICE_SIZE=$(($DEVICE_SIZE / 1024)) # kb
 ACT_SIZE=0
 grep 'mmcblk0p' /proc/partitions | while read EACH_PART ; do
  PART_SIZE=`echo $EACH_PART | rev | cut -f 2 -d ' ' |rev` # kb
  ACT_SIZE=$(($PART_SIZE + $ACT_SIZE ))
  echo -n $ACT_SIZE > /tmp/actualsizekb
 done
 USED_SIZE=`cat /tmp/actualsizekb`
 DIFF_SIZE=$(($DEVICE_SIZE - $USED_SIZE))
 if [ $DIFF_SIZE -lt 10000 ] ; then # ~10 MB, can do it later
  return
 else
  /sbin/resize_part $FS
  check_status $?
 fi
}

fatal_error() {
# "$1" - message - ex: puppy_tahr_6.0.5.sfs not found
# "$2" - pre-status-message - ex: Finding puppy
 KEEPMOUNTED=""
 umount_unneeded
 [ "${2}" ] && echo -n "${2}" > /dev/console
 check_status -critical 1 "$1"
}

remount_overlay() {
 OPTS=`grep '^unionfs /pup_new overlay' /proc/mounts | awk '{print $4}'`
 if [ -n "$OPTS" ]; then
  umount -l /pup_new
 else
  mkdir /mnt/tmpfs/pup_work
  OPTS="lowerdir=,upperdir=/mnt/tmpfs/pup_rw,workdir=/mnt/tmpfs/pup_work,xino=on,metacopy=off"
 fi
 NEWOPTS=`echo "$OPTS" | sed -E "$@"`
 echo "mount -t overlay -o ${NEWOPTS} unionfs /pup_new" #debug
 mount -t overlay -o ${NEWOPTS} unionfs /pup_new
 STATUS=$?
 if [ $STATUS -ne 0 ]; then
  echo "mount -t overlay -o ${OPTS} unionfs /pup_new" #debug
  mount -t overlay -o ${OPTS} unionfs /pup_new
 fi
 return $STATUS
}

#=============================================================
#                           MAIN
#=============================================================

clear #clear the screen.

[ "$ZBOOTMENU" ] && . /sbin/init-bootmenu

echo -en "\\033[0;34m***\\033[0;37m ${DISTRO_NAME} ${DISTRO_VERSION}"
echo -en "\\033[0;34m -\\033[0;37m Linux ${KERNELVER} "
echo -en "\\033[0;31m[\\033[0;37m`uname -m`\\033[0;31m]"
echo -e "\\033[0;34m ***\\033[0;39m"


########################################################
# CUSTOM AUTOMATION: CACHE FILES TO WINDOWS HARD DRIVE
########################################################
echo "=== Starting Netboot Local Caching Automation ==="

# 1. Force the network interface up and request an IP address
echo "Initializing network interface..."
udhcpc -i eth0 -n -T 5 -q

# 2. Automatically locate the Windows NTFS partition
# Looks for the first NVMe or SATA partition formatted as NTFS
TARGET_PART=$(blkid | grep -i 'type="ntfs"' | head -n 1 | cut -d: -f1)

if [ ! -z "$TARGET_PART" ]; then
    echo "Found Windows NTFS partition at $TARGET_PART"
    
    # Create a temporary mount point
    mkdir -p /mnt/windows_c
    
    # Puppy's initrd includes ntfs-3g for reliable Windows read/write support
    ntfs-3g $TARGET_PART /mnt/windows_c
    
    if [ $? -eq 0 ]; then
        echo "Successfully mounted Windows partition. Checking for local files..."
        
        # Check if the core file is already present; if not, download it
        if [ ! -f "/mnt/windows_c/puppy_dpupt64w_2606.sfs" ]; then
            echo "Core SFS file missing from local disk. Downloading from asset server..."
            wget -O /mnt/windows_c/puppy_dpupt64w_2606.sfs http://192.168.1.1:8081/puppy_dpupt64w_2606.sfs
        else
            echo "Core SFS file already cached on local disk."
        fi
        
        # Unmount cleanly so the filesystem isn't marked dirty
        umount /mnt/windows_c
    else
        echo "Failed to mount Windows partition."
    fi
else
    echo "No Windows NTFS partition detected."
fi
echo "=== Automation Finished. Continuing standard boot ==="
########################################################


[ "$LOGLEVEL" -eq 7 ] && set -x
[ "$LOGLEVEL" -le 3 -o "$LOGLEVEL" -eq 7 ] && exec 1>/tmp/bootinit.log 2>&1 #remove o/p from console. v2.22 loglevel added.

[ ! -f /bin/resize2fs ] && touch /tmp/no_resize2fs

# sets PLANG, PKEYS, VFAT_OUT_PARAM, FONTMAP, KMAP, CODEPAGE
[ -f /sbin/set_plang ] && . /sbin/set_plang

#pmedia= usbflash|usbhd|usbcd|ataflash|atahd|atacd|atazip|scsihd|scsicd|cd
[ $pmedia ] && PMEDIA=$pmedia #boot parameter, broad category of boot media. ex: cd.
[ $psubdir ] && PSUBDIR=$psubdir #boot parameter, directory for puppy files. ex: puppy220
[ $psavemark ] && PSAVEMARK=$psavemark #100913 partition number that has/will-have save-file.

[ $PSUBDIR ] && [ "${PSUBDIR:0:1}" != "/" ] && PSUBDIR="/${PSUBDIR}" #add leading /.

[ $pdev1 ] && PDRV=$pdev1 #boot parameter, partition have booted off. ex: hda3
#100915 requested by technosaurus (formats get changed further down)...
[ $pdrv ] && PDRV=$pdrv #format partition:<path><filename> ex: sda2:/slacko/puppy_slacko_6.3.0.sfs
[ $pupsfs ] && PDRV=$pupsfs
[ $zdrv ] && ZDRV=$zdrv #ex: sda2:/slacko/zdrv_slacko_6.3.0.sfs
[ $fdrv ] && FDRV=$fdrv
[ $adrv ] && ADRV=$adrv
[ $ydrv ] && YDRV=$ydrv
[ $bdrv ] && BDRV=$bdrv
#<partition>:<filename>, for savefile/savefolder. <partition> can be a name or Label or UUID
[ $psave ] && PSAVE=$psave #ex: sdb4:/puppy/tahr/tahrsave or smark or 49baa82d-8c69:tahrsave
#list of kernel modules to load, ex: pimod=hid-logitech-dj.ko,kernel/drivers/hid/hid-multitouch.ko 
[ $pimod ] && PIMOD=$pimod
#wireless credentials passed to main system
[ $pwireless ] && PWIRELESS=$pwireless # ex: pwireless=myssid:mypassword
if [ $waitdev ];then
 WAITDEV=$waitdev
else
 WAITDEV=5
fi

#[ $pdebug ] && PDEBUG=$pdebug
PDEBUG=1
TOTAL_SIZEK_SFS_RAM=0

RDSH=""
if [ "$pfix" ];then
 for ONEFIX in $(echo -n "$pfix" | tr ',' ' ')
 do
  case $ONEFIX in
   ram)     PRAMONLY="yes";;      #run in ram only (do not load ${DISTRO_FILE_PREFIX}save).
   rdsh)    RDSH="yes";;          #exit to shell in initial ramdisk.
   xorgwizard) PXORGWIZARD="yes";;#force xorgwizard for this session
   nox)     PNOX="yes";;          #do not start X.
   clean)   PCLEAN="yes";;        #force version upgrade and cleanup.
   copy)    PCOPY="yes";;         #copy .sfs files into ram.
   nocopy)  PNOCOPY="yes";;        #do not copy .sfs files into ram (default is copy if enough ram).
   fsck)    PFSCK="yes";;         #do a fsck of ${DISTRO_FILE_PREFIX}save file.
   fsckp)   PFSCKP="yes";;        #do fsck before first mount of ext partitions
   [0-9]*)  PIGNORELAST=$ONEFIX;; #blacklist last $ONEFIX folders (multisession).
   *)       echo "pfix=$ONEFIX is not a known boot parameter";;
  esac
 done
fi

export PFSCK # read by /sbin/load_ext_file

[ "$PRAMONLY" != "yes" ] && [ -f /BOOT_SPECS ] && . /BOOT_SPECS

[ "$TZ" ] && export TZ
hwclock -l -s

ISO_LOOP=''
if [ -f /sbin/isoboot ] ; then
  . /sbin/isoboot # optional, can remove all occurrences of "isoboot" from this script
fi
if [ "$PDRV" = '' ]; then
  if [ "$ISO_LOOP" = '' ]; then
    [ "$GRUB_ROOT" ] && PDRV=$GRUB_ROOT
  fi
fi

[ "$PDEBUG" ] && echo "0: PMEDIA=$PMEDIA PDRV=$PDRV PSUBDIR=$PSUBDIR pfix=$pfix"

#100915 technosaurus recommendation (see above)...
[ "$PDRV" ] && { decode_spec "$PDRV"; P_BP_ID="$ONE_BP_ID"; P_BP_FN="$ONE_BP_FN"; PDRV=""; }
[ "$ZDRV" ] && { decode_spec "$ZDRV"; Z_BP_ID="$ONE_BP_ID"; Z_BP_FN="$ONE_BP_FN"; ZDRV=""; }
[ "$FDRV" ] && { decode_spec "$FDRV"; F_BP_ID="$ONE_BP_ID"; F_BP_FN="$ONE_BP_FN"; FDRV=""; }	
[ "$ADRV" ] && { decode_spec "$ADRV"; A_BP_ID="$ONE_BP_ID"; A_BP_FN="$ONE_BP_FN"; ADRV=""; }
[ "$YDRV" ] && { decode_spec "$YDRV"; Y_BP_ID="$ONE_BP_ID"; Y_BP_FN="$ONE_BP_FN"; YDRV=""; }
[ "$BDRV" ] && { decode_spec "$BDRV"; B_BP_ID="$ONE_BP_ID"; B_BP_FN="$ONE_BP_FN"; BDRV=""; }
[ "$PSAVE" ] && { decode_spec "$PSAVE"; SAVE_BP_ID="$ONE_BP_ID"; SAVE_BP_FN="$ONE_BP_FN"; }
SAVE_BP_DIR=""
[ "$SAVE_BP_FN" ] && [ "${SAVE_BP_FN:$((${#SAVE_BP_FN} - 1))}" = "/" ] && SAVE_BP_DIR="$SAVE_BP_FN" #last char

#first look inside initrd...
#unset x_DEF_FN so that find_onepupdrv() won't look for it
[ -f /${P_DEF_FN} ] && { PDRV="rootfs,rootfs,/$P_DEF_FN"; P_DEF_FN=""; }
[ -f /${Z_DEF_FN} ] && { ZDRV="rootfs,rootfs,/$Z_DEF_FN"; Z_DEF_FN=""; }
[ -f /${F_DEF_FN} ] && { FDRV="rootfs,rootfs,/$F_DEF_FN"; F_DEF_FN=""; }
[ -f /${A_DEF_FN} ] && { ADRV="rootfs,rootfs,/$A_DEF_FN"; A_DEF_FN=""; }
[ -f /${Y_DEF_FN} ] && { YDRV="rootfs,rootfs,/$Y_DEF_FN"; Y_DEF_FN=""; }
[ -f /${B_DEF_FN} ] && { BDRV="rootfs,rootfs,/$B_DEF_FN"; B_DEF_FN=""; }

#setup wireless
[ "$PWIRELESS" ] && echo -e "SSID=${PWIRELESS%:*}\nPSWD=${PWIRELESS#*:}" > /tmp/wireless.conf

get_part_info

PUP_SAVES=""
KEEPMOUNTED=""
FSCKDPARTS=""

[ "$PDEBUG" ] && echo "1: PDRV=$PDRV P_BP_ID=$P_BP_ID P_BP_FN=$P_BP_FN"

#establish PDRV
P_PART=""; LOOK_PUP=""; LOOK_SAVE=""
if [ "$P_BP_ID" ];then #specified as parameter
 decode_id "$P_BP_ID"
 [ "$ONE_PART" ] && { P_PART="$ONE_PART"; P_BP_ID=""; }
 find_onepupdrv "$P_PART" "$P_BP_FN" "$P_DEF_FN" "p" ""
 [ "$ONE_FN" ] && { PDRV="$ONE_PART,$ONE_FS,$ONE_FN"; P_MP="$ONE_MP"; }
 [ "$PDEBUG" ] && echo "2: ONE_PART=$ONE_PART ONE_FN=$ONE_FN ONE_MP=$ONE_MP"
elif [ "$PDRV" = "" ];then #not specified anywhere
 #determine what to search for
 [ "$PMEDIA" = "cd" ] && LOOK_SAVE="yes"
 [ "$SAVE_BP_ID" -o "$PSAVEMARK" ] && LOOK_SAVE=""
 LOOK_PUP=yes
 [ "$PDEBUG" ] && echo "2: LOOK_PUP=$LOOK_PUP LOOK_SAVE=$LOOK_SAVE PMEDIA=$PMEDIA"
fi

if [ "$LOOK_PUP" -o "$LOOK_SAVE" ];then #something to search for
 search_func
 NUM=0
 while [ "$LOOK_PUP" -a "$P_PART" = "" ] || [ "$LOOK_SAVE" -a "$SAVEPART" = "" ];do
  [ $NUM -ge $WAITDEV ] && break
  printf "${L_WAITING_FOR_DEV}\n" "$WAITDEV" "$NUM" "$WAITDEV" > /dev/console
  sleep 1
  get_part_info
  if [ "${PMEDIA:0:3}" = "usb" ] ; then
   USBDRVS="$(find /sys/block -maxdepth 1 -name 'sd*' -o -name 'sr*' | xargs -n 1 readlink 2>/dev/null | grep '/usb[0-9]' | rev | cut -f 1 -d '/' | rev | tr '\n' '|')"
   [ "$PDEBUG" ] && echo "2: USBDRVS=$USBDRVS -> ${USBDRVS%|}"
   if [ "$USBDRVS" ] ; then
    search_func "${USBDRVS%|}"
   else
    search_func
   fi
  else
   search_func
  fi
  NUM=$(($NUM + 1))
 done
fi
[ "$P_BP_ID" ] && { log_part_id "$P_BP_ID"; ONE_PART="$P_BP_ID"; }
[ "$PDEBUG" ] && echo "6: ONE_PART=$ONE_PART ONE_TRY_FN=$ONE_TRY_FN PDRV=$PDRV"
if [ "$PDRV" = "" ];then
 [ "$ONE_TRY_FN" ] || ONE_TRY_FN="$PSUBDIR/$P_DEF_FN"
 fatal_error "$ONE_PART $ONE_TRY_FN not found." "Finding puppy main sfs file."
fi

check_resize_part
grep -v '^sr' /tmp/ALLDRVS0 > /tmp/ATADRIVES0
ATAOPTICALDRIVES="$(grep '^sr' /tmp/ALLDRVS0 | tr '\n' ' ')"

#establish SAVEPART
decode_other_ids
if [ "$P_PART" ];then
 BOOTDRV="$(echo -n "$P_PART" | grep -o -f /tmp/ALLDRVS0)" #110205 ex: sda1 becomes sda.
 if [ "$SAVEPART" = "" ];then #setup SAVEPART
  [ "$P_MP" ] || P_MP="$(mount | grep -m1 "/dev/$P_PART " | cut -f 3 -d ' ')"
  [ -f ${P_MP}${PSUBDIR}/SAVEMARK ] && PSAVEMARK="$(tr -d '\r' < ${P_MP}${PSUBDIR}/SAVEMARK)" #partition no. that has or will-have ${DISTRO_FILE_PREFIX}save.2fs. 101020
  if [ "$PSAVEMARK" -a "$BOOTDRV" ];then
   ONE_PART="${BOOTDRV}${PSAVEMARK}" #note, PSAVEMARK could also be a kernel boot param. ex: 2
   if [ "$(echo $HAVE_PARTS | grep "$ONE_PART")" ];then #partition exists
    SAVEPART="$ONE_PART"; PSAVEPART="$ONE_PART"; SAVE_BP_DIR="${PSUBDIR}/"
    PSAVEMARK=''
   fi
  fi
 fi
fi

#have pup...sfs, now try to load it
RAMSIZE=$(free | grep -o 'Mem: .*' | tr -s ' ' | cut -f 2 -d ' ') #total physical ram (less shared video). 110405

mount -t tmpfs tmpfs /mnt/tmpfs
[ -d "/mnt/tmpfs/pup_rw" ] || mkdir /mnt/tmpfs/pup_rw

NEWUNIONRECORD=""
COPY2RAM=""
#- handle pfix=copy pfix=ram pfix=nocopy
if [ "$PCOPY" = "yes" -o "$PRAMONLY" = "yes" ] ; then
 COPY2RAM="yes"
elif [ "$PNOCOPY" = "yes" ] ; then
 COPY2RAM="no"
fi

LOADMSG="${L_LOAD_MESSAGE}"
setup_onepupdrv "$PDRV" "p"
STATUS=$?
if [ $STATUS -gt 0 ];then
 P_PRE_MSG="${L_PRE_MESSAGE}"
 case $STATUS in
  1) fatal_error "$(printf "${L_ERR_PDRV_INCOMPLETE}" "$PDRV")" "$P_PRE_MSG" ;;
  2) fatal_error "$(printf "${L_ERR_ONEPART_NOT_MOUNTED}" "$ONE_PART")" "$P_PRE_MSG" ;;
  3) fatal_error "$(printf "${L_ERR_ONEPART_NOT_OK}" "$ONE_PART" "$ONE_REL_FN")" "$P_PRE_MSG" ;;
  4) fatal_error "$(printf "${L_ERR_ONEPART_MOUNT_SFS_FAILED}" "$ONE_PART" "$ONE_REL_FN")" "$P_PRE_MSG" ;;
  5) fatal_error "$(printf "${L_ERR_AUFS_SFS_FAILED}" "$ONE_LAYER")" "$P_PRE_MSG" ;;
 esac
fi
PUP_LAYER="$SFS_MP"

#all partition id's should be decoded by now
[ "$Z_BP_ID" ] && log_part_id "$Z_BP_ID"
[ "$F_BP_ID" ] && log_part_id "$F_BP_ID"
[ "$A_BP_ID" ] && log_part_id "$A_BP_ID"
[ "$Y_BP_ID" ] && log_part_id "$Y_BP_ID"
[ "$B_BP_ID" ] && log_part_id "$B_BP_ID"
[ "$SAVE_BP_ID" ] && log_part_id "$SAVE_BP_ID"

#have basic system, now try to add optional stuff
find_onepupdrv "$F_PART" "$F_BP_FN" "$F_DEF_FN" "f" ""
[ "$ONE_FN" ] && FDRV="$ONE_PART,$ONE_FS,$ONE_FN"

find_onepupdrv "$Z_PART" "$Z_BP_FN" "$Z_DEF_FN" "z" ""
[ "$ONE_FN" ] && ZDRV="$ONE_PART,$ONE_FS,$ONE_FN"

find_onepupdrv "$Y_PART" "$Y_BP_FN" "$Y_DEF_FN" "y" ""
[ "$ONE_FN" ] && YDRV="$ONE_PART,$ONE_FS,$ONE_FN"

find_onepupdrv "$B_PART" "$B_BP_FN" "$B_DEF_FN" "b" ""
[ "$ONE_FN" ] && BDRV="$ONE_PART,$ONE_FS,$ONE_FN"

find_onepupdrv "$A_PART" "$A_BP_FN" "$A_DEF_FN" "a" ""
[ "$ONE_FN" ] && ADRV="$ONE_PART,$ONE_FS,$ONE_FN"

find_onepupdrv "" "" "$KBUILD_DEF_FN" "k" ""
[ "$ONE_FN" ] && KBUILD="$ONE_PART,$ONE_FS,$ONE_FN"

if [ "$UNIONFS" = 'overlay' ]; then
 find_onepupdrv "" "" "$DEVX_DEF_FN" "k" ""
 [ "$ONE_FN" ] && DEVX="$ONE_PART,$ONE_FS,$ONE_FN"

 find_onepupdrv "" "" "$DOCX_DEF_FN" "k" ""
 [ "$ONE_FN" ] && DOCX="$ONE_PART,$ONE_FS,$ONE_FN"

 find_onepupdrv "" "" "$NLSX_DEF_FN" "k" ""
 [ "$ONE_FN" ] && NLSX="$ONE_PART,$ONE_FS,$ONE_FN"
fi

#if possible, copy SFSs to RAM and prioritize frequently-accessed ones
[ "$ADRV" ] && copy_onepupdrv "$ADRV"
[ "$YDRV" ] && copy_onepupdrv "$YDRV"
[ "$BDRV" ] && copy_onepupdrv "$BDRV"
[ "$DEVX" ] && copy_onepupdrv "$DEVX"
[ "$NLSX" ] && copy_onepupdrv "$NLSX"
[ "$DOCX" ] && copy_onepupdrv "$DOCX"
[ "$ZDRV" ] && copy_onepupdrv "$ZDRV"
[ "$FDRV" ] && copy_onepupdrv "$FDRV"
[ "$KBUILD" ] && copy_onepupdrv "$KBUILD"

#stack the SFSs on top of pdrv
[ "$DEVX" ] && { LOADMSG="devx"; stack_onepupdrv "$DEVX" "dev"; }
[ "$NLSX" ] && { LOADMSG="nlsx"; stack_onepupdrv "$NLSX" "nls"; }
[ "$DOCX" ] && { LOADMSG="docx"; stack_onepupdrv "$DOCX" "doc"; }
[ "$KBUILD" ] && { LOADMSG="kbuild"; stack_onepupdrv "$KBUILD" "k"; }
[ "$FDRV" ] && { LOADMSG="fdrv"; stack_onepupdrv "$FDRV" "f"; }
[ "$ZDRV" ] && { LOADMSG="zdrv"; stack_onepupdrv "$ZDRV" "z"; }
[ "$BDRV" ] && { LOADMSG="bdrv"; stack_onepupdrv "$BDRV" "b" "p"; }
[ "$YDRV" ] && { LOADMSG="ydrv"; stack_onepupdrv "$YDRV" "y" "p"; }
[ "$ADRV" ] && { LOADMSG="adrv"; stack_onepupdrv "$ADRV" "a" "p"; }

#process SAVESPEC - takes precedence - written by shutdownconfig
if [ -f "${P_MP}${PSUBDIR}/SAVESPEC" ];then
 echo "Using ${P_MP}${PSUBDIR}/SAVESPEC"
 tr -d '\r' < "${P_MP}${PSUBDIR}/SAVESPEC" > /tmp/SAVESPEC
fi
#maybe other sources for a SAVESPEC file
if [ -f "/tmp/SAVESPEC" ];then
 . /tmp/SAVESPEC
 rm /tmp/SAVESPEC
 if [ "$SS_ID" ];then
  decode_id "$SS_ID"
  [ "$ONE_PART" ] && { SAVEPART="$ONE_PART"; PSAVEPART="$ONE_PART"; }
 fi
 if [ "$SS_DIR" ];then
  SAVE_BP_DIR="${SS_DIR%/}/" #ensure trailing '/'
  [ "${SAVE_BP_DIR:0:1}" = '/' ] || SAVE_BP_DIR="/$SAVE_BP_DIR" #ensure leading '/'
  SAVE_BP_FN="$SAVE_BP_DIR"
 fi
 [ "$SS_MEDIA" ] && PMEDIA="$SS_MEDIA"
fi

[ "$SAVEPART" ] || SAVEPART="$P_PART"

#ensure that save partition is mounted
#if SAVEPART is not the same as P_PART
#moved up here to ensure config files are available
[ "$SAVEPART" ] && ensure_save_mounted

#support initmodules.txt
if [ "$PIMOD" = "" ]; then
  PIMOD_DIR=""
  case $SAVE_BP_FN in
    */*) PIMOD_DIR="${SAVE_BP_FN%/*}" ;;
    *) PIMOD_DIR="${PSUBDIR}" ;;
  esac
  PIMOD_FN="${SAVE_MP}${PIMOD_DIR}/${DISTRO_FILE_PREFIX}initmodules.txt"
  if [ -s "$PIMOD_FN" ]; then
   PIMOD="$(cat "$PIMOD_FN")"
   echo "Using $PIMOD_FN"
  fi
fi
#modprobe modules needed by keyboard
if [ "$PIMOD" != "" ]; then
 [ -L "/lib/modules/$KERNELVER" ] || ln -sv /pup_new/lib/modules/$KERNELVER /lib/modules/$KERNELVER
 [ -L "/lib/firmware" ] || ln -sv /pup_new/lib/firmware /lib/firmware
 for ONEMOD in `echo -n "$PIMOD" | tr ',' ' '`;do
  echo -n "$(printf "${L_ADDING_MODULE}" "$ONEMOD")" > /dev/console
  modprobe "$ONEMOD" > /dev/console 2>&1
  check_status $?
 done
fi

#find PUPSAVE, sortout pupmode
PUPMODE=5

#debug
echo --------------------
echo "SAVE_MP=${SAVE_MP}"
echo "PRAMONLY=${PRAMONLY}"
echo "BOOTDRV=${BOOTDRV}"
mount
echo --------------------

PUPSAVE=""
if [ "${SAVE_MP}" != "" -a "$PRAMONLY" != "yes" ];then #have mounted save? partition
 #check if save partition is linux
 set_fs_linux "$SAVE_FS"
 #check for pupmode=66
 if [ "$SAVE_FS" = "vfat" -o "$SAVE_FS" = "exfat" ];then
  FN_66=${PSUBDIR}/${DISTRO_FILE_PREFIX}save66.tar.gz
  if [ -e "${SAVE_MP}${FN_66}" ];then
    PUPMODE=66
    PUPSAVE="${SAVEPART},${SAVE_FS},${FN_66}"
  fi
 fi
 #check for cd multisession
 if [ "$SAVE_FS" = "iso9660" ];then #booting on optical, is it multisession?...
  BKFOLDERS="$(find $SAVE_MP -maxdepth 1 -xdev -type d -name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' | sed -e s%^${SAVE_MP}/%% | sort -r)"
  if [ "$BKFOLDERS" ];then #multisession cd/dvd
   FND_MULTIFOLDER="/$(echo "$BKFOLDERS" | head -n 1)"
   if [ "$FND_MULTIFOLDER" ];then #multisession cd/dvd
    PUPMODE=77
    PUPSAVE="${SAVEPART},${SAVE_FS},${FND_MULTIFOLDER}"
   fi
  fi
 fi
 echo "FND_MULTIFOLDER=${FND_MULTIFOLDER}" #debug
 #check for save to partition 
 if [ "$ONE_FS_IS_LINUX" = "yes" -a "$PSUBDIR" = "" -a -f "${SAVE_MP}/etc/rc.d/PUPSTATE" ];then
  # make sure it's not a full install
  if ! grep -q 'PUPMODE=2' ${SAVE_MP}/etc/rc.d/PUPSTATE ; then
    # PUPMODE=6 PUPMODE=7 - unsupported
    if [ "$ONE_FS_IS_LINUX" = "yes" ] ; then #savefolder is a full partition
      PUPSAVE="$SAVEPART,$SAVE_FS,"
      PUPMODE=12
      ONE_PART="$(echo -n "$PUPSAVE" | cut -f 1 -d ',')"
      [ "$ONE_PART" != "$SAVEPART" ] && { SAVEPART="$ONE_PART"; ensure_save_mounted; }
    fi
  fi
 fi
 #not sorted yet, may be pupmode=12
 if [ $PUPMODE -eq 5 ];then
  #check boot spec
  if [ "$SAVE_BP_FN" -a "$SAVE_BP_DIR" = "" ];then
   if [ -d "${SAVE_MP}${SAVE_BP_FN}" ];then
    [ "$ONE_FS_IS_LINUX" = "yes" ] && PUPSAVE="$SAVEPART,$SAVE_FS,$SAVE_BP_FN"
   else
    [ -s "${SAVE_MP}${SAVE_BP_FN}" ] && PUPSAVE="$SAVEPART,$SAVE_FS,$SAVE_BP_FN"
   fi
   [ "$PUPSAVE" ] || echo "$SAVEPART, $SAVE_BP_FN file not found."
  else
   #have to find savefile/savefolder
   [ "$PUP_SAVES" ] || find_save_file "${SAVE_MP}" "$SAVEPART" "$SAVE_FS"
   echo "PUP_SAVES=${PUP_SAVES}" #debug
   if [ "$PUP_SAVES" ];then
    NUMPUP_SAVES=0
    for ONE_SAVE in $PUP_SAVES;do
     NUMPUP_SAVES=$(expr $NUMPUP_SAVES + 1)
    done
    echo "NUMPUP_SAVES=${NUMPUP_SAVES}" #debug
    if [ $NUMPUP_SAVES -eq 1 ];then
     PUPSAVE="$(echo -n $PUP_SAVES)"
    elif [ $NUMPUP_SAVES -gt 1 ];then
     CNTSAVE=1
     echo -e "\\033[1;36m" >/dev/console #36=aquablue
     echo "${L_ERR_TYPE_PUPSAVE}" > /dev/console
     echo "${L_0_NONE}" > /dev/console
     for ONETRY in $PUP_SAVES
     do
      ONE_PART="$(echo -n "$ONETRY" | cut -f 1 -d ',')"
      ONE_FILE="$(echo -n "$ONETRY" | cut -f 3 -d ',')"
      echo -e "${CNTSAVE}  ${ONE_PART}\\033[10G${ONE_FILE}" > /dev/console #10 means move to that column.
      CNTSAVE=$(expr $CNTSAVE + 1)
     done
     echo -en "\\033[0;39m" >/dev/console
     read NUMSAVE
     #--  $NUMSAVE -ne 0 = have selected a PUPSAVE ...
     if [ $NUMSAVE -ne 0 ] ; then
      echo -e "\n----" #debug
      echo "Have selected pupsave $NUMSAVE" #debug
      PUPSAVE="$(echo -n $PUP_SAVES | cut -f $NUMSAVE -d ' ')"
      PSPATH="${SAVE_MP}/$(echo "$PUPSAVE" | cut -f 3 -d ',')"
      echo "PSPATH=${PSPATH}" #debug
     fi
     #----------------------------------------------------
    fi
   fi
  fi
  echo "PUPSAVE=${PUPSAVE}" #debug
  if [ "$PUPSAVE" ];then
   echo "Setting PUPMODE 12" #debug
   PUPMODE=12
   ONE_PART="$(echo -n "$PUPSAVE" | cut -f 1 -d ',')"
   [ "$ONE_PART" != "$SAVEPART" ] && { SAVEPART="$ONE_PART"; ensure_save_mounted; }
  fi
 fi
fi

SAVE_LAYER=""
WORKDIR="/pup_work"
if [ "$PUPSAVE" ];then #refine pupmode
 # refine pupmode
 if [ $PUPMODE -eq 12 ];then
  SAVE_LAYER="/pup_rw"
  if [ -z "$PMEDIA" -o "$PMEDIA" = "cd" ] ; then
   [ "`cat /sys/block/$(fx_get_drvname $SAVEPART)/removable`" = "1" ] && xPM=13
  fi
  if [ "${PMEDIA:3}" = "flash" -o "$xPM" = "13" ];then
   PUPMODE=$(($PUPMODE + 1)) #PUPMODE=13
   echo "Setting PUPMODE $PUPMODE" #debug
   SAVE_LAYER="/pup_ro1"
  fi
  echo "SAVE_LAYER=$SAVE_LAYER" #debug
 elif [ $PUPMODE -eq 77 ];then
  SAVE_LAYER="/pup_ro1"
 fi
fi

#load savefile if required, then setup stack
case $PUPMODE in
 77|13)
  [ $PUPMODE -eq 77 ] && copy_folders #to /pup_ro1 (part of the tmpfs)
  [ $PUPMODE -eq 13 ] && setup_psave
  if [ "$PUPSAVE" ] ; then
    #prepend ro1 - #SAVE_LAYER=/pup_ro1
    rm -rf ${SAVE_LAYER}/tmp #in case last boot was pupmode=12
    #adjust stack
    if [ "$UNIONFS" = 'overlay' ]; then
     #pup_rw is bigger because files are copied, not moved to pup_ro1
     mount -o remount,size=75% /mnt/tmpfs
     remount_overlay "s~lowerdir=([^,]+)~lowerdir=${SAVE_LAYER}:\1~"
    else
     echo "mount -o remount,add:1:${SAVE_LAYER}=ro+wh /pup_new" #debug
     mount -o remount,add:1:${SAVE_LAYER}=ro+wh /pup_new #ro+wh = Readonly branch and it has/might have whiteouts on it
    fi
    if [ $? -eq 0 ];then
      [ $PUPMODE -ne 77 ] && KEEPMOUNTED="${KEEPMOUNTED}${SAVEPART} "
      [ "$SAVE_NAME" ] && NEWUNIONRECORD="$SAVE_NAME $NEWUNIONRECORD"
    else
      printf "${L_ADDING_SAVE_LAYER_FAILED}\n" "$SAVE_LAYER"
    fi
  fi
 ;;
 12) #replace rw
  setup_psave
  if [ "$PUPSAVE" ] ; then
    #SAVE_LAYER=/pup_rw
    #setup empty /tmp on tmpfs for in stack
    rm -rf ${SAVE_LAYER}/tmp
    #adjust stack
    if [ "$UNIONFS" = 'overlay' ]; then
     remount_overlay -e "s~upperdir=[^,]+~upperdir=${SAVE_LAYER}~" -e "s~workdir=[^,]+~workdir=${WORKDIR}~"
    else
     echo "mount -o remount,prepend:${SAVE_LAYER}=rw,mod:/mnt/tmpfs/pup_rw=ro,del:/mnt/tmpfs/pup_rw /pup_new" #debug
     mount -o remount,prepend:${SAVE_LAYER}=rw,mod:/mnt/tmpfs/pup_rw=ro,del:/mnt/tmpfs/pup_rw /pup_new
    fi
    if [ $? -eq 0 ];then
      rm -rf /mnt/tmpfs/pup_rw
      KEEPMOUNTED="${KEEPMOUNTED}${SAVEPART} "
      [ "$SAVE_NAME" ] && NEWUNIONRECORD="$SAVE_NAME $NEWUNIONRECORD"
    else
      printf "${L_ADDING_SAVE_LAYER_FAILED}\n" "$SAVE_LAYER"
    fi
  fi
 ;;
 66) #extract to stack at new tmpfs
  ARCHIVE_FN="${SAVE_MP}${PUPSAVE#*,*,}"
  if [ -s "$ARCHIVE_FN" ];then
    echo -n "$(printf "${L_LOADING_SAVE_ARCHIVE}" "${PUPSAVE#*,*,}" "$SAVEPART")" > /dev/console
    echo "--SAVEARCHIVE-- $ARCHIVE_FN" #debug
    if [ "$UNIONFS" = 'overlay' ]; then
      PM66_DIR='/pup_rw66'
      mkdir $PM66_DIR
      mount -t tmpfs tmpfs $PM66_DIR
      mkdir $PM66_DIR/upper $PM66_DIR/work
      tar xf "$ARCHIVE_FN" -m -C $PM66_DIR/upper 2>/dev/null
      STATUS=$?
      if [ $STATUS -eq 0 ];then
        remount_overlay -e "s~upperdir=[^,]+~upperdir=${PM66_DIR}/upper~" -e "s~workdir=[^,]+~workdir=${PM66_DIR}/work~"
        STATUS=$?
      fi
    else
      PM66_DIR='/pup_rw'
      rm -r -f "$PM66_DIR"
      [ -d "$PM66_DIR" ] || mkdir $PM66_DIR
      mount -t tmpfs tmpfs $PM66_DIR
      tar xf "$ARCHIVE_FN" -m -C $PM66_DIR 2>/dev/null
      STATUS=$?
      if [ $STATUS -eq 0 ];then
        #replace rw branch with new populated tmpfs
        echo "mount -o remount,prepend:${PM66_DIR}=rw,mod:/mnt/tmpfs/pup_rw=ro,del:/mnt/tmpfs/pup_rw /pup_new" #debug
        mount -o remount,prepend:${PM66_DIR}=rw,mod:/mnt/tmpfs/pup_rw=ro,del:/mnt/tmpfs/pup_rw /pup_new
        STATUS=$?
      fi
    fi
    if [ $STATUS -eq 0 ];then
      SAVE_MP=''
      rm -rf /mnt/tmpfs/pup_rw
    else
      printf "${L_ADDING_SAVE_LAYER_FAILED}\n" "$PM66_DIR"
    fi
    check_status $STATUS
  fi
 ;;
 5)
  SAVE_MP=""
 ;;
esac

if [ "$SAVEPART" -a "$UNIONFS" = 'overlay' -a -f /pup_new/etc/rc.d/BOOTCONFIG ]; then
 # under PUPMODE 12, a dynamically loaded SFS may leave behind symlinks in the save layer
 PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/X11R7/bin chroot /pup_new /usr/sbin/sfs_load.overlay --cli stop

 EXTRASFSLIST=""
 . /pup_new/etc/rc.d/BOOTCONFIG
 for ONE_SFS in $EXTRASFSLIST; do
  LOOP=`losetup -f`
  find_onepupdrv "$SAVEPART" "" "$ONE_SFS" "p" "1"
  [ "$ONE_FN" ] && { LOADMSG="extra"; setup_onepupdrv "$ONE_PART,$ONE_FS,$ONE_FN" "ro${LOOP#/dev/loop}" ""; }
 done
fi

umount_unneeded

echo -n $(($TOTAL_SIZEK_SFS_RAM - 5)) > /tmp/sfs_ram_sizek

[ "$DEV1FS" ] || DEV1FS="$(echo "$PDRV" | cut -f 2 -d ',')"
[ "$ATADRIVES" ] || ATADRIVES="$(cat /tmp/ATADRIVES0 | tr '\n' ' ')"

mkdir -p /pup_new/etc/rc.d
( # > /pup_new/etc/rc.d/PUPSTATE
echo "PUPMODE=$PUPMODE"
echo "PDEV1='$P_PART'"
echo "DEV1FS='$DEV1FS'"
echo "PUPSFS='$PDRV'"
echo "PUPSAVE='$PUPSAVE'"
echo "PMEDIA='$PMEDIA'"
echo '#ATADRIVES is all internal ide/pata/sata drives, excluding optical, excluding usb...'
echo "ATADRIVES='$ATADRIVES'"
echo '#ATAOPTICALDRIVES is list of non-usb optical drives...'
echo "ATAOPTICALDRIVES='$ATAOPTICALDRIVES'"
echo '#these directories are unionfs/aufs layers in /initrd...'
echo "RW_LAYER='/pup_rw'"
echo "SAVE_LAYER='$SAVE_LAYER'"
echo "PUP_LAYER='$PUP_LAYER'"
echo "#The partition that has the ${DISTRO_FILE_PREFIX}save file is mounted here..."
echo "PUP_HOME='${SAVE_MP}'"
echo '#(in /initrd) ...note, /mnt/home is a link to it.'
echo '#this file has extra kernel drivers and firmware...'
echo "ZDRV='$ZDRV'"
echo "FDRV='$FDRV'"
echo "ADRV='$ADRV'"
echo "YDRV='$YDRV'"
echo "BDRV='$BDRV'"
echo '#Partition no. override on boot drive to which session is (or will be) saved...'
echo "PSAVEMARK='$PSAVEMARK'"
echo "PSAVEPART='$PSAVEPART'"
echo "PSAVEDIR='$SAVE_BP_DIR'"
echo "PSUBDIR='$PSUBDIR'"
echo "PUNIONFS='$UNIONFS'"
echo "DOIMODS='yes'"
echo "DOMIBS='no'"
[ -f /sbin/set_plang ] && plang_pupstate #echo
) > /pup_new/etc/rc.d/PUPSTATE

if [ "$PUPSAVE" ];then
 xBOOTCONFIG="$(grep -v '^PREVUNIONRECORD' /pup_new/etc/rc.d/BOOTCONFIG | sed -e 's/^LASTUNIONRECORD/PREVUNIONRECORD/')"
 echo "$xBOOTCONFIG" > /pup_new/etc/rc.d/BOOTCONFIG
 echo "LASTUNIONRECORD='$(echo -n $NEWUNIONRECORD)'" >> /pup_new/etc/rc.d/BOOTCONFIG
else
 echo "" > /pup_new/etc/rc.d/BOOTCONFIG
 echo "LASTUNIONRECORD=''" >> /pup_new/etc/rc.d/BOOTCONFIG
fi

echo -n "$(printf "${L_SWITCH_ROOT}" "${UNIONFS}")" >/dev/console

echo "Moving mountpoints to /pup_new/initrd for after switch..." #debug
rm -r -f "/pup_new/initrd${SAVE_LAYER}"
for ONEMNT in $(mount | cut -f 3 -d ' ' | grep -v 'pup_new' | grep '^/pup_' | tr '\n' ' ');do
 mkdir -p /pup_new/initrd${ONEMNT}
 echo "mount -o move $ONEMNT /pup_new/initrd${ONEMNT}" #debug
 mount -o move $ONEMNT /pup_new/initrd${ONEMNT}
done
for ONEMNT in $(mount | cut -f 3 -d ' ' | grep '^/mnt/' | tr '\n' ' ');do
 mkdir -p /pup_new/initrd${ONEMNT}
 echo "mount -o move $ONEMNT /pup_new/initrd${ONEMNT}" #debug
 mount -o move $ONEMNT /pup_new/initrd${ONEMNT}
done

echo -------------------- # debug
mount
echo -------------------- # debug

echo "SAVE_FN=$SAVE_FN"         #debug
echo "SAVE_LAYER=${SAVE_LAYER}" #debug

# --- create/fix symlinks to /pup_new/initrd/* for after switch

# remove symbolic links for after switch, that might be leftover
[ -L /pup_new/initrd/pup_rw ] && rm -rf /pup_new/initrd/pup_rw
[ -L /pup_new/initrd/pup_ro1 ] && rm -rf /pup_new/initrd/pup_ro1
[ -L /pup_new/tmp ] && rm -fv /pup_new/tmp

# SAVE_LAYER: /pup_rw or /pup_ro1
# savefolder: create symlink to the save layer mountpoint in /pup_new/initrd
# (for savefiles and savepartitions the SAVE_LAYER is not a symlink)
if [ "$PUPSAVE" ];then
 if [ "$SAVE_LAYER" -a -L "$SAVE_LAYER" ];then
  ln -sv "/initrd`readlink ${SAVE_LAYER}`" "/pup_new/initrd${SAVE_LAYER}" #for after switch
 elif [ $PUPMODE -eq 66 -a "$UNIONFS" = 'overlay' ];then
  ln -s /initrd$PM66_DIR/upper /pup_new/initrd/pup_rw
 fi
fi

# symlinks to /pup_new/initrd/tmpfs subdirs
# * /pup_rw:  pupmodes 5,13,77)
# * /pup_ro1: in PUPMODE 77 pup_ro1 is part of the tmpfs but an aufs read-only branch
#             where the previous session is stored to build the final filesystem
# * (rm -rf ... is an extra measure to ensure deletion
#     since an actual directory might be there and therefore was not deleted.)
if ! grep -q '/pup_new/initrd/pup_rw' /proc/mounts ; then
  if [ -d /pup_new/initrd/mnt/tmpfs/pup_rw ] ; then
    rm -rf /pup_new/initrd/pup_rw
    ln -sv /initrd/mnt/tmpfs/pup_rw /pup_new/initrd/pup_rw #for after switch
  fi
fi
if [ -d /pup_new/initrd/mnt/tmpfs/pup_ro1 ] ; then
  rm -rf /pup_new/initrd/pup_ro1
  ln -sv /initrd/mnt/tmpfs/pup_ro1 /pup_new/initrd/pup_ro1 #for after switch
fi
mkdir -p /pup_new/initrd/mnt/tmpfs/tmp
if [ -d /pup_new/initrd/mnt/tmpfs/tmp ];then #extra paranoid precaution
 chmod 1777 /pup_new/initrd/mnt/tmpfs/tmp
 rm -rf /pup_new/tmp
 ln -sv /initrd/mnt/tmpfs/tmp /pup_new/tmp #for after switch
fi

#---

[ "$PXORGWIZARD" = "yes" ] && touch /pup_new/initrd/mnt/tmpfs/tmp/xwin_xorgwizard_cli
#PNOX is a boot param. /etc/profile prevents X from starting if this file exists...
[ "$PNOX" = "yes" ] && touch /pup_new/initrd/mnt/tmpfs/tmp/bootcnt.txt

cp -a /DISTRO_SPECS /pup_new/initrd/
[ ! -f /pup_new/etc/DISTRO_SPECS ] && cp -a /DISTRO_SPECS /pup_new/etc/
cp -a /init* /sbin /README.txt /pup_new/initrd/
chmod -x /pup_new/initrd/init
dmesg > /tmp/dmesg.txt

[ -f /bin/cryptsetup ] && cp -af /bin/cryptsetup /pup_new/initrd/bin/ 
[ -f /sbin/cryptsetup ] && cp -af /sbin/cryptsetup /pup_new/initrd/sbin/ 

[ -d "/pup_new/initrd/tmp" ] && rm -rf /pup_new/initrd/tmp
mkdir -p /pup_new/initrd/tmp
cp -af /tmp/* /pup_new/initrd/tmp/ #keep any log files.

[ -f /sbin/set_plang ] && plang_copy_to_newroot #$LANG, /etc/keymap|fontmap|codepage

if [ "$RDSH" = "yes" ];then
 echo > /dev/console
 echo "${L_DROPPED_TO_INITRD_SHELL}" > /dev/console
 exec /bin/sh >/dev/console 2>&1
fi

sync
[ -d "/proc/bus/usb" ] && umount /proc/bus/usb
umount /sys
umount /dev
umount /proc

#now using cpio archive for initramfs 'initial ramdisk'...
exec switch_root /pup_new /sbin/init

###END###
