summaryrefslogtreecommitdiffstats
path: root/upslak.sh
diff options
context:
space:
mode:
author Eric Hameleers <alien@slackware.com>2017-09-19 20:51:34 +0200
committer Eric Hameleers <alien@slackware.com>2017-09-19 20:51:34 +0200
commit888d2a08730e0dc7343696945769e4ab4f8b4659 (patch)
tree9cc3c4f675ac461fb43870d8981e14836faf5c3e /upslak.sh
parent0ddc28312087bd711b49240361177309ed3641e7 (diff)
downloadliveslak-888d2a08730e0dc7343696945769e4ab4f8b4659.tar.gz
liveslak-888d2a08730e0dc7343696945769e4ab4f8b4659.tar.xz
Add upslak.sh, a script to tweak the Live USB stick.
Purpose: to update the content of a Slackware Live USB stick. upslak.sh accepts the following parameters: -b|--nobackup Do not try to backup original kernel and modules. -d|--devices List removable devices on this computer. -h|--help This help. -i|--init <filename> Replacement init script. -k|--kernel <filename> The kernel file (or package). -m|--kmoddir <name> The kernel modules directory (or package). -n|--netsupport Add network boot support if not yet present. -o|--outdev <filename> The device name of your USB drive. -p|--persistence Move persistent data into new Live module. -r|--restore Restore previous kernel and modules. -s|--scan Scan for insertion of new USB device instead of providing a devicename (using option '-o'). -v|--verbose Show verbose messages. -w|--wait<number> Add <number> seconds wait time to initialize USB.
Diffstat (limited to 'upslak.sh')
-rw-r--r--upslak.sh923
1 files changed, 923 insertions, 0 deletions
diff --git a/upslak.sh b/upslak.sh
new file mode 100644
index 0000000..67c64ed
--- /dev/null
+++ b/upslak.sh
@@ -0,0 +1,923 @@
+#!/bin/bash
+#
+# Copyright 2017 Eric Hameleers, Eindhoven, NL
+# 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.
+
+# -----------------------------------------------------------------------------
+#
+# This script can perform the following changes on
+# the USB version of on Slackware Live Edition.
+# - upgrade the kernel and modules
+# - add network support modules for PXE boot (if missing)
+# - increase (or decrease) USB wait time during boot
+# - replace the Live init script inside the initrd image
+# - move current persistence data to a new squashfs module in 'addons'
+#
+# -----------------------------------------------------------------------------
+
+# Be careful:
+set -e
+
+# Limit the search path:
+export PATH="/usr/sbin:/sbin:/usr/bin:/bin"
+
+# ---------------------------------------------------------------------------
+# START possible tasks to be executed by the script:
+# ---------------------------------------------------------------------------
+
+# By default do not move persistence data into a new Live module:
+CHANGES2SXZ=0
+
+# Replace the live 'init' script with the file $LIVEINIT:
+LIVEINIT=""
+
+# Do we need to add network support? This can be enforced through commandline,
+# otherwise will be determined by examining the original kernelmodules:
+NETSUPPORT=""
+
+# This will be set to '1' if the user wants to restore the backups of the
+# previous kernel and modules:
+RESTORE=0
+
+# Set default for 'do we update the kernel':
+UPKERNEL=0
+
+# Do not change usb wait time by default:
+WAIT=-1
+
+# ---------------------------------------------------------------------------
+# END possible tasks to be executed by the script:
+# ---------------------------------------------------------------------------
+
+# Determine whether the USB stick has a supported kernel configuration
+# i.e. one active and optionally one backup kernel plus mmodules:
+SUPPORTED=1
+
+# Values obtained from the init script on the USB:
+DISTRO=""
+LIVE_HOSTNAME=""
+LIVEMAIN=""
+LIVEUID=""
+MARKER=""
+MEDIALABEL=""
+PERSISTENCE=""
+VERSION=""
+
+# By default we make a backup of your old kernel/modules when adding new ones:
+KBACKUP=1
+
+# Does the initrd contain an old kernel that we can restore?
+# The 'read_initrd' routing may set this to '0':
+KRESTORE=1
+
+# Timeout when scanning for inserted USB device, 30 seconds by default,
+# but this default can be changed from outside the script:
+SCANWAIT=${SCANWAIT:-30}
+
+# By default do not show file operations in detail:
+VERBOSE=0
+
+# Set to '1' if we are to scan for device insertion:
+SCAN=0
+
+# Minimim free space (in MB) we want to have left in any partition
+# after we are done.
+# The default value can be changed from the environment:
+MINFREE=${MINFREE:-10}
+
+# Variables to store content from an initrd we are going to refresh:
+OLDKERNELSIZE=""
+OLDKMODDIRSIZE=""
+OLDKVER=""
+OLDWAIT=""
+
+# Record the version of the new kernel:
+KVER=""
+
+# Define ahead of time, so that cleanup knows about them:
+IMGDIR=""
+KERDIR=""
+USBMNT=""
+EFIMNT=""
+
+# These tools are required by the script, we will check for their existence:
+REQTOOLS="cpio gdisk inotifywait strings xz"
+
+# Compressor used on the initrd ("gzip" or "xz --check=crc32");
+# Note that the kernel's XZ decompressor does not understand CRC64:
+COMPR="xz --check=crc32"
+
+# -- START: Taken verbatim from make_slackware_live.sh -- #
+# List of kernel modules required for a live medium to boot properly;
+# Lots of HID modules added to support keyboard input for LUKS password entry:
+KMODS=${KMODS:-"squashfs:overlay:loop:xhci-pci:ohci-pci:ehci-pci:xhci-hcd:uhci-hcd:ehci-hcd:mmc-core:mmc-block:sdhci:sdhci-pci:sdhci-acpi:usb-storage:hid:usbhid:i2c-hid:hid-generic:hid-apple:hid-cherry:hid-logitech:hid-logitech-dj:hid-logitech-hidpp:hid-lenovo:hid-microsoft:hid_multitouch:jbd:mbcache:ext3:ext4:isofs:fat:nls_cp437:nls_iso8859-1:msdos:vfat:ntfs"}
+
+# Network kernel modules to include for NFS root support:
+NETMODS="kernel/drivers/net"
+
+# Network kernel modules to exclude from above list:
+NETEXCL="appletalk arcnet bonding can dummy.ko hamradio hippi ifb.ko irda macvlan.ko macvtap.ko pcmcia sb1000.ko team tokenring tun.ko usb veth.ko wan wimax wireless xen-netback.ko"
+# -- END: Taken verbatim from make_slackware_live.sh -- #
+
+#
+# -- function definitions --
+#
+
+# Clean up in case of failure:
+cleanup() {
+ # Clean up by unmounting our loopmounts, deleting tempfiles:
+ echo "--- Cleaning up the staging area..."
+ # During cleanup, do not abort due to non-zero exit code:
+ set +e
+ sync
+ # No longer needed:
+ [ -n "${IMGDIR}" ] && ( rm -rf $IMGDIR )
+ [ -n "${KERDIR}" ] && ( rm -rf $KERDIR )
+ if [ -n "${USBMNT}" ]; then
+ if mount |grep -qw ${USBMNT} ; then umount ${USBMNT} ; fi
+ rm -rf $USBMNT
+ fi
+ if [ -n "${EFIMNT}" ]; then
+ if mount |grep -qw ${EFIMNT} ; then umount ${EFIMNT} ; fi
+ rm -rf $EFIMNT
+ fi
+ set -e
+} # End of cleanup()
+
+trap 'echo "*** $0 FAILED at line $LINENO ***"; cleanup; exit 1' ERR INT TERM
+
+# Show the help text for this script:
+showhelp() {
+cat <<EOT
+#
+# Purpose: to update the content of a Slackware Live USB stick.
+#
+# $(basename $0) accepts the following parameters:
+# -b|--nobackup Do not try to backup original kernel and modules.
+# -d|--devices List removable devices on this computer.
+# -h|--help This help.
+# -i|--init <filename> Replacement init script.
+# -k|--kernel <filename> The kernel file (or package).
+# -m|--kmoddir <name> The kernel modules directory (or package).
+# -n|--netsupport Add network boot support if not yet present.
+# -o|--outdev <filename> The device name of your USB drive.
+# -p|--persistence Move persistent data into new Live module.
+# -r|--restore Restore previous kernel and modules.
+# -s|--scan Scan for insertion of new USB device instead of
+# providing a devicename (using option '-o').
+# -v|--verbose Show verbose messages.
+# -w|--wait<number> Add <number> seconds wait time to initialize USB.
+#
+EOT
+} # End of showhelp()
+
+# Scan for insertion of a USB device:
+scan_devices() {
+ local BD
+ # Inotifywatch does not trigger on symlink creation,
+ # so we can not watch /sys/block/
+ BD=$(inotifywait -q -t ${SCANWAIT} -e create /dev 2>/dev/null |cut -d' ' -f3)
+ echo ${BD}
+} # End of scan_devices()
+
+# Show a list of removable devices detected on this computer:
+show_devices() {
+ local MYDATA="${*}"
+ if [ -z "${MYDATA}" ]; then
+ MYDATA="$(ls --indicator-style=none /sys/block/ |grep -Ev '(ram|loop|dm-)')"
+ fi
+ echo "# Removable devices detected on this computer:"
+ for BD in ${MYDATA} ; do
+ if [ $(cat /sys/block/${BD}/removable) -eq 1 ]; then
+ echo "# /dev/${BD} : $(cat /sys/block/${BD}/device/vendor) $(cat /sys/block/${BD}/device/model): $(( $(cat /sys/block/${BD}/size) / 2048)) MB"
+ fi
+ done
+ echo "#"
+} # End of show_devices()
+
+# Uncompress the initrd based on the compression algorithm used:
+uncompressfs () {
+ if $(file "${1}" | grep -qi ": gzip"); then
+ gzip -cd "${1}"
+ elif $(file "${1}" | grep -qi ": XZ"); then
+ xz -cd "${1}"
+ fi
+} # End of uncompressfs ()
+
+# Collect the kernel modules we need for the liveslak initrd.
+# When calling this function, the old module tree must already
+# have been renamed to ${OLDKVER}.prev
+collect_kmods() {
+ local IMGDIR="$1"
+
+ # Borrow (and mangle) code from Slackware's mkinitrd
+ # to convert the KMODS variable into a collection of modules:
+ # Sanitize the modules list first, before any further processing.
+ # The awk command eliminates doubles without changing the order:
+ KMODS=$(echo $KMODS |tr -s ':' '\n' |awk '!x[$0]++' |tr '\n' ':')
+ KMODS=$(echo ${KMODS%:}) # Weed out a trailing ':'
+
+ # Count number of modules
+ # This INDEX number gives us an easy way to find individual
+ # modules and their arguments, as well as tells us how many
+ # times to run through the list
+ if ! echo $KMODS | grep ':' > /dev/null ; then # only 1 module specified
+ INDEX=1
+ else
+ # Trim excess ':' which will screw this routine:
+ KMODS=$(echo $KMODS | tr -s ':')
+ INDEX=1
+ while [ ! "$(echo "$KMODS" | cut -f $INDEX -d ':' )" = "" ]; do
+ INDEX=$(expr $INDEX + 1)
+ done
+ INDEX=$(expr $INDEX - 1) # Don't include the null value
+ fi
+
+ mkdir -p $IMGDIR/lib/modules/${KVER}
+
+ # Wrap everything in a while loop
+ i=0
+ while [ $i -ne $INDEX ]; do
+ i=$(( $i + 1 ))
+
+ # FULL_MOD is the module plus any arguments (if any)
+ # MODULE is the module name
+ # ARGS is any optional arguments to be passed to the kernel
+ FULL_MOD="$(echo "$KMODS" | cut -d ':' -f $i)"
+ MODULE="$(echo "$FULL_MOD" | cut -d ' ' -f 1 )"
+ # Test for arguments
+ if echo "$FULL_MOD" | grep ' ' > /dev/null; then
+ ARGS=" $(echo "$FULL_MOD" | cut -d ' ' -f 2- )"
+ else
+ unset ARGS
+ fi
+
+ # Get MODULE deps and prepare modprobe lines
+ modprobe --dirname ${KMODDIR%%/lib/modules/${KVER}} --set-version $KVER --show-depends --ignore-install $MODULE 2>/dev/null \
+ | grep "^insmod " | cut -f 2 -d ' ' | while read SRCMOD; do
+
+ if ! grep -Eq " $(basename $SRCMOD .ko)(\.| |$)" $IMGDIR/load_kernel_modules 2>/dev/null ; then
+ LINE="$(echo "modprobe -v $(basename ${SRCMOD%%.gz} .ko)" )"
+
+ # Test to see if arguments should be passed
+ # Over-ride the previously defined LINE variable if so
+ if [ "$(basename $SRCMOD .ko)" = "$MODULE" ]; then
+ # SRCMOD and MODULE are same, ARGS can be passed
+ LINE="$LINE$ARGS"
+ fi
+
+ fi
+
+ if ! grep -qx "$LINE" $IMGDIR/load_kernel_modules ; then
+ echo "$LINE" >> $IMGDIR/load_kernel_modules
+ fi
+
+ # Try to add the module to the initrd-tree. This should be done
+ # even if it exists there already as we may have changed compilers
+ # or otherwise caused the modules in the initrd-tree to need
+ # replacement.
+ cd ${KMODDIR}
+ # Need to strip ${KMODDIR} from the start of ${SRCMOD}:
+ cp -a --parents $(echo $SRCMOD |sed 's|'${KMODDIR}'/|./|' ) $IMGDIR/lib/modules/${KVER}/ 2>/dev/null
+ COPYSTAT=$?
+ cd - 1>/dev/null
+ if [ $COPYSTAT -eq 0 ]; then
+ if [ $VERBOSE -eq 1 ]; then
+ echo "OK: $SRCMOD added."
+ fi
+ # If a module needs firmware, copy that too
+ modinfo -F firmware "$SRCMOD" | sed 's/^/\/lib\/firmware\//' |
+ while read SRCFW; do
+ if cp -a --parents "$SRCFW" $IMGDIR 2>/dev/null; then
+ if [ $VERBOSE -eq 1 ]; then
+ echo "OK: $SRCFW added."
+ fi
+ else
+ echo "*** WARNING: Could not find firmware \"$SRCFW\""
+ fi
+ done
+ else
+ echo "*** WARNING: Could not find module \"$SRCMOD\""
+ fi
+ unset COPYSTAT
+
+ done
+ done
+ # End of Slackware mkinitrd code.
+
+ # Do we have to add network support?
+ if [ $NETSUPPORT -eq 1 ]; then
+ # The initrd already contains dhcpcd so we just need to add kmods:
+ cd ${KMODDIR}
+ mkdir -p ${IMGDIR}/lib/modules/${KVER}
+ cp -a --parents ${NETMODS} ${IMGDIR}/lib/modules/${KVER}/
+ cd - 1>/dev/null
+ # Prune the ones we do not need:
+ for KNETRM in ${NETEXCL} ; do
+ find ${IMGDIR}/lib/modules/${KVER}/${NETMODS} \
+ -name $KNETRM -depth -exec rm -rf {} \;
+ done
+ # Add any dependency modules:
+ for MODULE in $(find ${IMGDIR}/lib/modules/${KVER}/${NETMODS} -type f -exec basename {} .ko \;) ; do
+ modprobe --dirname ${KMODDIR%%/lib/modules/${KVER}} --set-version $KVER --show-depends --ignore-install $MODULE 2>/dev/null |grep "^insmod " |cut -f 2 -d ' ' |while read SRCMOD; do
+ if [ "$(basename $SRCMOD .ko)" != "$MODULE" ]; then
+ cd ${KMODDIR}
+ # Need to strip ${KMODDIR} from the start of ${SRCMOD}:
+ cp -a --parents $(echo $SRCMOD |sed 's|'${KMODDIR}'/|./|' ) \
+ ${IMGDIR}/lib/modules/${KVER}/
+ cd - 1>/dev/null
+ fi
+ done
+ done
+ fi
+ # We added extra modules to the initrd, so we run depmod again:
+ if [ $VERBOSE -eq 1 ]; then
+ chroot ${IMGDIR} depmod $KVER
+ else
+ chroot ${IMGDIR} depmod $KVER 2>/dev/null
+ fi
+}
+
+# Read configuration data from old initrd:
+read_initrd() {
+ local IMGDIR="$1"
+
+ cd ${IMGDIR}
+
+ # Retrieve the currently defined USB wait time:
+ OLDWAIT=$(cat ./wait-for-root)
+
+ # Read the values of liveslak template variables in the init script:
+ for TEMPLATEVAR in DISTRO LIVE_HOSTNAME LIVEMAIN LIVEUID MARKER MEDIALABEL PERSISTENCE VERSION ; do
+ eval $(grep "^ *${TEMPLATEVAR}=" ./init |head -1)
+ done
+
+ if [ $RESTORE -eq 1 ]; then
+ # Add '||true' because grep's exit code '1' may abort the script:
+ PREVMODDIR=$(find ./lib/modules -type d -mindepth 1 -maxdepth 1 |grep .prev || true)
+ if [ -n "${PREVMODDIR}" ] ; then
+ KRESTORE=1
+ else
+ echo "--- No backed-up kernel modules detected in '${IMGFILE}'."
+ KRESTORE=0
+ fi
+ fi
+ if [ $UPKERNEL -eq 1 ]; then
+ OLDMODDIR=$(find ./lib/modules -type d -mindepth 1 -maxdepth 1 |grep -v .prev)
+ if [ $(echo ${OLDMODDIR} |wc -w) -gt 1 ] ; then
+ echo "*** Multiple kernelmodule trees detected in '${IMGFILE}'."
+ SUPPORTED=0
+ else
+ OLDKVER=$(basename "${OLDMODDIR}")
+ OLDKMODDIRSIZE=$(du -sm "${OLDMODDIR}" |tr '\t' ' ' |cut -d' ' -f1)
+ # Find out if the old kernel contains network support.
+ # Use presence of 'devlink.ko' in the old tree to determine this,
+ # but allow for a pre-set override value based on commandline preference:
+ if [ -f ${OLDMODDIR}/kernel/net/core/devlink.ko ]; then
+ NETSUPPORT=${NETSUPPORT:-1}
+ else
+ NETSUPPORT=${NETSUPPORT:-0}
+ fi
+ fi
+ fi
+} # End read_initrd()
+
+# Extract the initrd:
+extract_initrd() {
+ local IMGFILE="$1"
+
+ cd ${IMGDIR}
+ uncompressfs ${IMGFILE} \
+ | cpio -i -d -H newc --no-absolute-filenames
+} # End of extract_initrd()
+
+# Modify the extracted initrd and re-pack it:
+update_initrd() {
+ local IMGFILE="$1"
+ local NEED_RECOMP=0
+
+ cd ${IMGDIR}
+ if [ ${WAIT} -ge 0 ]; then
+ if [ $WAIT != $OLDWAIT ]; then
+ echo "--- Updating 'waitforroot' time from '$OLDWAIT' to '$WAIT'"
+ echo ${WAIT} > wait-for-root
+ NEED_RECOMP=1
+ fi
+ fi
+
+ if [ $UPKERNEL -eq 1 ]; then
+ OLDMODDIR=$(find ./lib/modules -type d -mindepth 1 -maxdepth 1 |grep -v .prev)
+ rm -rf ./lib/modules/*.prev
+ if [ $KBACKUP -eq 1 ]; then
+ # We make one backup:
+ if [ $VERBOSE -eq 1 ]; then
+ echo "--- Making backup of kernel modules"
+ fi
+ mv -i ${OLDMODDIR} ${OLDMODDIR}.prev
+ else
+ echo "--- No room for backing up old kernel modules"
+ rm -rf ${OLDMODDIR}
+ fi
+ # Add modules for the new kernel:
+ echo "--- Adding new kernel modules"
+ collect_kmods ${IMGDIR}
+ NEED_RECOMP=1
+ elif [ $RESTORE -eq 1 -a $KRESTORE -eq 1 ]; then
+ # Restore previous kernel module tree.
+ # The 'read_initrd' routine will already have checked that we have
+ # one active and one .prev modules tree:
+ OLDMODDIR=$(find ./lib/modules -type d -mindepth 1 -maxdepth 1 |grep .prev || true)
+ NEWMODDIR=$(find ./lib/modules -type d -mindepth 1 -maxdepth 1 |grep -v .prev)
+ echo "--- Restoring old kernel modules"
+ rm -rf ${NEWMODDIR}
+ mv ${OLDMODDIR} ${OLDMODDIR%.prev}
+ NEED_RECOMP=1
+ fi
+
+ if [ -n "${LIVEINIT}" ]; then
+ echo "--- Replacing live init script"
+ cp ./init ./init.prev
+ if grep -q "@LIVEMAIN@" ${LIVEINIT} ; then
+ # The provided init is a liveinit template, and we need
+ # to substitute the placeholders with actual values:
+ parse_template ${LIVEINIT} $(pwd)/init
+ else
+ cat ${LIVEINIT} > ./init
+ fi
+ NEED_RECOMP=1
+ fi
+
+ if [ ${NEED_RECOMP} -eq 1 ]; then
+ echo "--- Compressing the initrd image again"
+ chmod 0755 ${IMGDIR}
+ find . |cpio -o -H newc |$COMPR > ${IMGFILE}
+ fi
+ cd - 1>/dev/null # End of 'cd ${IMGDIR}'
+} # End of update_initrd()
+
+# Accept either a kernelimage or a packagename,
+# and return the path to a kernelimage:
+getpath_kernelimg () {
+ local MYDATA="${*}"
+ [ -z "${MYDATA}" ] && echo ""
+
+ if [ -n "$(file \"${MYDATA}\" |grep -E 'x86 boot (executable|sector)')" ]; then
+ # We have a kernel image:
+ echo "${MYDATA}"
+ else
+ # We assume a Slackware package:
+ # Extract the generic kernel from the package and return its filename:
+ tar --wildcards -C ${KERDIR} -xf ${MYDATA} boot/vmlinuz-generic-*
+ echo "$(ls --indicator-style=none ${KERDIR}/boot/vmlinuz-generic-*)"
+ fi
+} # End of getpath_kernelimg
+
+# Accept either a directory containing module tree, or a packagename,
+# and return the path to a module tree:
+getpath_kernelmods () {
+ local MYDATA="${*}"
+ [ -z "${MYDATA}" ] && echo ""
+
+ if [ -d "${MYDATA}" ]; then
+ # We have directory, assume it contains the kernel modules:
+ echo "${MYDATA}"
+ else
+ # We assume a Slackware package:
+ # Extract the kernel modules from the package and return the path:
+ tar -C ${KERDIR} -xf ${MYDATA} lib/modules
+ cd ${KERDIR}/lib/modules/*
+ pwd
+ fi
+} # End of getpath_kernelmods
+
+# Determine size of a mounted partition (in MB):
+get_part_mb_size() {
+ local MYSIZE
+ MYSIZE=$(df -P -BM ${1} |tail -1 |tr -s '\t' ' ' |cut -d' ' -f2)
+ echo "${MYSIZE%M}"
+} # End of get_part_mb_size
+
+# Determine free space of a mounted partition (in MB):
+get_part_mb_free() {
+ local MYSIZE
+ MYSIZE=$(df -P -BM ${1} |tail -1 |tr -s '\t' ' ' |cut -d' ' -f4)
+ echo "${MYSIZE%M}"
+} # End of get_part_mb_free
+
+parse_template() {
+ # Parse a liveslak template file and substitute the placeholders.
+ local INFILE="$1"
+ local OUTFILE="$2"
+
+ # We expect these variables to be set before calling this function.
+ # But, we do provide default values.
+ DISTRO=${DISTRO:-slackware}
+ VERSION=${VERSION:-1337}
+
+ cat ${INFILE} | sed \
+ -e "s/@LIVEMAIN@/${LIVEMAIN:-liveslak}/g" \
+ -e "s/@MARKER@/${MARKER:-LIVESLAK}/g" \
+ -e "s/@MEDIALABEL@/${MEDIALABEL:-LIVESLAK}/g" \
+ -e "s/@PERSISTENCE@/${PERSISTENCE:-persistence}/g" \
+ -e "s/@DARKSTAR@/${LIVE_HOSTNAME:-darkstar}/g" \
+ -e "s/@LIVEUID@/${LIVEUID:-live}/g" \
+ -e "s/@DISTRO@/$DISTRO/g" \
+ -e "s/@CDISTRO@/${DISTRO^}/g" \
+ -e "s/@UDISTRO@/${DISTRO^^}/g" \
+ -e "s/@VERSION@/${VERSION}.1337/g" \
+ > ${OUTFILE}
+} # End of parse_template()
+
+#
+# -- end of function definitions --
+#
+
+# ===========================================================================
+
+# Parse the commandline parameters:
+if [ -z "$1" ]; then
+ showhelp
+ exit 1
+fi
+while [ ! -z "$1" ]; do
+ case $1 in
+ -b|--nobackup)
+ KBACKUP=0
+ shift
+ ;;
+ -d|--devices)
+ show_devices
+ exit
+ ;;
+ -h|--help)
+ showhelp
+ exit
+ ;;
+ -i|--init)
+ LIVEINIT="$2"
+ shift 2
+ ;;
+ -k|--kernel)
+ KERNEL="$2"
+ shift 2
+ ;;
+ -m|--kmoddir)
+ KMODDIR="$2"
+ shift 2
+ ;;
+ -n|--netsupport)
+ NETSUPPORT=1
+ shift
+ ;;
+ -o|--outdev)
+ TARGET="$2"
+ shift 2
+ ;;
+ -p|--persistence)
+ CHANGES2SXZ=1
+ shift
+ ;;
+ -r|--restore)
+ RESTORE=1
+ shift
+ ;;
+ -s|--scan)
+ SCAN=1
+ shift
+ ;;
+ -v|--verbose)
+ VERBOSE=1
+ shift
+ ;;
+ -w|--wait)
+ WAIT="$2"
+ shift 2
+ ;;
+ *)
+ echo "*** Unknown parameter '$1'!"
+ exit 1
+ ;;
+ esac
+done
+
+# Before we start:
+if [ "$(id -u)" != "0" ]; then
+ echo "*** You need to be root to run $(basename $0)."
+ exit 1
+fi
+
+#
+# More sanity checks:
+#
+
+# Either provide a block device, or else scan for a block device:
+if [ -z "$TARGET" ]; then
+ if [ $SCAN -eq 1 ]; then
+ echo "-- Waiting ${SCANWAIT} seconds for a USB stick to be inserted..."
+ TARGET=$(scan_devices)
+ if [ -z "$TARGET" ]; then
+ echo "*** No new USB device detected during $SCANWAIT seconds scan."
+ exit 1
+ else
+ TARGET="/dev/${TARGET}"
+ fi
+ else
+ echo "*** You must specify the Live USB devicename (option '-o')!"
+ exit 1
+ fi
+elif [ $SCAN -eq 1 ]; then
+ echo "*** You can not use options '-o' and '-s' at the same time!"
+ exit 1
+fi
+
+if [ ! -b $TARGET ]; then
+ echo "*** Not a block device: '$TARGET' !"
+ show_devices
+ exit 1
+elif [ "$(echo ${TARGET%%[0-9]*})" != "$TARGET" ]; then
+ echo "*** You need to point to the USB device, not a partition ($TARGET)!"
+ show_devices
+ exit 1
+fi
+
+if [ -z "$KERNEL" -a -z "$KMODDIR" ]; then
+ # We don't need to update the kernel/modules:
+ UPKERNEL=0
+else
+ if [ $RESTORE -eq 1 ]; then
+ echo "*** You can not use options '-k'/'-m' and '-r' at the same time!"
+ exit 1
+ fi
+ # If we get here, we have one or both '-k' and '-m'.
+ # Sanitize the input values of '-k' and '-m':
+ if [ -z "$KERDIR" ]; then
+ # Create a temporary extraction directory:
+ mkdir -p /mnt
+ KERDIR=$(mktemp -d -p /mnt -t alienker.XXXXXX)
+ if [ ! -d $KERDIR ]; then
+ echo "*** Failed to create temporary extraction dir for the kernel!"
+ cleanup
+ exit 1
+ fi
+ fi
+ KERNEL="$(getpath_kernelimg ${KERNEL})"
+ KMODDIR="$(getpath_kernelmods ${KMODDIR})"
+
+ if [ ! -f "${KERNEL}" -o ! -d "${KMODDIR}" ]; then
+ echo "*** You need to provide the path to a kernel imagefile (-k),"
+ echo "*** as well as the directory containing the kernel modules (-m)!"
+ cleanup
+ exit 1
+ else
+ # Determine the new kernel version from a module,
+ # rather than from a directory- or filenames:
+ KVER=$(strings ${KMODDIR}/kernel/fs/overlayfs/overlay.ko* |grep ^vermagic |cut -d= -f2 |cut -d' ' -f1)
+ if [ -z "${KVER}" ]; then
+ echo "*** Could not determine kernel version from the module directory"
+ echo "*** (querying module kernel/fs/overlayfs/overlay.ko)!"
+ cleanup
+ exit 1
+ fi
+ UPKERNEL=1
+ fi
+fi
+
+if [ -n "${LIVEINIT}" -a ! -f "${LIVEINIT}" ]; then
+ echo "*** The replacement init script '${LIVEINIT}' is not a file!'"
+ cleanup
+ exit 1
+fi
+
+if [ $CHANGES2SXZ -eq 1 ]; then
+ # We need to create a module, so add squashfs to the required tools:
+ REQTOOLS="${REQTOOLS} mksquashfs"
+fi
+
+# Are all the required tools present?
+PROG_MISSING=""
+for PROGN in ${REQTOOLS} ; do
+ if ! which $PROGN 1>/dev/null 2>/dev/null ; then
+ PROG_MISSING="${PROG_MISSING}-- $PROGN\n"
+ fi
+done
+if [ ! -z "$PROG_MISSING" ] ; then
+ echo "-- Required program(s) not found in search path '$PATH'!"
+ echo -e ${PROG_MISSING}
+ echo "-- Exiting."
+ cleanup
+ exit 1
+fi
+
+# We are refreshing the Live content.
+# Confirm refresh:
+cat <<EOT
+#
+# We are going to update the Live OS on this device.
+# ---------------------------------------------------------------------------
+# Target is - '$TARGET':
+# Vendor : $(cat /sys/block/$(basename $TARGET)/device/vendor)
+# Model : $(cat /sys/block/$(basename $TARGET)/device/model)
+# Size : $(( $(cat /sys/block/$(basename $TARGET)/size) / 2048)) MB
+# ---------------------------------------------------------------------------
+#
+# FDISK OUTPUT:
+EOT
+
+echo q |gdisk -l $TARGET 2>/dev/null | \
+ while read LINE ; do echo "# $LINE" ; done
+
+# If the user just used the scan option (-s) and did not select a task,
+# we will exit the script gracefully now:
+if [[ $WAIT -lt 0 && $UPKERNEL -ne 1 && $RESTORE -ne 1 && $NETSUPPORT -ne 1 && $LIVEINIT = "" && $CHANGES2SXZ -ne 1 ]]; then
+ cleanup
+ exit 0
+else
+ # We have one or more tasks to execute, allow user to back out:
+ cat <<EOT
+*** ***
+*** If this is the wrong drive, then press CONTROL-C now! ***
+*** ***
+
+EOT
+ read -p "Or press ENTER to continue: " JUNK
+fi
+
+# OK... the user was sure about the drive...
+# Create a temporary extraction directory for the initrd:
+mkdir -p /mnt
+IMGDIR=$(mktemp -d -p /mnt -t alienimg.XXXXXX)
+if [ ! -d $IMGDIR ]; then
+ echo "*** Failed to create temporary extraction directory for the initrd!"
+ cleanup
+ exit 1
+fi
+chmod 711 $IMGDIR
+
+# Create temporary mount point for the USB device:
+mkdir -p /mnt
+# USB mounts:
+USBMNT=$(mktemp -d -p /mnt -t alienusb.XXXXXX)
+if [ ! -d $USBMNT ]; then
+ echo "*** Failed to create a temporary mount point for the USB device!"
+ cleanup
+ exit 1
+else
+ chmod 711 $USBMNT
+fi
+EFIMNT=$(mktemp -d -p /mnt -t alienefi.XXXXXX)
+if [ ! -d $EFIMNT ]; then
+ echo "*** Failed to create a temporary mount point for the USB device!"
+ cleanup
+ exit 1
+else
+ chmod 711 $EFIMNT
+fi
+
+# Mount the Linux partition:
+mount -t auto ${TARGET}3 ${USBMNT}
+
+# Mount the EFI partition:
+mount -t vfat -o shortname=mixed ${TARGET}2 ${EFIMNT}
+
+# Determine size of the Linux partition (in MB), and the free space:
+USBPSIZE=$(get_part_mb_size ${USBMNT})
+USBPFREE=$(get_part_mb_free ${USBMNT})
+
+# Determine size of the EFI partition (in MB), and the free space:
+EFIPSIZE=$(get_part_mb_size ${EFIMNT})
+EFIPFREE=$(get_part_mb_free ${EFIMNT})
+
+# Record the Slackware Live version:
+OLDVERSION="$(cat ${USBMNT}/.isoversion 2>/dev/null)"
+echo "-- The medium '${TARGET}' contains '${OLDVERSION}'"
+
+# Find out if the USB contains an EFI bootloader and use it:
+if [ ! -f ${EFIMNT}/EFI/BOOT/boot*.efi ]; then
+ EFIBOOT=0
+ echo "-- Note: UEFI boot file 'bootx64.efi' or 'bootia32.efi' not found on ISO."
+ echo "-- UEFI boot will not be supported"
+else
+ EFIBOOT=1
+fi
+
+# Record the size of the running kernel:
+if [ -f "${USBMNT}/boot/vmlinuz*" ]; then
+ KIMG="$(find ${USBMNT}/boot/ -type f -name \"vmlinuz*\" |grep -v prev)"
+else
+ # Default liveslak kernelname:
+ KIMG="${USBMNT}/boot/generic"
+fi
+OLDKERNELSIZE=$(du -sm "${KIMG}" |tr '\t' ' ' |cut -d' ' -f1)
+
+# Collect data from the USB initrd:
+extract_initrd ${USBMNT}/boot/initrd.img
+read_initrd ${IMGDIR}
+
+# The read_initrd routine will set SUPPORTED to '0'
+# if it finds a non-standard configuration for kernel & modules:
+if [ $KBACKUP -eq 1 ]; then
+ if [ $SUPPORTED -ne 1 ]; then
+ echo "*** ${TARGET} has an unsupported kernel configuration."
+ echo "*** Exiting now."
+ cleanup
+ exit 1
+ else
+ # If free space is low, require '-b' to skip make a backup (unsafe).
+ if [ $(( $USBPFREE - $OLDKMODDIRSIZE - $OLDKERNELSIZE )) -lt $MINFREE ]; then
+ KBACKUP=-1
+ fi
+ if [ $EFIBOOT -eq 1 -a $(( $EFIPFREE - $OLDKMODDIRSIZE - $OLDKERNELSIZE )) -lt $MINFREE ]; then
+ KBACKUP=-1
+ fi
+ if [ $KBACKUP -eq -1 ]; then
+ echo "*** Not enough free space for a backup of old kernel and modules."
+ echo "*** If you want to update your kerel anyway (without backup) then"
+ echo "*** you have to add the parameter '-b' to the commandline."
+ cleanup
+ exit 1
+ fi
+ fi
+fi
+
+# Update the initrd with regard to USB wait time, liveinit, kernel:
+update_initrd ${USBMNT}/boot/initrd.img
+
+# Take care of the kernel in the Linux partition:
+if [ $UPKERNEL -eq 1 ]; then
+ if [ $KBACKUP -eq 1 ]; then
+ # We always make one backup with the suffix ".prev":
+ if [ $VERBOSE -eq 1 ]; then
+ echo "-- Backing up ${KIMG} to ${USBMNT}/boot/$(basename \"${KIMG}\").prev"
+ fi
+ mv "${KIMG}" ${USBMNT}/boot/$(basename "${KIMG}").prev
+ else
+ rm -rf "${KIMG}"
+ fi
+ # And we name our new kernel exactly as the old one:
+ if [ $VERBOSE -eq 1 ]; then
+ echo "-- Copying \"${KERNEL}\" to ${USBMNT}/boot/$(basename \"${KIMG}\")"
+ fi
+ cp "${KERNEL}" ${USBMNT}/boot/$(basename "${KIMG}")
+elif [ $RESTORE -eq 1 -a $KRESTORE -eq 1 ]; then
+ if [ $VERBOSE -eq 1 ]; then
+ echo "-- Restoring ${USBMNT}/boot/$(basename \"${KIMG}\").prev to ${KIMG}"
+ fi
+ rm -f "${KIMG}"
+ mv ${USBMNT}/boot/$(basename "${KIMG}").prev "${KIMG}"
+fi
+
+if [ $EFIBOOT -eq 1 ]; then
+ # Refresh the kernel/initrd on the EFI partition:
+ if [ $VERBOSE -eq 1 ]; then
+ rsync -rlptD --delete -v ${USBMNT}/boot/* ${EFIMNT}/boot/
+ else
+ rsync -rlptD --delete ${USBMNT}/boot/* ${EFIMNT}/boot/
+ fi
+ sync
+fi
+
+if [ $CHANGES2SXZ -eq 1 ]; then
+ if [ ! -d /mnt/live/changes ]; then
+ echo "*** No directory '/mnt/live/changes' exists!"
+ echo "*** This script must be executed when running ${DISTRO^} Live Edition"
+ else
+ # We need to be able to write to the partition:
+ mount -o remount,rw ${USBMNT}
+ # Tell init to wipe the original persistence data at next boot:
+ touch /mnt/live/changes/.wipe 2>/dev/null || true
+ if [ ! -f /mnt/live/changes/.wipe ]; then
+ echo "*** Unable to create file '/mnt/live/changes/.wipe'!"
+ echo "*** Are you sure you are running ${DISTRO^} Live Edition?"
+ else
+ # Squash the persistence data into a Live .sxz module:
+ LIVE_MOD_SYS=$(dirname $(find ${USBMNT} -name "0099-${DISTRO}_zzzconf*.sxz" |head -1))
+ LIVE_MOD_ADD=$(dirname ${LIVE_MOD_SYS})/addons
+ MODNAME="0100-${DISTRO}_customchanges-$(date +%Y%m%d%H%M%S).sxz"
+ echo "-- Moving current persistence data into addons module '${MODNAME}'"
+ mksquashfs /mnt/live/changes ${LIVE_MOD_ADD}/${MODNAME} -noappend -comp xz -b 1M -e .wipe
+ fi
+ fi
+fi
+
+# Unmount/remove stuff:
+cleanup
+
+# THE END
+