#! /bin/sh -
#
# Boot-time system initialization script
#
# Copyright (c) 2017-2019 Matias Fonzo, <selk@dragora.org>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

umask 022
IFS='
 	'
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin

# Mount virtual file systems

echo "(Startup): Mounting kernel based file systems"
mount -v -n -o nosuid,noexec,nodev -t proc proc /proc
mount -v -n -o nosuid,noexec,nodev -t sysfs sysfs /sys
if ! mountpoint -q /dev
then
    mount -v -n -t devtmpfs devtmpfs /dev
else
    # Re-mount devtmpfs if necessary due to an initramfs
    mount -v -n -o remount -t devtmpfs devtmpfs /dev
fi

mkdir -p /dev/pts /dev/shm /run
mount -v -n -o mode=0620,gid=5 -t devpts devpts /dev/pts
mount -v -n -o defaults -t tmpfs none /dev/shm
mount -v -n -o defaults -t tmpfs tmpfs /run

# Start the dynamic device management

echo "(Startup) Starting event managing daemon"
udevd --daemon

# Request device uevents to replay events at system coldplug
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices    --action=add

echo "Waiting for event queue"
udevadm settle

# Re-mount the root filesystem in *read-only mode*, if needed
if test -w /
then
    echo "(Startup) Remounting root filesystem in read-only mode"
    mount -v -n -o remount,ro /
fi

# Mount Control Groups (v1)

if grep -q cgroup /proc/filesystems
then
    if test -d /sys/fs/cgroup
    then
        # Cgroup controllers v1 must be mounted against a tmpfs(5)
        mount -v -n -t tmpfs cgroup_root /sys/fs/cgroup

        # Comount all v1 controllers against the same hierarchy
        mount -v -n -t cgroup cgroup /sys/fs/cgroup
    fi
fi

# Initialize the Logical Volume Manager version 2

if type lvm > /dev/null 2>&1
then
    echo "(LVM2) Scanning for new volume groups ..."
    modprobe -q dm-mod
    vgscan --mknodes --ignorelockingfailure 2> /dev/null && \
     vgchange --ignorelockingfailure -a y
fi

# Activate swap partition if any available
swapon -a

# Set system clock (1/2)

# Avoid unnecessary fsck runs at boot time, especially for
# already existing (multiple) systems not designed for UTC
hwclock --hctosys --localtime

# Perform file system checks

if test ! -f /fastboot
then
    # Limit number of filesystem checkers using the max. number of processors
    FSCK_MAX_INST=$(nproc 2> /dev/null) || FSCK_MAX_INST=1

    # Force checks if the regular file '/forcefsck' exists
    test -f /forcefsck && forcefsck_flag=-f

    echo "*** Checking root file system ..."
    fsck $forcefsck_flag -a -C
    status=$?

    if test $status -gt 1
    then
        if test $status -eq 32
        then
            echo "fsck(8) canceled by user request." 1>&2
        else
            if test $status -ge 4
            then
                echo "EXIT CODE = $status"                        1>&2
                echo ""                                           1>&2
                echo "A maintenance shell will be started ..."    1>&2
                echo "Refer to the file system-specific utility"  1>&2
                echo "and manual pages for correction."           1>&2
                if type sulogin > /dev/null
                then
                    sulogin
                else
                    echo "Executing \`/bin/sh' as emergency shell ..."
                    /bin/sh -
                fi
            fi
            echo "The system will be restarted now."
            umount -v -n -a -r
            mount -v -n -o remount,ro /
            reboot -n -f;
            exit 99
        fi
    fi
    unset status

    echo "*** Checking local file system(s) ..."
    fsck $forcefsck_flag -A -C -R -T -a

    unset FSCK_MAX_INST forcefsck_flag
else
    echo "WARNING: /fastboot is present: Dodging checks" 1>&2
fi

# Parse config file.
#
# Values given on /proc/cmdline have priority over
# those present at "/etc/rc.conf"

if grep -q -m 1 RC_ /proc/cmdline
then
    tr -s '[:space:]' '[\n*]' < /proc/cmdline | \
     while IFS='=' read -r variable value
     do
         case $variable in
         RC_?*)
             # Set variable value avoiding possible code execution
             eval "$variable=\${value}"
             ;;
         esac
     done
fi
if test -f /etc/rc.conf
then
    while IFS='=' read -r variable value
    do
        case $variable in
        RC_?*)
            if test -z "$variable"
            then
                eval "$variable=\${value}"
            fi
            ;;
        esac
    done < /etc/rc.conf
fi

# Use default values if variables are not defined
RC_HWCLOCK="${RC_HWCLOCK:-utc}"
RC_HOSTNAME="${RC_HOSTNAME:-dragora}"
RC_DOMAINNAME="${RC_DOMAINNAME:-example.net}"
RC_ESPEAKUP="${RC_ESPEAKUP:-0}"
RC_EVOICE="${RC_EVOICE:-default}"
RC_KEYMAP="${RC_KEYMAP:-qwerty/us}"
RC_BLANKTIME="${RC_BLANKTIME:-15}"

# Set system clock (2/2)

if test "$RC_HWCLOCK" = utc
then
    echo "(Startup) Setting system time from the hardware clock to UTC"
    hwclock --hctosys --utc
else
    echo "(Startup) The system time was already set to local time" 1>&2
fi
unset RC_HWCLOCK

# Re-mount the root filesystem in *read-write mode*
echo "(Startup) Remounting root filesystem in read-write mode:"
if ! test -w /
then
    mount -v -n -o remount,rw /
else
    echo "    The root filesystem is already in read-write mode." 1>&2
fi

# In modern distributions /etc/mtab is a symbolic link to /proc/mounts
rm -f /etc/mtab
ln -sf /proc/mounts /etc/mtab

echo "(Startup) Mounting local file systems [only]"
mount -a -t no,proc,sysfs,devtmpfs,shm,devpts,usbfs,cifs,smbfs,nfs

# Activate swap partitions or swap files

echo "(Startup) Activating swap devices, if any"
swapon -v -a

# Update kernel modules

if test -s "/lib/modules/$(uname -r)/modules.dep"
then
    echo "(Startup) Refreshing kernel module list: depmod --quick"
    depmod --quick
else
    echo "(Startup) Generating kernel module dependency list: depmod --all"
    depmod --all
fi

# Re-create hierarchy for temporary files (if needed)

mkdir -p -m 1777 -- /tmp /tmp/.font-unix /tmp/.ICE-unix /tmp/.X11-unix
chmod 1777 -- /tmp /tmp/.font-unix /tmp/.ICE-unix /tmp/.X11-unix

# Seek and destroy temporary files

rm -f /etc/nologin /fastboot /forcefsck
find /var/lock /var/run \( ! -type d -a ! -name utmp \) -delete

# Set kernel parameters at runtime

echo "(Startup) Setting kernel parameters: sysctl -q --system"
sysctl -q --system

# Set host name and domain name for the system,
# overrides any value given in sysctl(8)

echo "$RC_HOSTNAME"    > /proc/sys/kernel/hostname
echo "$RC_DOMAINNAME"  > /proc/sys/kernel/domainname

unset RC_HOSTNAME RC_DOMAINNAME

# Start the loopback device

echo "(Startup) Starting loopback device"

if type ip > /dev/null 2>&1
then
    ip addr del 127.0.0.1/8 dev lo 2> /dev/null
    ip addr add 127.0.0.1/8 dev lo brd + scope host
    ip link set lo up
elif type ifconfig > /dev/null 2>&1
then
    ifconfig lo up > /dev/null
else
    echo "WARNING: Could not find ip(8) or ifconfig(1)" 1>&2
fi

# Initialize the random number generator, see random(4)

echo "(Startup) Initializing random number generator"
echo "    /etc/random-seed <-> /dev/urandom ..."

if test -s /etc/random-seed
then
    cat /etc/random-seed > /dev/urandom
fi

# Read pool size from /proc or assign a default value
read -r < /proc/sys/kernel/random/poolsize size || size=512

# Save seed file containing the whole entropy pool
dd if=/dev/urandom of=/etc/random-seed count=1 bs=${size} 2> /dev/null
unset size ; chmod 600 -- /etc/random-seed

# Configure ISA Plug-and-Play devices

if type isapnp > /dev/null 2>&1 && type pnpdump > /dev/null 2>&1
then
    if test -e /etc/isapnp.conf
    then
        echo "(Startup) Setting ISA PnP devices using /etc/isapnp.conf"
        isapnp /etc/isapnp.conf
    else
        echo "(Startup) Creating resource information for ISA PnP devices"
        pnpdump > /etc/isapnp.conf

        echo "(Startup) Setting devices from the new /etc/isapnp.conf"
        isapnp /etc/isapnp.conf
    fi
fi

# Start sound or speech engine

if test -x /etc/rc.d/rc.alsa
then
    /etc/rc.d/rc.alsa start
fi

if test "$RC_ESPEAKUP" != 0
then
    echo "(Startup) Activating software synthesizer: espeakup -V $RC_EVOICE"
    modprobe -q speakup_soft
    espeakup -V $RC_EVOICE
fi
unset RC_ESPEAKUP RC_EVOICE

# Load keyboard map

echo "Loading keyboard map: loadkeys $RC_KEYMAP"
loadkeys $RC_KEYMAP
unset RC_KEYMAP

# Set terminal attributes

echo "Setting screen blanking interval: setterm -blank $RC_BLANKTIME"
setterm -blank "$RC_BLANKTIME"
unset RC_BLANKTIME

