# Copyright (c) 2005--2025, Yoshihiro Kawamata
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
#   * Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 
#   * Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
# 
#   * Neither the name of Yoshihiro Kawamata nor the names of its
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


#====================
# interim rc file for LiveCD
#
# KAWAMATA, Yoshihiro
# kaw@on.rim.or.jp
#

#====================
# Global Definitions
#====================
init_args="$@"
osrel=`sysctl -n kern.osrelease`
osmac=`sysctl -n hw.machine`

#-------------------------------
# make a list of all partitions
#
scan_disks () {

    #-------------------------------
    # make a list of all partitions
    #
    for dsk in `sysctl -n hw.disknames | /boottmp/sed -E -e 's/:[0-9a-f]+/:/g; s/[:,]+/ /g;'`; do
        case $dsk in
            [csw]d[0-9]*)
                disklabel -c -pm $dsk 2> /dev/null \
                    | /boottmp/sed -E -e '/^  [abd-p]: /!d; s/^  (.):/'$dsk'\1/'
                ;;
        esac
    done > /boottmp/boot_partitions


    #-------------------------------
    # inspecting every disk partitions
    #
    echo -n "scanning partitions:"
    unset partlst part_sys part_sto part_enc part_swp part_noask
    while read ln; do
        set -- $ln
        part="$1"
        fstype="$4"
        partlst=${partlst:+"$partlst "}$part
        echo -n " $part"
        case $fstype in
            swap)
                part_swp=${part_swp:+"$part_swp "}$part
                ;;
            RAID)
                # search string 'SR CRYPTO' at head of partition
                # We cannot use "fgrep -q" because bin dirs not mounted yet.
                #
                if [ "`dd if=/dev/r$part bs=1k skip=8 count=1 2>/dev/null | /boottmp/sed -e '/SR CRYPTO/!d; s/.*SR CRYPTO.*/FOUND/'`" \
                     = 'FOUND' ]; then
                    part_enc=${part_enc:+"$part_enc "}$part
                fi
                ;;
            4.2BSD|ISO9660|MSDOS|NTFS|ext2fs)
                if mount -r /dev/$part /mnt 2> /dev/null; then
                    set -- /mnt/ISO/FuguIta-${osrel}-${osmac}-?????????.iso
                    if [ -f /mnt/fuguita-${osrel}-${osmac}.ffsimg -o ! X"$1" = X"/mnt/ISO/FuguIta-${osrel}-${osmac}-?????????.iso" ]; then
                        part_sys=${part_sys:+"$part_sys "}$part
                    fi
                    if [ -d /mnt/livecd-config ]; then
                        part_sto=${part_sto:+"$part_sto "}$part
                    fi
                    if [ -r /mnt/livecd-config/${osrel}/${osmac}/noasks ]; then
                        # set local parameters to null
                        local noask_rdev noask_umem noask_setup_rw_mode noask_confdev noask_confdata  # define local parameters
                        unset noask_rdev noask_umem noask_setup_rw_mode noask_confdev noask_confdata  # after unset, they become global
                        local noask_rdev noask_umem noask_setup_rw_mode noask_confdev noask_confdata  # so redefine them as local
                        . /mnt/livecd-config/${osrel}/${osmac}/noasks
                        if [ "X${noask_rdev}${noask_umem}${noask_setup_rw_mode}${noask_confdev}${noask_confdata}" != X ]; then
                            # any of noask parameters is set
                            part_noask=${part_noask:+"$part_noask "}${part}:/livecd-config/${osrel}/${osmac}/noasks
                        fi
                    fi
                    umount /dev/$part
                fi
                ;;
        esac
    done < /boottmp/boot_partitions
    echo
}

#-------------------------------
# parse  -  convert size with factor to megabytes
#
#  usage: parsesize factored-size memory-size(MB) swap-size(MB)
#
#         factors: n|n[Mm] - n megabytes
#                  n[kK]   - n kilobytes
#                  n[gG]   - n gigabytes
#                  n%      - n percent of memory-size
#                  n%%     - n percent of (memory-size+swap-size)
#
#    The result will be output to stdout with megabyte value
#    null string returned if conversion fails
#
parsesize () {
    local   umem="$1"; shift
    local maxmem="$1"; shift
    local swpmem="$1"; shift

    local d0='[0-9]'
    local d1='[1-9]'
    local k='[kK]'
    local m='[mM]'
    local g='[gG]'

    case "$umem" in
        $d0|$d1$d0|$d1$d0$d0|$d1$d0$d0$d0|$d1$d0$d0$d0$d0) # up to 99999(MB)
            echo $umem
            ;;
        $d0$k|$d1$d0$k|$d1$d0$d0$k|$d1$d0$d0$d0$k|$d1$d0$d0$d0$d0$k|$d1$d0$d0$d0$d0$d0$k|$d1$d0$d0$d0$d0$d0$d0$k|$d1$d0$d0$d0$d0$d0$d0$d0$k)  # up to 99999999KB
            echo $((${umem%?}/1024))
            ;;
        $d0$m|$d1$d0$m|$d1$d0$d0$m|$d1$d0$d0$d0$m|$d1$d0$d0$d0$d0$m) # up to 99999MB
            echo ${umem%?}
            ;;
        $d0$g|$d1$d0$g|$d1$d0$d0$g)  # up to 999GB
            echo $((1024*${umem%?}))
            ;;
        $d0%%|$d1$d0%%|100%%)
            echo $((${umem%??}*(maxmem+swpmem)/100))
            ;;
        $d0%|$d1$d0%|100%)
            echo $((${umem%?}*maxmem/100))
            ;;
        *)
    esac
}

#-------------------------------
# duid2dev  -  convert DUID.partition expression to DEVpartition
#     e.g. 7df1e3007af31be5.a -> sd0a
#                        sd0a -> sd0a
#               anything else -> NULL STRING
#
function duid2dev {
    devpart="$1"
    case X"$devpart"X in
        X[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[ad-p]X)
        # DUID expression - convert
            duid=${devpart%??}
            part=${devpart#?????????????????}

            local seendevs ddev matchdev

            OIFS="$IFS"
            IFS=','
            for dkname in `sysctl -n hw.disknames`;
            do
                dev=${dkname%:*}
                id=${dkname#*:}

                # warn DUID duplication
                #
                if [[ -n "$seendevs" &&
                          -n "$id" &&
                          "$seendevs" = *":$id"* ]]; then
                    ddev=${seendevs%%:${id}*}
                    ddev=${ddev##* }
                    echo "Warning: $ddev and $dev have the same DUID - $id" >&2
                fi
                seendevs=${seendevs:+"$seendevs "}"$dev:$id"

                # DUID matched - emit devname
                #
                if [ "$duid" = "$id" ]; then
                    matchdev="$dev$part"
                fi
            done
            IFS="$OIFS"

            [ -z "$ddev" ] && echo "$matchdev"
            ;;
        X[cws]d[0-9][ad-p]X|X[cws]d[1-9][0-9][ad-p]X)
        # DEV expression - no convert
            echo "$devpart"
            ;;
        XX)
            ;;
        *)
        # ILLEGAL expression
            echo "Warning: Illegal format for a disk partition - \"$devpart\"" >&2
            ;;
    esac
}

#-------------------------------
# make shadow directory
#
#    mkshadowdir orig-dir shadow-dir
#
mkshadowdir() {
    local  srcdir="$1"
    local destdir="$2"

    # error checks
    [ -n "$destdir" ]   || return  # no enough arguments
    [ -d "$srcdir" ]    || return  # non existent srcdir
    mkdir -p "$destdir" || return  # can't make destdir

    # make shadow directory tree
    lndir -s "$srcdir" "$destdir"

    # fix permissions and time stamps of target directories
    #
    # Note:
    # If the last output line of 'mtree -cdtq' starts with '..',
    # it will be deleted by sed.
    # This is because 'mtree -edtq' complains about such lines when
    # source directory is empty.
    mtree -p "$srcdir" -cdtq \
    | sed -e '${/^\.\.$/{d;};}' \
    | mtree -p "$destdir" -edtq -u > /dev/null
}


#-------------------------------
# return lesser value from two positive integer
#    returns null string when error occurred
#
min () {
    [[ -z "$1" ]] && return
    [[ -z "$2" ]] && return

    if [[ "$1" -lt "$2" ]]; then
        echo "$1"
    else
        echo "$2"
    fi
}


#====================
# Active code from here
#====================
# setup file systems;
#   1. /         ...  rd - ram disk attached to kernel
#   2. /sysmedia ...  CD or USB flashdrive - containing FFS system image
#   3. /fuguita  ...  vnode disk - mounted FFS system image
#   4. /ram      ...  user-modifiable file system
#

cd /

#-------------------------------
# setup root fs and record starting timestamp of boot
#
mount -w /dev/rd0a /
: > /boottmp/boot_starts

#----------------------------
# detect boot-failure loop
#
if [ -r /boottmp/boot_tries ]; then
    read boot_tries < /boottmp/boot_tries
    boot_tries=$((boot_tries+1))
else
    boot_tries=1
fi

if [ $boot_tries -ge 10 ]; then
    echo 'Boot retries exceeded.'
    echo -n 'emergency stop ->'; read dummy
    boot_tries=0
fi
echo $boot_tries > /boottmp/boot_tries

#-------------------------------
# ask which system-stored device is.
#
echo '
==================================================
=       ______               __   _
=      / ____/              |  |_| |__
=     / /____  ______  __  _|  /_   _/_____
=    / ___/ / / / __ \/ / / |  | | | /  _  |
=   / /  / /_/ / /_/ / /_/ /|  | | |_| (_) |__
=  /_/   \____/\__  /\____/ |__| \___/____/__/
=              __/ /
=             /___/
=
=  Welcome to FuguIta  -  OpenBSD-based Live System
=                              https://fuguita.org/
===================================================
'

scan_disks

#-------------------------------
# set noask parameters
# from a single noasks file
#
set -- $part_noask
if [ $# -eq 1 ]; then
    if [ ! X"$1" = X ] &&
    mount -r /dev/${1%%:*} /mnt; then  # strip after ":" from "devname:path"
        if [ -r /mnt/livecd-config/${osrel}/${osmac}/noasks ]; then
            . /mnt/livecd-config/${osrel}/${osmac}/noasks
        fi
        umount /mnt
    fi
elif [ $# -gt 1 ]; then
    echo "Warning: multiple noask files found: "
    for f in $part_noask; do
        echo "    $f"
    done
    echo "disabling non-interactive boot ..."
fi

#-------------------------------
# wait for cancelling non-interactive boot
#
if [ "X${noask_rdev}${noask_umem}${noask_setup_rw_mode}${noask_confdev}${noask_confdata}" != X ]; then
    trap "unset noask_rdev noask_umem noask_setup_rw_mode noask_confdev noask_confdata; echo ' ... cancelled'" 2
    echo "Press ^C to cancel non-interactive boot"
    sleep 5
fi
trap - 2


#-------------------------------
# ask user for FuguIta's operating device
#
if [ X"$part_sys" = X ]; then
    echo "Warning: None of FuguIta's operating device(s) found." 
else
    echo "FuguIta's operating device(s): ${part_sys}."
    set -- $part_sys
    if [ $# -eq 1 ]; then
        def_rdev="$1"
    fi
fi

noask_rdev=`duid2dev $noask_rdev`
if [ X = X"$noask_rdev" ]; then
    while :; do
        echo
        echo -n "Which is FuguIta's operating device? ${def_rdev:+[default: ${def_rdev}] }-> "
        read rdev
        [ -n "${def_rdev}${rdev}" ] && break
    done
    [ -z "${rdev}" ] && rdev="$def_rdev"
else
    echo "Which is FuguIta's operating device? -> $noask_rdev"
    rdev="$noask_rdev"
    noask_rdev=''
fi


#-------------------------------
# mount system-stored device
#
    vn_devname="vnd5"
vn_devname_iso="vnd4"

/sbin/mount -r /dev/${rdev} /fuguita || exit
if [ -f /fuguita/fuguita-${osrel}-${osmac}.ffsimg ]; then
    /sbin/umount /fuguita
    /sbin/mount -r /dev/${rdev} /sysmedia
    /sbin/vnconfig ${vn_devname} /sysmedia/fuguita-${osrel}-${osmac}.ffsimg
    /sbin/mount -r /dev/${vn_devname}a /fuguita
elif [ -d /fuguita/ISO ]; then
    /sbin/umount /fuguita
    /sbin/mount -r /dev/${rdev} /sysmedia
    set -- /sysmedia/ISO/FuguIta-${osrel}-${osmac}-?????????.iso
    shift $(($# - 1))
    if [ ! X"$1" = X -a \
         ! X"$1" = "X/sysmedia/ISO/FuguIta-${osrel}-${osmac}-?????????.iso" ] ;then
        umount /sysmedia
        mount -r /dev/${rdev} /sysmedia-iso
        /sbin/vnconfig ${vn_devname_iso} /sysmedia-iso/ISO/${1##*/}
        /sbin/mount -r /dev/${vn_devname_iso}a /sysmedia
        /sbin/vnconfig ${vn_devname} /sysmedia/fuguita-${osrel}-${osmac}.ffsimg
        /sbin/mount -r /dev/${vn_devname}a /fuguita
    fi
fi

#-------------------------------
# read global system configurations
#
if [[ -r /fuguita/etc/fuguita/global.conf ]]; then
    . /fuguita/etc/fuguita/global.conf  # for $mfs_max_mb
fi

#-------------------------------
# get ram size in MB
#
maxmem=$(($(sysctl -n hw.physmem)/1024/1024))

#-------------------------------
# activate swap partition(s)
#
if [ -n "$part_swp" ]; then
    for swdev in $part_swp; do
        echo "activating swap partition: /dev/$swdev"
        swapon /dev/$swdev
        if [[ "${rdev%?}" = "${swdev%?}" ]]; then
            # since rdev is a flash device,
            # reduce the write frequency of this swap partition
            swapctl -c -p 10000 "/dev/${swdev}"
        fi
    done
fi
#
# get total swap size in MB
#
swpmem=$( (swapctl -lk; echo 'end') | while read dev size rest
          do
              if [[ "$dev" = 'end' ]]; then
                  echo $((totsize/1024))
              elif [[ "$dev" = 'Device' ]]; then
                  :
              elif [[ "$dev" = 'Total' ]]; then
                  :
              else
                  totsize=$((totsize+size))
              fi
          done ) 2> /dev/null

#-------------------------------
# prompt for mfs/tmpfs size
#
memfstype=${memfstype:-mfs}  # unless global.conf loaded

while :; do
    echo "available memory: ${maxmem}M"
    [[ 0 -lt "$swpmem" ]] && echo "total swap size: ${swpmem}M"
    echo

    if [[ -n "$noask_umem" ]]; then  # non-interactive value specified
        umem="$noask_umem"
        echo "${memfstype} size -> $umem"
        unset noask_umem  # make unset for next loop

        umem=$(min "$mfs_max_mb" $(parsesize "$umem" $maxmem $swpmem))
    else  # manual setup
        echo -n "Enter ${memfstype} size"
        if [[ "$memfstype" = 'tmpfs' ]]; then
            defmem=0
            echo ' (0 is auto).'
        else
            defmem=$(min "$mfs_max_mb" $(parsesize '75%' $maxmem $swpmem))
            echo '.'
        fi

        echo '  You can add suffix K, M, or G.'
        echo '  % is a percentage of memory size.'
        echo '  and %% is a percentage of the total memory and swap.'
        echo '  otherwise considered "megabytes"'
        echo
        echo -n "[default: ${defmem}M] -> "; read umem
        
        if [[ -z "$umem" ]]; then
            umem="$defmem"
        fi

        umem=$(min "$mfs_max_mb" $(parsesize "$umem" $maxmem $swpmem))
    fi

    if [[ -n "$umem" ]]; then
        if [[ "$memfstype" = tmpfs && "$umem" -eq 0 ]]; then
            echo "set ${memfstype} size to auto"
        else
            echo "set ${memfstype} size to ${umem}MB"
        fi
        break;
    else
        echo "illegal input - try again"
    fi
done


#-------------------------------
# create and mount memory-based file system
#
if [[ "$memfstype" = 'tmpfs' ]]; then
    /fuguita/sbin/mount_tmpfs -s ${umem}M -o wxallowed tmpfs /ram || exit
else
    # mount_mfs exists on in-kernel FS
    # to be able to umount /fuguita at boot mode 2
    /boottmp/mount_mfs -s $((2*1024*umem)) -o wxallowed swap /ram || exit
fi

#-------------------------------
# generate fstab from current
# mounting status
#
echo "# generated automatically at boot time" > /boottmp/fstab
/sbin/mount | \
while read ln; do
    set - $ln
    case X"$3"X in
        X/X)
            echo /dev/rd0a / ffs rw 0 0 ;;
        X/fuguitaX|X/sysmediaX)
            echo $1 $3 $5 ro 0 0 ;;
        X/ramX)
            echo $memfstype $3 $5 rw,wxallowed 0 0 ;;
        *)
            echo $1 $3 $5 defaults 0 0 ;;
    esac
done >> /boottmp/fstab

#----------------------------
# re-link bin dirs to System device
#
/fuguita/bin/rm -rf /bin /sbin
/fuguita/bin/ln -sf fuguita/bin fuguita/sbin .

while :; do

    #----------------------------
    # detect select-mode failure loop
    #
    if [ "X$select_mode_tries" = X ]; then
        select_mode_tries=1
    else
        select_mode_tries=$(($select_mode_tries+1))
    fi

    if [ $select_mode_tries -ge 10 ]; then
        echo 'Too many boot retries.'
        echo -n 'emergency stop ->'; read dummy
        unset select_mode_tries
    fi

    #----------------------------
    # boot modes
    #
    echo
    echo 'Boot modes:'
    echo '   0: fresh boot - standard mode as a live system'
    echo '   1: fresh boot - less memory, faster boot'
    echo "                  (/usr is non-writable, can't pkg_add)"
    echo '   2: fresh boot - works using only RAM'
    echo '                  (about 1GB or more of RAM required)'
    echo '   3: boot with retrieving saved files from storage device'
    echo '      or enter passphrase for an encrypted volume'
    echo '   4: boot with retrieving saved files from floppy disk'
    echo '   5: interactive shell for maintenance'
    echo -n '-> '
    if [ X = X"$noask_setup_rw_mode" ]; then
        read setup_rw_mode
    else
        echo $noask_setup_rw_mode
        setup_rw_mode="$noask_setup_rw_mode"
        noask_setup_rw_mode=''
    fi

    case X"$setup_rw_mode" in

        #-----------------------
        #-----------------------
        # System Storage only mode
        #-----------------------
        #-----------------------
        #
        X[012])
        if [ X"$setup_rw_mode" = X0 ]; then
            echo "manual"
        elif [ X"$setup_rw_mode" = X1 ]; then
            echo "manual_less_ram"
        elif [ X"$setup_rw_mode" = X2 ]; then
            echo "manual_more_ram"
        fi > /boottmp/boot_mode

        #-------------------------------------
        # copy System Storage contents to rw-able file system
        #
        echo "Running manual setup."
        echo -n "Copying system files to /ram ... "
        cd /ram
        if [ X"$setup_rw_mode" = X0 ]; then
            (cd ../fuguita && tar cf - altroot etc home tmp root var) | tar xpf -
        elif [ X"$setup_rw_mode" = X1 ]; then
            (cd ../fuguita && tar cf - altroot etc home tmp root var) \
            | tar -x \
                  -p \
                  -f - \
                  -s '|^etc/X11/.*||' \
                  -s '|^var/db/pkg/.*||' \
                  -s '|^var/www/htdocs/.*||'
        elif [ X"$setup_rw_mode" = X2 ]; then
            (cd ../fuguita && pax -rwpe . /ram/. && cd /)
        fi
        echo "done"

        #-----------------------
        # symlink from / to ram
        #
        cd /
        rm -rf /tmp
        mv /etc /bootetc
        ln -sf ram/* . 2> /dev/null
        cp /boottmp/fstab /etc

        #-------------------------------------------
        # symlink rest of contents from / to System Storage
        #
        ln -s fuguita/* .     2> /dev/null
        #ln -s fuguita/.??* . 2> /dev/null ; # Maybe not needed


        # modify /etc/mtree/special
        #
        if [ -r /boottmp/mtree_special.mode${setup_rw_mode}.diff ]; then
            cat /boottmp/mtree_special.mode${setup_rw_mode}.diff | ( cd /etc/mtree && patch -s )
        fi

        if [ X"$setup_rw_mode" = X0 ]; then
            #-------------------------------------------
            # extract pre-build symlinks archive
            # or lndir from /ram/usr to /fuguita/usr
            #
            if [ -r /fuguita/etc/fuguita/mode0symlinks.cpio.gz \
                 -a ! -e /boottmp/force_lndir ]; then
                echo -n "Extracting symlinks from /ram to /fuguita ... "
                ( cd /ram \
                  && pax -rzpe -f /fuguita/etc/fuguita/mode0symlinks.cpio.gz \
                  && [ -r /etc/mtree/special ] \
                  && mtree -edtq -u -p / -f /etc/mtree/special > /dev/null )
            else
                echo -n "Linking files from /ram to /fuguita ... "
                mkshadowdir /fuguita/usr /ram/usr
            fi

            #-------------------------------------------
            # Replace symlinks to directories and files
            #
            for d in \
                usr/libexec/auth
            do
                if [ -d /fuguita/$d ]; then
                    rm -rf /ram/$d && cd $(dirname /fuguita/$d) && pax -rwpe $(basename $d) $(dirname /ram/$d)
                fi
            done

            #-------------------------------------------
            # Replace symlinks to ordinary files
            #
            for f in \
                usr/local/info/dir \
                usr/local/share/info/dir \
                usr/local/man/mandoc.db \
                usr/local/libdata/perl5/site_perl/OpenBSD/Quirks.pm \
                usr/local/libdata/perl5/site_perl/OpenBSD/Quirks/ghc.pm \
                usr/fuguita/man/mandoc.db \
                usr/fuguita/share/man/mandoc.db
            do
                if [ -f /fuguita/$f ]; then
                    rm -f /ram/$f && cp -p /fuguita/$f /ram/$f
                fi
            done
        
            #-------------------------------------------
            # Replace directories to symlinks
            #
            #      to                               from
            set -- /fuguita/usr/X11R6/lib/X11/fonts /ram/usr/X11R6/lib/X11/fonts \
                   /etc/X11/app-defaults            /ram/usr/local/lib/X11/app-defaults
        
            while [ -n "$1" -a -n "$2" ]
            do
                if [ -d "$1" -a -d "$2" ]; then
                    rm -r "$2"
                    ln -s "$1" "$2"
                fi
                shift 2
            done

            cd / && ln -sf ram/usr .
        elif [ X"$setup_rw_mode" = X1 ]; then
            mkshadowdir /fuguita/etc/X11        /ram/etc/X11
            mkshadowdir /fuguita/var/db/pkg     /ram/var/db/pkg
            mkshadowdir /fuguita/var/www/htdocs /ram/var/www/htdocs
        fi

        echo "done"

        #========================================
        # Configurations under /etc
        #========================================

        #---------------
        # keyboard type
        #
        if dmesg | grep -q '^.* at .*: console keyboard'; then
            while :; do

                # display list of kb encodings
                #     (note that sed don't handle \n in replace string)
                #
                echo `kbd -l` | sed -e 's/tables available for \([^ ][^ ]*\) keyboard: encoding /\
\
\1 keyboard:\
/g' | sed -e '1s/.*/\
Enter keyboard type./'

                echo -n 'keyboard type -> '; read kbtype
                if kbd $kbtype; then
                    echo $kbtype > /etc/kbdtype
                    break
                fi
            done
        fi

        #------------------------------
        # serial console (for vmm/vmd)
        #
        if dmesg | grep -q '^com0: console'; then
            ttyspeed=`stty speed`
            sed -i.orig \
                -e '/^console/s|[	 ]on| off|;
                    s|^tty00[ 	].*|tty00	"/usr/libexec/getty std.'${ttyspeed}'"	vt220	on  secure|' \
                /etc/ttys
        fi

        #------------------------------
        # put customized man.conf at mode 0
        #
        if [ X"$setup_rw_mode" = X0 ]; then
            cat <<EOT >/etc/man.conf
# comment out if the man directory is empty
#
manpath /fuguita/usr/share/man
manpath /fuguita/usr/X11R6/man
manpath /fuguita/usr/local/man
manpath /fuguita/usr/fuguita/man
manpath /fuguita/usr/fuguita/share/man
manpath /usr/local/man
manpath /usr/fuguita/man
manpath /usr/fuguita/share/man
EOT
        else
            rm -f /etc/man.conf
        fi

        #---------------
        # root password
        #
        echo
        until passwd root
          do
          echo "passwd failed, Try again."
        done

        #------------------------
        # create /etc/fuguita related stuffs
        #
        mkdir -p /etc/fuguita/netconfs/templ.{head,tail}  # may already be created
        cat > /etc/fuguita/netconfs/templ.head/sysctl.conf <<EOT
machdep.lidaction=0
net.inet.ip.forwarding=0
net.inet.ip.mforwarding=0
net.inet6.ip6.forwarding=0
net.inet6.ip6.mforwarding=0
EOT
        cat > /etc/fuguita/netconfs/templ.head/hosts <<EOT
127.0.0.1   localhost
::1         localhost
EOT
        # configure network
        #
        if /boottmp/gennetconfs -b -d 'default config at fresh boot' default; then
            /boottmp/chnetconf -f -d default
        fi

        #-----------------------
        # now disable to use prepared keys;
        #
        # To use this, uncomment following comment lines
        # then remove or comment 'genkeys=y' line
        #
        genkeys=y; # now force to generate keys

        case X"$genkeys" in
            X[Nn]*)
                :
            ;;
            *)
            rm -f /etc/soii.key /etc/ssh/*_key* /etc/isakmpd/local.pub /etc/isakmpd/private/local.key
            ;;
        esac

        # settings on xenodm activation
        #
        case `uname -m` in
            i386|amd64|arm64)
                echo
                echo 'Do you login with C)onsole or X) Window System?'
                echo -n '[default: C] -> '; read ans
                case "$ans" in
                    [Xx]*) echo 'xenodm_flags=' >> /etc/rc.conf.local
                    ;;
                esac
            ;;
        esac

        # modify OpenBSD's orignal /etc/{rc,login.conf}
        #
        (if cd /etc; then
             patch -s < /boottmp/etc.rc.diff
             patch -s < /boottmp/etc.login.conf.diff
         fi)

        # create misc stuffs
        #
        ln -sf /usr/share/zoneinfo/UTC /etc/localtime
        echo 'https://cdn.openbsd.org/pub/OpenBSD' > /etc/installurl
        echo '/usr/sbin/fw_update -v'              > /etc/rc.firsttime
        cat <<EOT > /etc/rc.shutdown
force_umount=No  # set Yes for forced umount /ram at shutdown
force_resync=No  # set Yes to re-sync at shutdown

# list of daemons
# both heading and trailing spaces needed for pattern match
#
skip_daemons=' mountd '  # skipped in stop_daemons()
kill_daemons=' mountd '  # -KILLed in kill_daemons()

# stop_daemons - to eliminate all daemons before usbfadm_r
#
stop_daemons () {
    echo -n 'stopping daemons:'
    for srv in \$(rcctl ls started); do
        if ! expr "\$skip_daemons" : ".* \$srv " >/dev/null ; then
            rcctl stop \$srv
        fi
    done
    echo "\ndone."
}

# kill_daemons - to eliminate all daemons at umount /ram
#
kill_daemons () {
    ulimit -c 0  # to avoid useless coredumps
    for srv in \$kill_daemons; do
        pkill -KILL \$srv
    done
}

# usbfadm_r - perform re-sync of the usbfadm utility
#
# This function calls usbfadm's sync function on shutdown to
# synchronize the contents of the USB stick with ${memfstype}.
# If usbfadm is incompletely configured, this function will invoke a
# sub-shell to prompt for configuration and saving by usbfadm.
# If re-synchronisation fails repeatedly, it will still launch a
# sub-shell for data preservation work, allowing the user to remove
# the cause of the error and perform usbfadm sync manually or by other
# means to preserve the data.
#
usbfadm_r () {
    ( # Invoking auto-save process in a subshell

      export PATH=\$PATH:/usr/local/bin:/usr/local/bin:/usr/fuguita/sbin:/usr/fuguita/bin

      # check if 'saveas' is set
      #
      if [[ -z \$(</boottmp/boot_user_config) ]] 2>/dev/null; then
          echo "= The 'saveas' of usbfadm utility is not set."
          echo "= Please do 'saveas' then 'sync' in the interactive mode of usbfadm."
          echo = invoking interactive shell for emergency...
          PS1="(emg) \$PS1" /bin/ksh -li
      fi

      # usbfadm with retry loop
      #
      retry=0
      retrymax=3
      waitsec=5
      ulimit -d unlimited  # prevent rsync from failing
      ulimit -m unlimited  # due to lack of memory
      while ! /usr/fuguita/sbin/usbfadm -r; do
          retry=\$((retry+1))
          if [ \$retry -ge \$retrymax ]; then
              echo = too many failures of usbfadm
              echo = invoking interactive shell for emergency
              PS1="(emg) \$PS1" /bin/ksh -li
              retry=0  # reset retry loop then do again...
          else
              echo usbfadm failed,
          fi
          echo will retry after \$waitsec seconds...
          sleep \$waitsec
      done )
}

[[ "\$force_umount" = [Yy][Ee][Ss] ]] && stop_daemons

# not to set default 'saveas' when archive deployed
# to avoid misoperation of usbfadm sync
if [[ \$(cat /boottmp/boot_mode) != usbflash_arc ]]; then
    [[ "\$force_resync" = [Yy][Ee][Ss] ]] && usbfadm_r
fi

kill_daemons
[[ "\$force_umount" = [Yy][Ee][Ss] ]] && /boottmp/umount -f /ram
EOT
        # motd
        #
        cat <<EOT > /etc/motd
OpenBSD ?.? (UNKNOWN)

Welcome to FuguIta, the OpenBSD-based live system.

FuguIta aims to help popularize OpenBSD operating system by making it easier
to get started with.

For information on FuguIta's specific features and how to use them, please
refer to the documentation on https://fuguita.org/.

If you have any questions or suggestions for FuguIta, please send an email to
me or post a message to fuguita.org's message board.
Please feel free to contact me.

Yoshihiro Kawamata
kaw@on.rim.or.jp , https://fuguita.org/

EOT

        #========================================
        # Configurations under misc dir
        #========================================
        #
        cat <<EOT | tee -a /root/.profile >> /etc/skel/.profile

PATH=\$PATH:/usr/fuguita/sbin:/usr/fuguita/bin
export PATH
EOT
        install -o root -g wheel -m 0600 /dev/null /root/.Xauthority
        install -o root -g wheel -m 0600 /dev/null /etc/skel/.Xauthority
        dd if=/dev/random of=/var/db/host.random bs=64k count=1 2>/dev/null
        chown root:wheel /var/db/host.random
        chmod 0600 /var/db/host.random

        break
        ;;

        #-----------------------
        #-----------------------
        # Restore from USB flash mode
        #-----------------------
        #-----------------------
        #
        X3)
        echo "usbflash" > /boottmp/boot_mode

        #-----------------------
        # Re-scan and build device list
        #
        scan_disks

        #-------------------------------
        # ask user for FuguIta's operating device
        #
        if [ -z "${part_sto}${part_enc}" ]; then
            echo "Warning: None of FuguIta's storage device(s) found."
            continue
        else
            # display concerning devices
            echo "Device(s) found:"
            if [ -n "${part_sto}" ]; then
                echo "  loadable from: ${part_sto}"
                set -- $part_sto
                if [ $# -eq 1 ]; then
                    def_sdev="$1"  # single device only ... set default
                else
                    unset def_sdev
                fi
            fi
            if [ -n "${part_enc}" ]; then
                echo "      encrypted: ${part_enc}"
            fi
        fi

        noask_confdev=`duid2dev $noask_confdev`
        if [ -z "$noask_confdev" ]; then
            # manual input
            #
            echo
            echo -n "Which is FuguIta's storage device? ${def_sdev:+[default: ${def_sdev}] }-> "
            read sdev

            if [ -z "$sdev" ]; then
                if [ -n "$def_sdev" ]; then
                    sdev="$def_sdev"
                else
                    continue  # not input / no default ... return to boot menu
                fi
            fi
        else
            # input from noasks
            #
            echo "Which is FuguIta's storage device? -> $noask_confdev"
            sdev="$noask_confdev"
            noask_confdev=''
        fi

        # Is crypto volume selected?
        #
        if [ 0 -lt `expr " ${part_enc} " : ".* $sdev "` ]; then
            if bioctl -c C -l /dev/$sdev softraid0; then
                sleep 1  # wait for kernel messages printed
                echo "Passphrase successful: Select boot mode again..."
                sleep 1
            fi
            continue  # return to boot mode menu
        elif [ 0 -eq `expr " ${part_sto} " : ".* $sdev "` ]; then
            echo "$sdev is not loadable"
            continue  # return to boot mode menu
        fi

        usb_devname=/dev/${sdev}
        echo "$usb_devname" > /boottmp/boot_restore_devname

        #-----------------------
        # mount user's storage
        #
        usb_devname=`cat /boottmp/boot_restore_devname`
        if mount -r "$usb_devname" /mnt; then
            #-----------------------
            # select config files
            #
            if [ ! -d /mnt/livecd-config ]; then
                echo "cannot find config dir on $usb_devname"
                umount "$usb_devname"
                continue
            fi

            while :; do
                echo "$usb_devname : available data;"
                (if cd /mnt/livecd-config; then
                     cd $osrel/$osmac 2> /dev/null
                     echo
                     echo $(ls | /boottmp/sed -e '/^noasks$/d')  # print except noasks
                     echo
                 fi)
                echo -n 'config name -> '
                if [ X = X"$noask_confdata" ]; then
                    read confdata
                else
                    echo $noask_confdata
                    confdata="$noask_confdata"
                    noask_confdata=''
                fi

                if [ X"$confdata" = X ]; then
                    echo 'conf dir not specified'
                    umount "$usb_devname"
                    continue 2
                elif [ -d /mnt/livecd-config/$osrel/$osmac/$confdata -o \
                       -f /mnt/livecd-config/$osrel/$osmac/$confdata -o \
                       -d /mnt/livecd-config/$confdata ]; then
                    echo "$confdata" > /boottmp/boot_user_config
                    break
                else
                    echo 'cannot find such data'
                    umount "$usb_devname"
                    continue 2
                fi
            done

            #-----------------------
            # copying to ram
            #
            echo "Copying files from persistent storage to ram ... "

            # an archive file
            if [ -f /mnt/livecd-config/$osrel/$osmac/$confdata ]; then
                echo "usbflash_arc" > /boottmp/boot_mode  # overwrite "usbflash"
                if cd /ram; then
                    # locate crunched binary gzip to temporary /usr/bin
                    # because pax has fixed command search PATH in it.
		    # gzip must be included in PATH
                    mkdir -p /usr/bin
                    ln -s /boottmp/gzip /usr/bin

                    if ! pax -rzpe < /mnt/livecd-config/$osrel/$osmac/$confdata; then
                        # tmpfs bug workaround
                        # will retry later
                        pax_arc_failed="yes"
                    fi

                    # cleanup temporary /usr/bin/gzip
                    rm -rf /usr
                fi

            # synced dir tree
            elif cd /mnt/livecd-config/$osrel/$osmac/$confdata 2> /dev/null || \
               cd /mnt/livecd-config/$confdata; then
                if ! pax -rwpe . /ram; then
                    # tmpfs bug workaround
                    # will retry later
                    pax_failed="yes"
                fi
            fi
            echo "done"

            #-----------------------
            # setup operational file/dir tree
            #
            cd /
            rm -rf /tmp
            mv /etc /bootetc
            ln -sf ram/* . 2> /dev/null    # connect /ram dirs to /
            ln -s fuguita/* . 2> /dev/null # connect rest of dirs in System Storage to /
            #
            # tmpfs bug work around
            # retry copying to ram again
            #
            if [ "$pax_failed" = "yes" ]; then
                if cd /mnt/livecd-config/$osrel/$osmac/$confdata 2> /dev/null || \
                   cd /mnt/livecd-config/$confdata; then
                    for i in 1 2 3; do  # retry 3 time max
                        echo "Copying to ram was partially failed, retrying..."
                        if PATH=$PATH:/fuguita/usr/local/bin:/fuguita/usr/fuguita/bin \
                           rsync -rlptgovHS . /ram/.; then
                            echo "done"
                            break
                        fi
                    done
                fi
            fi
            cd /
            umount /mnt

            cp /boottmp/fstab /etc  # fix /etc/fstab
        else
            echo "Failed to mount user's storage"
            continue
        fi

        #-------------------------------------------
        # merge user-defined fstab entries
        # into auto generated /etc/fstab
        #
        fstab_tail="/etc/fuguita/fstab.tail"
        fstab_merged="# followings are merged from $fstab_tail"

        if ! fgrep -q "$fstab_merged" /etc/fstab; then
            if [ -r $fstab_tail ]; then
                echo $fstab_merged >> /etc/fstab
                cat $fstab_tail >> /etc/fstab
            fi
        fi

        break
        ;;

        #-----------------------
        #-----------------------
        # Restore from floppy mode
        #-----------------------
        #-----------------------
        #
        X4)
        echo "floppy" > /boottmp/boot_mode

        #-----------------------
        # copying to ram
        #
        if mount -r /dev/fd0a /mnt; then
            if [ -r /mnt/livecd-retr.sh.inc ]; then
                cp -p /boottmp/livecd-retr.sh.inc /boottmp/livecd-retr.sh.inc.orig
                cat /mnt/livecd-retr.sh.inc > /boottmp/livecd-retr.sh.inc
                .  /boottmp/livecd-retr.sh.inc
                umount /mnt
            else
                echo "Retrieval script not found on fd0a."
                umount /mnt
                continue
            fi
        else
            echo "Failed to read /mnt/livecd-config.tar.gz on /dev/fd0a"
            continue
        fi

        break
        ;;

        #-----------------------
        #-----------------------
        # Interactive shell mode
        #-----------------------
        #-----------------------
        #
        X5)
        echo "intr-shell" > /boottmp/boot_mode
        echo "==INTERACTIVE SHELL MODE================
=
= An interactive shell invoked for manual operation.
= Now, just System Storage mounted on /fuguita.
=
= After exit this shell, select boot mode again.
=
========================================"
        PATH="/fuguita/sbin:/fuguita/bin" /fuguita/bin/sh
        ;;

        *) echo "What?" ;;
    esac
done

#====================
# remove unused directories / files
#
rm -f /boot.catalog /cdboot /cdbr /rr_moved
rmdir /sysmedia-iso 2> /dev/null


#-------------------------------------------
# if the origin boot mode is 2:
#  - unmount operating devices
#  - deactivate swap partitions
#
if [ -d /ram/usr -a ! -L /ram/usr/fuguita/version ]; then

    # umount sysmedia - the device containing file tree
    #
    umount /fuguita
    vnconfig -u ${vn_devname}
    umount /sysmedia

    # umount ISO image file if mounted
    #
    if mount | grep -q "/sysmedia-iso"; then
        vnconfig -u ${vn_devname_iso}
        umount /sysmedia-iso
    fi

    # modify /etc/fstab
    #
    egrep -v ' /(sysmedia|sysmedia-iso|fuguita) ' /etc/fstab > /etc/fstab.tmp
    mv /etc/fstab.tmp /etc/fstab

    # deactivate swap partitions if any
    #
    swapctl -l \
    | awk '/^\/dev\// && $3 == 0 {
              printf("deactivating swap partition: %s ", $1)
              system("swapctl -d " $1)
              printf("\n") }'

    # delete encrypted volume if any
    #
    bioctl softraid0 \
    | awk '/^softraid0 .* sd[0-9]/ {
              printf("delete encrypted volume: %s ", $5)
              system("bioctl -d " $5)
              printf("\n") }'

    # check and report
    #   - umount all fs except RAM fs
    #   - all swap partitions deactivated
    #   - delete encrypted volumes
    #
    echo 'on-memory operation:'
    if ! mount | egrep -v ' on (/ |/ram )' | grep -q '.' && \
            swapctl -l 2>&1 | grep -q 'no swap devices configured'; then
        # mount & swap purged
        if [ -z "`bioctl softraid0`" ]; then
            # no encrypted volumes reside
            echo '    You can remove all storage device(s).'
        else
            echo "    encrypted volume not deleted yet."
            sleep 5
        fi
        
    else
        echo "    ${memfstype} still paged out ... You can't remove any storage device(s)."
        sleep 5
    fi
fi

echo "            _________________________________________________
           /      Setup for FuguIta ends.         /
          / OpenBSD's boot sequence will follow. /
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
date > /boottmp/boot_livecd_rc_ends

#========================================
# chain original /etc/rc
#

exec /bin/ksh /etc/rc "$init_args"
