#!/bin/bash
###################################################################################
# File.......: /usr/lib/setup/armedslack-SeTpartitions
# Called from: /usr/lib/setup/SeTpartitions
# Purpose....: Detect a Slackware ARM/AArch64 bootable SD card and append it to
#              the /etc/fstab of the new installation.
#              Mount this SD card under /mnt/boot (/mnt being the location that
#              the Slackware installer mounts the new OS's root filesystem).
#              Updates the U-Boot configuration.
#
#              This is to support the boot process where we ship SD card images
#              that provide a bootable U-Boot header and an ext4 file system containing
#              the U-Boot configuration, Linux Kernel and Slackware installer and OS
#              initial RAM disks ('initrd').
# Version....: 1.00
# Date.......: 08-Apr-2021
# Author.....: Stuart Winter <mozes@slackware.com>
###################################################################################
#
# Todo
# * Detect whether it's possible to resize /boot before offering.
###################################################################################
#
# Copyright 2021  Stuart Winter, Donostia, Spain.
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 AUTHOR 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.

# Config files:
ARMEDSLACK_EXTLINUXCONF=extlinux/extlinux.conf
# Experimentation with INCLUDE
#ARMEDSLACKOS_EXTLINUXCONF=extlinux/slkos

###################################################################################
################### Functions #####################################################
###################################################################################

# Ensure that the device has a single partition, which we will assume means the user
# wrote the image directly to the SD card and made no modifications.
# Takes full device name as input - e.g. /dev/mmcblk1p1
function sanitycheckbootpart() {
   local dev=${1%%p*} # lop off the partition number
   local devbase=${dev#/dev/} # lop off /dev/
   # If 1 partition found, we're good.
   [ $( grep -c "${devbase}p[0-9]" /proc/partitions 2> /dev/null ) -eq 1 ] && return 0
   # Else we're not:
   return 1
}

function offerresizebootsuccess() {
   dialog \
      --backtitle "Slackware ARM / AArch64 installer" \
      --title "RESIZE /boot PARTITION ON SD CARD" --ok-button "OK" \
      --msgbox "\n\nResizing was successful.\n" 9 60
   clear
}

function offerresizebootfail() {
   dialog \
      --backtitle "Slackware ARM / AArch64 installer" \
      --title "RESIZE /boot PARTITION ON SD CARD" --ok-button "OK" \
      --msgbox '\nResizing failed!\n\n
The installation of Slackware cannot continue.
\n\nYou must investigate manually.\n
\nOne option may be to re-write the Installer image to the SD card again and
reboot the installer.\n' 14 79
   clear
}

# Offer the user the option of resizing /boot:
function offerresizebootpart() {
   dialog \
      --backtitle "Slackware ARM / AArch64 installer" \
      --title "RESIZE /boot PARTITION ON SD CARD" --yesno \
"\nBy default Slackware AArch64 supplies the Slackware Installer image that presently
occupies a 1GB partition on the SD card within this machine.\n\n
This SD card will be transformed into the Operating System's /boot partition
as part of the installation process.\n
\n
It is recommended that this SD card is used for nothing more than /boot, however this
is not mandatory, and some users may prefer to create additional partitions subsequently (post installation).
\n
\nDo you want to resize the /boot partition to fill all available space? (recommendation is 'Yes')\n \

\n" 17 77
  return $?
}

# Resize /boot:
# Take full device name including partition number as input.
# e.g. /dev/mmcblk1p1
function resizebootpart(){
   local dev=${1%%p*} # lop off the partition number
   local devpart=${1}

   # Cause the Kernel to become aware of the new size.
   # Unnecessary but I'll keep it in case:
   # echo 1 > /sys/block/mmcblk1/device/rescan
   # [ "${mmcdev:(-2)}" = "p1" ] && echo y

   # Grow the partition to fill all available space:
   echo "EXISTING SIZE: $( /sbin/fdisk -l ${devpart} | grep "Disk ${devpart}" )"
   echo "OPERATION: Growing partition ${devpart}"
   /sbin/e2fsck -yf ${devpart}
   /usr/sbin/parted -s -a opt ${dev} "resizepart 1 100%"
   estat=$?
   if [ $estat -gt 0 ]; then
      read -p "An error occurred.  Press ENTER to continue"
      return $estat
   fi

   # Resize the ext4 filesystem for /boot on partition 1:
   echo "OPERATION: Resizing ${devpart}"
   /sbin/e2fsck -yf ${devpart}
   /sbin/resize2fs ${devpart}
   estat=$?
   if [ $estat -gt 0 ]; then
      read -p "An error occurred.  Press ENTER to continue"
      return $estat
   fi
   echo "NEW SIZE: $( /sbin/fdisk -l ${devpart} | grep "Disk ${devpart}" )"

   # Wait a moment to see the output:
   sleep 6
   return 0
}

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

# Scan the MMC block devices for the filesystem label 'SLKboot:'
# If there is >1, we'll pick the last.
for mmcdev in /dev/mmcblk* ; do
   { ( /sbin/e2label ${mmcdev} 2>/dev/null | grep -Eq '^SLKboot:a' ) && ARMEDSLACK_MMCBOOTPART=${mmcdev} ;}
done

# If a Slackware ARM Installer partition was found, we offer the user the option to
# grow it, then proceed to configure the boot loader.
if [ ! -z "${ARMEDSLACK_MMCBOOTPART}" ]; then

   # By default Slackware AArch64's installer image contains a 1GB single partition.
   # Offer to resize it if seems like the 'stock' image, and handle failures.
   sanitycheckbootpart ${ARMEDSLACK_MMCBOOTPART} && {
      offerresizebootpart && {
         # There's no possibility to retry here.
         resizebootpart ${ARMEDSLACK_MMCBOOTPART}
         estat=$?
         if [ $estat -gt 0 ]; then
           offerresizebootfail ; exit 1
          else
           offerresizebootsuccess
         fi
       }
   }

cat << EOF >> ${TMP}/SeTnative
# This is the SD card that contains a bootable U-Boot header, and an ext4 file system containing the
# Linux Kernel and Slackware initial RAM disk for the OS.
$( printf "%-16s %-11s %-11s %-16s %-3s %s\n" LABEL=SLKboot:aarch64 /boot ext4 errors=remount-ro 0 1 )
EOF

   clear
   echo "Detected Slackware ARM bootable SD card: ${ARMEDSLACK_MMCBOOTPART}"
   echo "Attempting to mount ..." # to ${T_PX}/boot"
   # Mount it:
   mkdir -pm755 ${T_PX}/boot
   mount -v ${ARMEDSLACK_MMCBOOTPART} ${T_PX}/boot
   if [ $? -gt 0 ]; then
      # Perhaps turn this into a dialog? not that it helps ;-)
      echo "ERROR: Unable to mount.  This will cause a boot failure."
      echo "       You need to fix this."
      # Abort the installation:
      exit 1
    else
      echo "Configuring U-Boot (${T_PX}/boot/extlinux/extlinux.conf)"
      # If the reached the end of the installer, elected not to erase the
      # installer, and rebooted into the installer to start over, we'll
      # have two copies of the OS boot config.  Let's handle that:
      # There should be two markers, but we'll remove the stanza if there's >0
      if [ $( grep -c '^##SLKOS' ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF} 2>/dev/null ) -gt 0 ]; then
         echo "...removing existing OS boot stanza (probably from a previous failed installation)"
         sed -i '/^##SLKOS/,/^##SLKOS/d' ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}
      fi
      # Add the Slackware OS boot configuration to extlinux.conf:
      # This was an experiment using the 'INCLUDE' feature, but I found it buggy
      # specifically that it included a single menu entry twice.
      #echo 'INCLUDE slkos' >> ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}
      # Set the device that contains the root filesystem, and its filesystem type:
      #sed -i 's?%ROOTDEV%?'"${ROOT_DEVICE}"'?g' ${T_PX}/boot/${ARMEDSLACKOS_EXTLINUXCONF}
      #sed -i 's?%ROOTFSTYPE%?'"${ROOT_SYS_TYPE}"'?g' ${T_PX}/boot/${ARMEDSLACKOS_EXTLINUXCONF}
      # If the user wants to enable the await root device feature, they can
      # set a flag from the shell ( $ touch /.enableawaitrootdev ) and we'll add it:
      if [ -f /.enableawaitrootdev ]; then
         echo "...enabling awaitrootdev OS InitRD feature"
         sed -e 's?APPEND ?APPEND awaitrootdev ?g' ${T_PX}/boot/extlinux/slkos.sample >> ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}
       else
         # Add the default OS boot stanza:
         cat ${T_PX}/boot/extlinux/slkos.sample >> ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}
      fi
      # This remains, otherwise if you reboot into the installer again from this
      # SD image, this file won't exist and the machine won't configure U-Boot for
      # booting the OS.
      #rm -f ${T_PX}/boot/extlinux/slkos.sample

      # This assumes a single OS installation:
      echo "...setting root filesystem"
      sed -i 's?%ROOTDEV%?'"${ROOT_DEVICE}"'?g' ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}
      sed -i 's?%ROOTFSTYPE%?'"${ROOT_SYS_TYPE}"'?g' ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}
      # We ship the SD cards with the default boot option as
      # the installer.  Let's switch it to the OS:
      echo "...setting the default boot option to Slackware OS"
      sed -i 's?^DEFAULT Installer?DEFAULT OS?g' ${T_PX}/boot/${ARMEDSLACK_EXTLINUXCONF}

      # As we're in this code path, it means we're on a Slackware AArch64 standard
      # installation, and we know that the installer is within /boot.
      # As the installer has a large footprint and is of limited utility once
      # the installation is complete, we'll suggest to the user to remove it from /boot.
      # We're going to make use of the post-installation package configuration system
      # (that you see when configuring networking/gpm, etc.).
      # Ordinarily these scripts remain on the OS within /var/lib/pkgtools/setup but
      # since this shouldn't be run outside of the installer, we clean it up from
      # within /usr/lib/setup/SeTconfig
      mkdir -pm755 ${T_PX}/var/lib/pkgtools/setup
      ln -fs /usr/lib/setup/armedslack-removeinstaller ${T_PX}/var/lib/pkgtools/setup/setup.armedslack-tmp-removeinstaller
      ln -fs /usr/lib/setup/armedslack-bootloader-flash ${T_PX}/var/lib/pkgtools/setup/setup.armedslack-tmp-bootloader-flash
   fi
fi

# Wait a few seconds, otherwise the user sees some text flash on the screen
# momentarily which may cause concern, as often that's what happens to
# error messages.
sleep 4
clear
