diff options
Diffstat (limited to 'upslak.sh')
-rw-r--r-- | upslak.sh | 526 |
1 files changed, 443 insertions, 83 deletions
@@ -62,15 +62,28 @@ UPKERNEL=0 # Do not change usb wait time by default: WAIT=-1 +# Not extending any container by default: +EXTENSION="" + # --------------------------------------------------------------------------- # END possible tasks to be executed by the script: # --------------------------------------------------------------------------- +# The extension for containerfiles accompanying an ISO is '.icc', +# whereas the persistent USB stick created with iso2usb.sh uses '.img'. +DEFEXT=".img" +CNTEXT="${DEFEXT}" + +# Default filesystem for devices/containers: +DEF_FS="ext4" +FSYS="${DEF_FS}" + # 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: +CORE2RAMMODS="" DEF_KBD="" DEF_LOCALE="" DEF_TZ="" @@ -81,7 +94,6 @@ LIVEUID="" MARKER="" MEDIALABEL="" PERSISTENCE="" -CORE2RAMMODS="" SQ_EXT_AVAIL="" VERSION="" @@ -89,9 +101,15 @@ VERSION="" KBACKUP=1 # Does the initrd contain an old kernel that we can restore? -# The 'read_initrd' routing may set this to '0': +# The 'read_initrddir' routine may set this to '0': KRESTORE=1 +# By default we create an addon live module for the new kernel modules, +# otherwise the Live OS will be broken after reboot. +# User can skip this if they already installed the kernel-modules package +# in the Live OS earlier: +NOLIVEMODS=0 + # Timeout when scanning for inserted USB device, 30 seconds by default, # but this default can be changed from outside the script: SCANWAIT=${SCANWAIT:-30} @@ -109,8 +127,6 @@ 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: @@ -121,10 +137,22 @@ IMGDIR="" KERDIR="" USBMNT="" EFIMNT="" +CNTDEV="" +LODEV="" + +# Empty initialization: +INCSIZE="" +PARTFREE="" +PARTSIZE="" # These tools are required by the script, we will check for their existence: REQTOOLS="cpio gdisk inotifywait lsblk strings xz" +# 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} + # 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" @@ -133,7 +161,7 @@ COMPR="xz --check=crc32" # 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; # Virtio modules added to experiment with liveslak in a VM. -KMODS=${KMODS:-"squashfs:overlay:loop:efivarfs:xhci-pci:ohci-pci:ehci-pci:xhci-hcd:uhci-hcd:ehci-hcd:mmc-core:mmc-block:sdhci:sdhci-pci:sdhci-acpi:rtsx_pci:rtsx_pci_sdmmc:usb-storage:uas: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:exfat:ntfs:virtio_ring:virtio:virtio_blk:virtio_balloon:virtio_pci:virtio_pci_modern_dev:virtio_net"} +KMODS=${KMODS:-"squashfs:overlay:loop:efivarfs:xhci-pci:ohci-pci:ehci-pci:xhci-hcd:uhci-hcd:ehci-hcd:mmc-core:mmc-block:sdhci:sdhci-pci:sdhci-acpi:rtsx_pci:rtsx_pci_sdmmc:usb-storage:uas: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:zstd_compress:lz4hc_compress:lz4_compress:btrfs:f2fs:jfs:xfs:isofs:fat:nls_cp437:nls_iso8859-1:msdos:vfat:exfat:ntfs:virtio_ring:virtio:virtio_blk:virtio_balloon:virtio_pci:virtio_pci_modern_dev:virtio_net"} # Network kernel modules to include for NFS root support: NETMODS="kernel/drivers/net kernel/drivers/virtio" @@ -147,22 +175,32 @@ NETEXCL="appletalk arcnet bonding can dummy.ko hamradio hippi ifb.ko irda macvla # # Clean up in case of failure: -cleanup() { +function 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 + + if [ -n "$CNTDEV" ]; then + # In case of failure, only most recent LUKS mapped device is still open: + if mount | grep -q ${CNTDEV} ; then + umount -f ${CNTDEV} + cryptsetup luksClose $(basename ${CNTDEV}) + losetup -d ${LODEV} + fi + fi + # 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 + rmdir $USBMNT fi if [ -n "${EFIMNT}" ]; then if mount |grep -qw ${EFIMNT} ; then umount ${EFIMNT} ; fi - rm -rf $EFIMNT + rmdir $EFIMNT fi set -e } # End of cleanup() @@ -170,7 +208,7 @@ cleanup() { trap 'echo "*** $0 FAILED at line $LINENO ***"; cleanup; exit 1' ERR INT TERM # Show the help text for this script: -showhelp() { +function showhelp() { cat <<EOT # # Purpose: to update the content of a Slackware Live USB stick. @@ -178,6 +216,7 @@ cat <<EOT # $(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. +# -e|--examples Show some common usage examples. # -h|--help This help. # -i|--init <filename> Replacement init script. # -k|--kernel <filename> The kernel file (or package). @@ -190,27 +229,71 @@ cat <<EOT # providing a devicename (using option '-o'). # -v|--verbose Show verbose messages. # -w|--wait<number> Add <number> seconds wait time to initialize USB. -# -# Note that if you upgrade the kernel and modules using $(basename $0), -# this will apply only to the USB boot kernel and its initrd! -# Before running $(basename $0) to upgrade the kernel & modules, -# you first need to upgrade the kernel-generic and kernel-modules packages -# in the Live OS using installpkg/upgradepkg or slackpkg. +# -x|--extend <fullpath> Full path (either in your filesystem or else +# relative to the USB partition root) +# to an existing (encrypted) container file, +# whose size you want to extend. +# Limitations: +# - container needs to be LUKS encrypted. +# - filename extension needs to be '${CNTEXT}'. +# Supported filesystems inside container: +# - $(resizefs). +# -N|--nolivemods Don't create an addon live module containing +# the new kernelmodules. Normally you *will* need +# this addon module, *unless* you have already +# installed these kernel-modules in the Live OS. +# FYI: the kernel and module upgrade applies only +# to the USB boot kernel and its initrd. +# -X|--extendsize <size|perc> Extend size of existing container; value +# is the requested extension of the container +# in kB, MB, GB, or as percentage of free space +# (integer numbers only). +# Examples: '-X 125M', '-X 2G', '-X 20%'. # EOT } # End of showhelp() +function showexamples() { +cat <<EOT +# +# Some common usage examples for $(basename $0) +# --------------------------------------------------------------------------- +# +# Get a listing of all available removable devices on the computer: +# ./$(basename $0) -d +# +# Updating kernel and modules, providing two packages as input and assuming +# that the USB stick is known as /dev/sdX: +# ./$(basename $0) -o /dev/sdX -m kernel-modules-4.19.0-x86_64-1.txz -k kernel-generic-4.19.0-x86_64-1.txz +# +# Restore the previous kernel and modules after a failed update, +# and let the script scan your computer for the insertion of your USB stick: +# ./$(basename $0) -s -r +# +# Replace the Live init script with the latest template taken from +# the liveslak git repository: +# wget https://git.liveslak.org/liveslak/plain/liveinit.tpl +# ./$(basename $0) -o /dev/sdX -i liveinit.tpl +# +# Extend the size of the pre-existing LUKS container for your homedirectory +# with 3 GB, and let the script scan for the insertion of your USB stick: +# ./$(basename $0) -s -x /slhome.img -X 3G +# +EOT +} # End of showexamples() + # Scan for insertion of a USB device: -scan_devices() { +function scan_devices() { + local MYSCANWAIT="${1}" 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) + BD=$(inotifywait -q -t ${MYSCANWAIT} -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() { +function show_devices() { local MYDATA="${*}" if [ -z "${MYDATA}" ]; then MYDATA="$(ls --indicator-style=none /sys/block/ |grep -Ev '(ram|loop|dm-)')" @@ -224,8 +307,110 @@ show_devices() { echo "#" } # End of show_devices() +# Determine size of a mounted partition (in MB): +function get_part_mb_size() { + local MYPART="${1}" + local MYSIZE + MYSIZE=$(df -P -BM ${MYPART} |tail -n -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): +function get_part_mb_free() { + local MYPART="${1}" + local MYSIZE + MYSIZE=$(df -P -BM ${MYPART} |tail -n -1 |tr -s '\t' ' ' |cut -d' ' -f4) + echo "${MYSIZE%M}" +} # End of get_part_mb_free() + +# Determine requested container size in MB (allow for '%|k|K|m|M|g|G' suffix). +# Note: sizes need to be integer values! Bash arithmetics don't work for floats. +function cont_mb() { + # Uses global variables: PARTFREE + local MYSIZE="$1" + case "${MYSIZE: -1}" in + "%") MYSIZE="$(( $PARTFREE * ${MYSIZE%\%} / 100 ))" ;; + "k") MYSIZE="$(( ${MYSIZE%k} / 1024 ))" ;; + "K") MYSIZE="$(( ${MYSIZE%K} / 1024 ))" ;; + "m") MYSIZE="${MYSIZE%m}" ;; + "M") MYSIZE="${MYSIZE%M}" ;; + "g") MYSIZE="$(( ${MYSIZE%g} * 1024 ))" ;; + "G") MYSIZE="$(( ${MYSIZE%G} * 1024 ))" ;; + *) MYSIZE=-1 ;; + esac + echo "$MYSIZE" +} # End of cont_mb() + +# Expand existing encrypted container file: +function expand_container() { + # Uses external function: cleanup + # Uses global variables: CNTEXT, MINFREE + # Sets global variables: CNTDEV, LODEV, PARTFREE, PARTSIZE + local MYPART="$1" # disk partition + local MYINC="$2" # requested increase ('%|k|K|m|M|g|G' suffix) + local MYFILE="$3" # full path to ${CNTEXT} containerfile + local MYMAP="" # Name of the device-mapped file + local CNTIS="" # Stores size of the container + + # Determine requested container increase in MB: + MYINC=$(cont_mb ${MYINC}) + + # Determine size of the target partition (in MB), and the free space: + PARTSIZE=$(get_part_mb_size ${MYPART}) + PARTFREE=$(get_part_mb_free ${MYPART}) + + if [ $PARTFREE -lt $(( ${MYINC} + ${MINFREE} )) ]; then + echo "*** Free space on USB partition after file-resizing would be less than ${MINFREE} MB;" + echo "*** Not resizing the container file!" + cleanup + exit 1 + fi + + if ! file ${MYFILE} |grep -q 'LUKS' ; then + echo "*** No LUKS container: '${MYFILE}'" + cleanup + exit 1 + else + echo "--- Expanding '$(basename ${MYFILE})' on '${MYPART}' with ${MYINC} MB..." + fi + + # Append random bytes to the end of the container file: + dd if=/dev/urandom of=${MYFILE} bs=1M count=${MYINC} oflag=append conv=notrunc 2>/dev/null + + # Setup a loopback device that we can use with or without cryptsetup: + LODEV=$(losetup -f) + losetup ${LODEV} ${MYFILE} + + if cryptsetup isLuks ${LODEV} ; then + # Unlock LUKS encrypted container first: + MYMAP=$(basename ${MYFILE} ${CNTEXT}) + CNTDEV=/dev/mapper/${MYMAP} + echo "--- Unlocking the LUKS container requires your passphrase..." + until cryptsetup luksOpen ${LODEV} ${MYMAP} ; do + echo ">>> Did you type an incorrect passphrases?" + read -p ">>> Press [ENTER] to try again or Ctrl-C to abort ..." REPLY + done + else + # Use the loopmounted block device for the un-encrypted container: + CNTDEV=${LODEV} + fi + + # Run fsck so the filesystem is clean before we resize it: + fsck -fvy ${CNTDEV} + # Resize the filesystem to occupy the full new size: + resizefs ${CNTDEV} + # Just to be safe: + fsck -fvy ${CNTDEV} + + # Don't forget to clean up after ourselves: + if cryptsetup isLuks ${LODEV} ; then + cryptsetup luksClose ${MYMAP} + fi + losetup -d ${LODEV} || true +} # End of expand_container() + # Uncompress the initrd based on the compression algorithm used: -uncompressfs () { +function uncompressfs () { if $(file "${1}" | grep -qi ": gzip"); then gzip -cd "${1}" elif $(file "${1}" | grep -qi ": XZ"); then @@ -233,10 +418,76 @@ uncompressfs () { fi } # End of uncompressfs () +# Resize the filesystem on a block device: +function resizefs() { + # Uses external function: cleanup + local MYDEV="${1}" + local MYFS + local TMPMNT + + if [ -z "${MYDEV}" ]; then + # Without arguments given, reply with list of supported fs'es: + echo "btrfs,ext2,ext4,f2fs,jfs,xfs" + return + fi + + # Determine the current filesystem for the block device: + MYFS=$(lsblk -n -o FSTYPE ${MYDEV}) + if [ -z "${MYFS}" ]; then + echo "*** Failed to resize filesystem on device '${MYDEV}'!" + echo "*** No filesystem found." + cleanup + exit 1 + fi + + TMPMNT=$(mktemp -d -p ${TMP:=/tmp} -t alienres.XXXXXX) + if [ ! -d $TMPMNT ]; then + echo "*** Failed to create temporary mount for the filesystem resize!" + cleanup + exit 1 + else + chmod 711 ${TMPMNT} + fi + + # Mount the block device prior to the resize + # (btrfs, jfs and xfs do not support offline resize): + mount -o rw -t ${MYFS} ${MYDEV} ${TMPMNT} + + # Resize the filesystem to occupy the full new device capacity: + case "${MYFS}" in + btrfs) btrfs filesystem resize max ${TMPMNT} + ;; + ext*) resize2fs ${MYDEV} + ;; + f2fs) resize.f2fs ${MYDEV} + ;; + jfs) mount -o remount,resize,rw ${TMPMNT} + ;; + xfs) xfs_growfs -d ${TMPMNT} + ;; + *) echo "*** Unsupported filesystem '${MYFS}'!" + cleanup + exit 1 + ;; + esac + + if [ ! $? ]; then + echo "*** Failed to resize '${MYFS}'filesystem on device '${MYDEV}'!" + cleanup + exit 1 + else + # Un-mount the device again: + sync + umount ${TMPMNT} + rmdir ${TMPMNT} + fi +} # End of resizefs() + + # 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() { +function collect_kmods() { local IMGDIR="$1" # Borrow (and mangle) code from Slackware's mkinitrd @@ -369,9 +620,15 @@ collect_kmods() { fi } # End of collect_kmods () -# Read configuration data from old initrd: -read_initrd() { +# Read configuration data from old initrd, +# after it has been extracted into a directory: +function read_initrddir() { local IMGDIR="$1" + local INITVARS="$2" + local OLDKVER + local OLDMODDIR + local OLDKMODDIRSIZE + local PREVMODDIR cd ${IMGDIR} @@ -379,7 +636,7 @@ read_initrd() { OLDWAIT=$(cat ./wait-for-root) # Read the values of liveslak template variables in the init script: - for TEMPLATEVAR in DEF_KBD DEF_LOCALE DEF_TZ DISTRO LIVE_HOSTNAME LIVEMAIN LIVEUID MARKER MEDIALABEL PERSISTENCE CORE2RAMMODS SQ_EXT_AVAIL VERSION ; do + for TEMPLATEVAR in ${INITVARS} ; do eval $(grep "^ *${TEMPLATEVAR}=" ./init |head -1) done @@ -411,23 +668,36 @@ read_initrd() { fi fi fi -} # End read_initrd() - -# Extract the initrd: -extract_initrd() { - local IMGFILE="$1" +} # End read_initrddir() + +# Extract the initrd into a new directory and report the dirname back: +function extract_initrd() { + local MYIMGFILE="$1" + local MYIMGDIR=$(mktemp -d -p ${TMP:=/tmp} -t alienimg.XXXXXX) + if [ ! -d $MYIMGDIR ]; then + echo "*** Failed to create temporary extraction directory for the initrd!" + cleanup + exit 1 + else + chmod 711 $MYIMGDIR + fi - cd ${IMGDIR} - uncompressfs ${IMGFILE} \ - | cpio -i -d -m -H newc + cd ${MYIMGDIR} + uncompressfs ${MYIMGFILE} 2>/dev/null \ + | cpio -i -d -m -H newc 2>/dev/null + echo "$MYIMGDIR" } # End of extract_initrd() # Modify the extracted initrd and re-pack it: -update_initrd() { - local IMGFILE="$1" +function update_initrd() { + local MYIMGFILE="$1" + local MYIMGDIR="$2" local NEED_RECOMP=0 + local NEWMODDIR + local OLDMODDIR + local OLDKVER - cd ${IMGDIR} + cd ${MYIMGDIR} if [ ${WAIT} -ge 0 ]; then if [ $WAIT != $OLDWAIT ]; then echo "--- Updating 'waitforroot' time from '$OLDWAIT' to '$WAIT'" @@ -438,24 +708,23 @@ update_initrd() { if [ $UPKERNEL -eq 1 ]; then OLDMODDIR=$(find ./lib/modules -type d -mindepth 1 -maxdepth 1 |grep -v .prev) + OLDKVER=$(strings $(find ${OLDMODDIR}/kernel/ -name "*.ko*" |head -1) |grep ^vermagic |cut -d= -f2 |cut -d' ' -f1) 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 + echo "--- Making backup of kernel modules (${OLDKVER}) in initrd" mv -i ${OLDMODDIR} ${OLDMODDIR}.prev else - echo "--- No room for backing up old kernel modules" + echo "--- No room for backing up old kernel modules in initrd" rm -rf ${OLDMODDIR} fi # Add modules for the new kernel: - echo "--- Adding new kernel modules" - collect_kmods ${IMGDIR} + echo "--- Adding new kernel modules (${KVER}) to initrd" + collect_kmods ${MYIMGDIR} 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 + # The 'read_initrddir' 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) @@ -466,6 +735,11 @@ update_initrd() { fi if [ -n "${LIVEINIT}" ]; then + if ! file "${LIVEINIT}" |grep -q 'shell script' ; then + echo "*** Not a shell script: "${LIVEINIT}"!" + cleanup + exit 1 + fi echo "--- Replacing live init script" cp ./init ./init.prev if grep -q "@LIVEMAIN@" ${LIVEINIT} ; then @@ -480,19 +754,21 @@ update_initrd() { if [ ${NEED_RECOMP} -eq 1 ]; then echo "--- Compressing the initrd image again" - chmod 0755 ${IMGDIR} - find . |cpio -o -H newc |$COMPR > ${IMGFILE} + chmod 0755 ${MYIMGDIR} + find . |cpio -o -H newc |$COMPR > ${MYIMGFILE} fi - cd - 1>/dev/null # End of 'cd ${IMGDIR}' + cd - 1>/dev/null # End of 'cd ${MYIMGDIR}' } # End of update_initrd() # Accept either a kernelimage or a packagename, # and return the path to a kernelimage: -getpath_kernelimg () { +function getpath_kernelimg () { local MYDATA="${*}" - [ -z "${MYDATA}" ] && echo "" - if [ -n "$(file "${MYDATA}" |grep -E 'x86 boot (executable|sector)')" ]; then + if [ -z "${MYDATA}" ]; then + echo "" + return + elif [ -n "$(file "${MYDATA}" |grep -E 'x86 boot (executable|sector)')" ]; then # We have a kernel image: echo "${MYDATA}" else @@ -505,38 +781,48 @@ getpath_kernelimg () { # Accept either a directory containing module tree, or a packagename, # and return the path to a module tree: -getpath_kernelmods () { +function getpath_kernelmods () { local MYDATA="${*}" - [ -z "${MYDATA}" ] && echo "" + local MYKVER - if [ -d "${MYDATA}" ]; then + if [ -z "${MYDATA}" ]; then + echo "" + return + elif [ -d "${MYDATA}" ]; then # We have directory, assume it contains the kernel modules: - echo "${MYDATA}" + MYKVER=$(strings $(find ${MYDATA}/kernel/ -name "*.ko*" |head -1) |grep ^vermagic |cut -d= -f2 |cut -d' ' -f1) + if [ -z "${MYKVER}" ]; then + echo "*** Could not determine new kernel version from module directory!" + cleanup + exit 1 + fi + mkdir -p ${KERDIR}/lib/modules/${MYKVER} + rsync -a ${MYDATA}/ ${KERDIR}/lib/modules/${MYKVER}/ 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 + cd ${KERDIR}/lib/modules/* + pwd } # End of getpath_kernelmods # Determine size of a mounted partition (in MB): -get_part_mb_size() { +function 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() { +function 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. +# Parse a liveslak template file and substitute the placeholders. +function parse_template() { local INFILE="$1" local OUTFILE="$2" @@ -587,6 +873,10 @@ while [ ! -z "$1" ]; do show_devices exit ;; + -e|--examples) + showexamples + exit + ;; -h|--help) showhelp exit @@ -631,6 +921,18 @@ while [ ! -z "$1" ]; do WAIT="$2" shift 2 ;; + -N|--nolivemods) + NOLIVEMODS=1 + shift + ;; + -x|--extend) + EXTENSION="$2" + shift 2 + ;; + -X|--extendsize) + INCSIZE="$2" + shift 2 + ;; *) echo "*** Unknown parameter '$1'!" exit 1 @@ -651,8 +953,8 @@ fi # 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) + echo "--- Waiting ${SCANWAIT} seconds for a USB stick to be inserted..." + TARGET=$(scan_devices ${SCANWAIT}) if [ -z "$TARGET" ]; then echo "*** No new USB device detected during $SCANWAIT seconds scan." exit 1 @@ -661,6 +963,7 @@ if [ -z "$TARGET" ]; then fi else echo "*** You must specify the Live USB devicename (option '-o')!" + echo "*** Alternatively, let the script scan for insertion (option '-s')!" exit 1 fi elif [ $SCAN -eq 1 ]; then @@ -712,7 +1015,6 @@ else KVER=$(strings $(find ${KMODDIR}/kernel/ -name "*.ko*" |head -1) |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 @@ -726,7 +1028,16 @@ if [ -n "${LIVEINIT}" -a ! -f "${LIVEINIT}" ]; then exit 1 fi -if [ $CHANGES2SXZ -eq 1 ]; then +if [ -n "${EXTENSION}" ]; then + if [ -z "${INCSIZE}" ]; then + echo "*** LUKS container '${EXTENSION}' defined but no extension size provided!" + echo "*** Not extending encrypted ${EXTENSION}, please use '-X' parameter." + cleanup + exit 1 + fi +fi + +if [ $CHANGES2SXZ -eq 1 ] || [ $UPKERNEL -eq 1 ]; then # We need to create a module, so add squashfs to the required tools: REQTOOLS="${REQTOOLS} mksquashfs" fi @@ -739,9 +1050,9 @@ for PROGN in ${REQTOOLS} ; do fi done if [ ! -z "$PROG_MISSING" ] ; then - echo "-- Required program(s) not found in search path '$PATH'!" + echo "--- Required program(s) not found in search path '$PATH'!" echo -e ${PROG_MISSING} - echo "-- Exiting." + echo "--- Exiting." cleanup exit 1 fi @@ -766,7 +1077,7 @@ echo q |gdisk -l $TARGET 2>/dev/null | \ # 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 +if [[ $WAIT -lt 0 && $UPKERNEL -ne 1 && $RESTORE -ne 1 && $NETSUPPORT -ne 1 && $LIVEINIT = "" && $CHANGES2SXZ -ne 1 && $EXTENSION = "" ]]; then cleanup exit 0 else @@ -786,15 +1097,19 @@ TARGETP1=$(fdisk -l $TARGET |grep ^$TARGET |cut -d' ' -f1 |grep -E '[^0-9]1$') TARGETP2=$(fdisk -l $TARGET |grep ^$TARGET |cut -d' ' -f1 |grep -E '[^0-9]2$') TARGETP3=$(fdisk -l $TARGET |grep ^$TARGET |cut -d' ' -f1 |grep -E '[^0-9]3$') -# 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 +# Normalize filepath: +if [ -f "${EXTENSION}" ]; then + # Container is an actual file, so where are we mounted? + EXTPART=$(cd "$(dirname "${EXTENSION}")" ; df --output=source . |tail -1) + EXTMNT=$(cd "$(dirname "${EXTENSION}")" ; df --output=target . |tail -1) + if [ "${EXTPART}" == "${TARGETP3}" ]; then + # User already mounted the USB linux partition; remove mountpoint: + EXTENSION="${EXTENSION#$EXTMNT}" + fi +elif [ "$(dirname ${EXTENSION})" == "." ]; then + # Containerfile was provided without leading slash, add one: + EXTENSION="/${EXTENSION}" fi -chmod 711 $IMGDIR # Create temporary mount point for the USB device: mkdir -p /mnt @@ -832,13 +1147,27 @@ EFIPFREE=$(get_part_mb_free ${EFIMNT}) # Record the Slackware Live version: OLDVERSION="$(cat ${USBMNT}/.isoversion 2>/dev/null)" -echo "-- The medium '${TARGET}' contains '${OLDVERSION}'" +echo "--- The medium '${TARGET}' contains '${OLDVERSION}'" + +# Try a write to the partition: +if touch ${USBMNT}/.rwtest 2>/dev/null && rm ${USBMNT}/.rwtest 2>/dev/null +then + echo "--- The partition '${TARGETP3}' is writable." +else + echo "--- Trying to remount readonly partition '${TARGETP3}' as writable..." + mount -o remount,rw ${USBMNT} + if [ $? -ne 0 ]; then + echo "*** Failed to remount '${TARGETP3}' writable, unable to continue!" + cleanup + exit 1 + fi +fi # 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" + 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 @@ -853,10 +1182,10 @@ 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} +IMGDIR="$( extract_initrd ${USBMNT}/boot/initrd.img )" +read_initrddir ${IMGDIR} "DEF_KBD DEF_LOCALE DEF_TZ DISTRO LIVE_HOSTNAME LIVEMAIN LIVEUID MARKER MEDIALABEL PERSISTENCE CORE2RAMMODS SQ_EXT_AVAIL VERSION" -# The read_initrd routine will set SUPPORTED to '0' +# The read_initrddir 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 @@ -883,14 +1212,27 @@ if [ $KBACKUP -eq 1 ]; then fi # Update the initrd with regard to USB wait time, liveinit, kernel: -update_initrd ${USBMNT}/boot/initrd.img +update_initrd ${USBMNT}/boot/initrd.img ${IMGDIR} + +# Add the new modules as a squashfs module: +if [ $UPKERNEL -eq 1 ] && [ $NOLIVEMODS -eq 0 ]; then + LIVE_MOD_SYS=$(dirname $(find ${USBMNT} -name "0099-${DISTRO}_zzzconf*.sxz" |head -1)) + LIVE_MOD_ADD=$(dirname ${LIVE_MOD_SYS})/addons + MODNAME="0100-${DISTRO}_kernelmodules_${KVER}.sxz" + echo "--- Creating kernelmodules addon live module '${MODNAME}'" + rm -f ${LIVE_MOD_ADD}/${MODNAME} + mksquashfs ${KERDIR} ${LIVE_MOD_ADD}/${MODNAME} -e boot -noappend -comp xz -b 1M + unset LIVE_MOD_SYS LIVE_MOD_ADD MODNAME +fi # 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" + echo "--- Backing up ${KIMG} to ${USBMNT}/boot/$(basename \"${KIMG}\").prev" + else + echo "--- Backing up old kernel" fi mv "${KIMG}" ${USBMNT}/boot/$(basename "${KIMG}").prev else @@ -898,15 +1240,21 @@ if [ $UPKERNEL -eq 1 ]; then 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}\")" + echo "--- Copying \"${KERNEL}\" to ${USBMNT}/boot/$(basename \"${KIMG}\")" + else + echo "--- Adding new kernel" 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}" + echo "--- Restoring ${USBMNT}/boot/$(basename \"${KIMG}\").prev to ${KIMG}" + else + echo "--- Restoring old kernel" fi + OLDKVER=$(file "${KIMG}" |sed 's/^.*\(version [^ ]* \).*$/\1/' |cut -d' ' -f2) rm -f "${KIMG}" mv ${USBMNT}/boot/$(basename "${KIMG}").prev "${KIMG}" + echo "--- You may remove obsolete 'addons/0100-${DISTRO}_kernelmodules_${OLDKVER}.sxz' module" fi if [ $EFIBOOT -eq 1 ]; then @@ -936,12 +1284,24 @@ if [ $CHANGES2SXZ -eq 1 ]; then 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}'" + 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 +# Should we extend the size of a container? +if [ -n "${EXTENSION}" ]; then + if [ "$(basename ${EXTENSION} ${CNTEXT})" == "$(basename ${EXTENSION})" ]; + then + echo "*** File '${EXTENSION}' does not have an '${CNTEXT}' extension!" + cleanup + exit 1 + fi + # Expand existing container file: + expand_container ${TARGETP3} ${INCSIZE} ${USBMNT}/${EXTENSION} +fi + # Unmount/remove stuff: cleanup |