From 3d9ba231c8fc58a1226c52d14fe500cdb409e6aa Mon Sep 17 00:00:00 2001 From: Eric Hameleers Date: Wed, 15 Jun 2016 11:03:54 +0200 Subject: iso2usb.sh: added 'refresh' parameter to update an existing Live USB stick. -r|--refresh => Refresh an existing Live USB stick with new ISO content. The refresh option "-r" can be used when you have a Live USB stick and you want to update the liveslak files with new versions on an ISO image file which you downloaded/created. The USB stick will not be formatted in this case, and user modifications like LUKS-encrypted homedirectory or persistence data will not be touched. The "system" squashfs modules will be replaced with the versions on the ISO file and any squashfs module not present in the system/ directory of the ISO will be deleted. The "optional" and "addons" directories are treated a bit differently: The files in there that you added yourself will not be deleted when the content of these directories is refreshed with the content from the ISO (unless of course your added files have the same name as one of the files in the ISO). The content of the /boot and /EFI directories will both be replaced with whatever is on the ISO image. --- iso2usb.sh | 267 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 171 insertions(+), 96 deletions(-) (limited to 'iso2usb.sh') diff --git a/iso2usb.sh b/iso2usb.sh index e23e670..4228c56 100644 --- a/iso2usb.sh +++ b/iso2usb.sh @@ -39,13 +39,21 @@ UNATTENDED=0 # By default do not show file operations in detail: VERBOSE=0 +# Variables to store content from an initrd we are going to refresh: +OLDWAIT="" +OLDLUKS="" + # Seconds to add to the initrd as wait-for-root value: WAIT=5 # No LUKS encryption by default: DOLUKS=0 +# We are NOT refreshing existing Live content by default: +REFRESH=0 + # Initialize more variables: +CNTBASE="" CNTDEV="" CNTFILE="" LUKSHOME="" @@ -53,7 +61,6 @@ LODEV="" # Define ahead of time, so that cleanup knows about them: IMGDIR="" -EFIMNT="" ISOMNT="" CNTMNT="" USBMNT="" @@ -73,7 +80,7 @@ cleanup() { # During cleanup, do not abort due to non-zero exit code: set +e sync - if [ $DOLUKS -eq 1 ]; then + if [ $DOLUKS -eq 1 -a -n "$CNTDEV" ]; then # In case of failure, only the most recent device should still be open: if mount |grep -q ${CNTDEV} ; then umount -f ${CNTDEV} @@ -81,7 +88,6 @@ cleanup() { losetup -d ${LODEV} fi fi - [ -n "${EFIMNT}" ] && ( /sbin/umount -f ${EFIMNT} 2>/dev/null; rmdir $EFIMNT ) [ -n "${ISOMNT}" ] && ( /sbin/umount -f ${ISOMNT} 2>/dev/null; rmdir $ISOMNT ) [ -n "${CNTMNT}" ] && ( /sbin/umount -f ${CNTMNT} 2>/dev/null; rmdir $CNTMNT ) [ -n "${USBMNT}" ] && ( /sbin/umount -f ${USBMNT} 2>/dev/null; rmdir $USBMNT ) @@ -110,6 +116,8 @@ cat < Full path to the ISO image file. # -o|--outdev The device name of your USB drive. # -p|--persistence Custom name of the 'persistence' directory. +# -r|--refresh Refresh the USB stick with the ISO content. +# No formatting, do not touch user content. # -u|--unattended Do not ask any questions. # -v|--verbose Show verbose messages. # -w|--wait Add seconds wait time to initialize USB. @@ -136,14 +144,21 @@ uncompressfs () { fi } +# Read configuration data from old initrd: +read_initrd() { + IMGFILE="$1" + + OLDWAIT=$(uncompressfs ${IMGFILE} |cpio -i --to-stdout wait-for-root 2>/dev/null) + OLDLUKS=$(uncompressfs ${IMGFILE} |cpio -i --to-stdout luksdev 2>/dev/null) +} + # Add longer USB WAIT to the initrd: update_initrd() { IMGFILE="$1" # USB boot medium needs a few seconds boot delay else the overlay will fail. # Check if we need to update the wait-for-root file in the initrd: - OLDWAIT=$(uncompressfs ${IMGFILE} |cpio -i --to-stdout wait-for-root 2>/dev/null) - if [ "$OLDWAIT" = "$WAIT" -a $DOLUKS -eq 0 ]; then + if [ "$OLDWAIT" = "$WAIT" -a $DOLUKS -eq 0 -a $REFRESH -eq 0 ]; then return fi @@ -162,7 +177,15 @@ update_initrd() { cd ${IMGDIR} uncompressfs ${IMGFILE} \ | cpio -i -d -H newc --no-absolute-filenames - echo "--- Updating 'waitforroot' time from '$OLDWAIT' to '$WAIT':" + + if [ $REFRESH -eq 1 ]; then + echo "--- Refreshing Slackware initrd..." + WAIT="$OLDWAIT" + echo "$OLDLUKS" >> luksdev + else + echo "--- Updating 'waitforroot' time from '$OLDWAIT' to '$WAIT':" + fi + echo ${WAIT} > wait-for-root if [ $DOLUKS -eq 1 -a -n "${LUKSHOME}" ]; then @@ -187,6 +210,14 @@ create_container() { CNTENCR=$4 # 'none' or 'luks' CNTUSED=$5 # '/home' or 'persistence' + # Create a container file or re-use previously created one: + if [ -f $USBMNT/${CNTBASE}.img ]; then + CNTFILE="${CNTBASE}.img" + CNTSIZE=$(( $(du -sk ${CNTFILE}) / 1024 )) + echo "--- Keeping existing '${CNTFILE}' (size ${CNTSIZE} MB)." + return + fi + # Determine size of the target partition (in MB), and the free space: PARTSIZE=$(df -P -BM ${CNTPART} |tail -1 |tr -s '\t' ' ' |cut -d' ' -f2) PARTSIZE=${PARTSIZE%M} @@ -221,23 +252,10 @@ create_container() { exit 1 fi - # Create an empty container file (re-use previously created one): - if [ -f $USBMNT/${CNTBASE}.img ]; then - CNTFILE="${CNTBASE}.img" - CNTSIZE=$(( $(du -sk ${CNTFILE}) / 1024 )) - if [ $UNATTENDED -eq 0 ]; then - echo "*** File '${CNTFILE}' already exists (size ${CNTSIZE} MB). ***" - echo "*** If you do not want to re-use it for '$CNTUSED', ***" - echo "*** then press CONTROL-C now and rename that file! ***" - read -p "Else press ENTER to continue: " JUNK - # OK... the user was sure about the file... - fi - else - echo "--- Creating ${CNTSIZE} MB container file using 'dd if=/dev/urandom', patience please..." - CNTFILE="${CNTBASE}.img" - # Create a sparse file (not allocating any space yet): - dd of=$USBMNT/${CNTFILE} bs=1M count=0 seek=$CNTSIZE - fi + echo "--- Creating ${CNTSIZE} MB container file using 'dd if=/dev/urandom', patience please..." + CNTFILE="${CNTBASE}.img" + # Create a sparse file (not allocating any space yet): + dd of=$USBMNT/${CNTFILE} bs=1M count=0 seek=$CNTSIZE # Setup a loopback device that we can use with cryptsetup: LODEV=$(losetup -f) @@ -329,6 +347,10 @@ while [ ! -z "$1" ]; do PERSISTENCE="$2" shift 2 ;; + -r|--refresh) + REFRESH=1 + shift + ;; -u|--unattended) UNATTENDED=1 shift @@ -371,7 +393,7 @@ if [ -z "$TARGET" -o -z "$SLISO" ]; then exit 1 fi -if [ ! -f $SLISO -a $FORCE -eq 0 ]; then +if [ $FORCE -eq 0 -a ! -f $SLISO ]; then echo "*** This is not a useable file: '$SLISO' !" exit 1 fi @@ -398,70 +420,86 @@ if [ ! -z "$PROG_MISSING" ] ; then exit 1 fi -# Confirm wipe: -cat </dev/null | while read LINE ; do echo "# $LINE" ; done -if [ $UNATTENDED -eq 0 ]; then - cat </dev/null | \ + while read LINE ; do echo "# $LINE" ; done + + if [ $UNATTENDED -eq 0 ]; then + cat </dev/null |grep EFI |tr -s ' ' | cut -d' ' -f 2) -if [ -n "$EFIOFFSET" ]; then - # Mount the EFI partition so we can retrieve the EFI bootloader: - /sbin/mount -o loop,offset=$((512*$EFIOFFSET)) ${SLISO} ${EFIMNT} - if [ ! -f ${EFIMNT}/EFI/BOOT/boot*.efi ]; then - 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 -fi - -# Create a temporary mount point for the USB device: -mkdir -p /mnt +# USB mount: USBMNT=$(mktemp -d -p /mnt -t alienusb.XXXXXX) if [ ! -d $USBMNT ]; then echo "*** Failed to create a temporary mount point for the USB device!" @@ -502,18 +524,46 @@ fi # Loop-mount the ISO (or 1st partition if this is a hybrid ISO): /sbin/mount -o loop ${SLISO} ${ISOMNT} +# Find out if the ISO contains an EFI bootloader and use it: +if [ ! -f ${ISOMNT}/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 + +if [ $REFRESH -eq 0 ]; then + # Collect data from the ISO initrd: + read_initrd ${ISOMNT}/boot/initrd.img +else + # Collect data from the USB initrd: + read_initrd ${USBMNT}/boot/initrd.img +fi + # Copy the ISO content into the USB Linux partition: echo "--- Copying files from ISO to USB... takes some time." if [ $VERBOSE -eq 1 ]; then # Show verbose progress: - rsync -av --progress --exclude=EFI ${ISOMNT}/* ${USBMNT}/ + rsync -rlptD -v --progress --exclude=EFI ${ISOMNT}/* ${USBMNT}/ elif [ -z "$(rsync --info=progress2 2>&1 |grep "unknown option")" ]; then # Use recent rsync to display some progress because this can take _long_ : - rsync -a --no-inc-recursive --info=progress2 --exclude=EFI \ + rsync -rlptD --no-inc-recursive --info=progress2 --exclude=EFI \ ${ISOMNT}/* ${USBMNT}/ else # Remain silent if we have an older rsync: - rsync -a --exclude=EFI ${ISOMNT}/* ${USBMNT}/ + rsync -rlptD --exclude=EFI ${ISOMNT}/* ${USBMNT}/ +fi + +if [ $REFRESH -eq 1 ]; then + # Clean out old Live system data: + echo "--- Cleaning out old Live system data." + LIVEMAIN="$(echo $(find ${ISOMNT} -name "0099*") |rev |cut -d/ -f3 |rev)" + rsync -rlptD --delete \ + ${ISOMNT}/${LIVEMAIN}/system/ ${USBMNT}/${LIVEMAIN}/system/ + chattr -i ${USBMNT}/boot/extlinux/ldlinux.sys 2>/dev/null + rsync -rlptD --delete \ + ${ISOMNT}/boot/ ${USBMNT}/boot/ fi # Write down the version of the ISO image: @@ -528,9 +578,22 @@ if [ $DOLUKS -eq 1 ]; then LUKSHOME=${CNTFILE} fi -# Add more USB WAIT seconds to the initrd: +# Update the initrd with longer USB wait time and LUKS /home info: update_initrd ${USBMNT}/boot/initrd.img +if [ $REFRESH -eq 1 ]; then + # Determine what we need to do with persistence if this is a refresh. + if [ -f ${USBMNT}/${PERSISTENCE}.img ]; then + # If a persistence container exists, we re-use it: + PERSISTTYPE="file" + elif [ -d ${USBMNT}/${PERSISTENCE} -a "${PERSISTTYPE}" = "file" ]; then + # A persistence directory exists but the user wants a container now; + # so we will delete the persistence directory and create a container file + # (sorry persistent data will not be migrated): + rm -rf ${USBMNT}/${PERSISTENCE} + fi +fi + if [ "${PERSISTTYPE}" = "dir" ]; then # Create persistence directory: mkdir -p ${USBMNT}/${PERSISTENCE} @@ -557,7 +620,7 @@ fi echo "--- Making the USB drive '$TARGET' bootable using extlinux..." mv ${USBMNT}/boot/syslinux ${USBMNT}/boot/extlinux mv ${USBMNT}/boot/extlinux/isolinux.cfg ${USBMNT}/boot/extlinux/extlinux.conf -rm ${USBMNT}/boot/extlinux/isolinux.* +rm -f ${USBMNT}/boot/extlinux/isolinux.* /sbin/extlinux --install ${USBMNT}/boot/extlinux # No longer needed: @@ -569,14 +632,26 @@ if [ $EFIBOOT -eq 1 ]; then mkdir -p ${USBMNT}/EFI/BOOT rsync -rlptD ${ISOMNT}/EFI/BOOT/* ${USBMNT}/EFI/BOOT/ mkdir -p ${USBMNT}/boot - rsync -rlptD ${ISOMNT}/boot/* ${USBMNT}/boot/ - # Add more USB WAIT seconds to the initrd: + echo "--- Copying EFI boot files from ISO to USB." + if [ $VERBOSE -eq 1 ]; then + rsync -rlptD -v ${ISOMNT}/boot/* ${USBMNT}/boot/ + else + rsync -rlptD ${ISOMNT}/boot/* ${USBMNT}/boot/ + fi + if [ $REFRESH -eq 1 ]; then + # Clean out old Live system data: + echo "--- Cleaning out old Live system data." + rsync -rlptD --delete \ + ${ISOMNT}/EFI/BOOT/ ${USBMNT}/EFI/BOOT/ + rsync -rlptD --delete \ + ${ISOMNT}/boot/ ${USBMNT}/boot/ + fi + # Update the initrd with longer USB wait time and LUKS container info: update_initrd ${USBMNT}/boot/initrd.img fi # No longer needed: if /sbin/mount |grep -qw ${USBMNT} ; then /sbin/umount ${USBMNT} ; fi -if /sbin/mount |grep -qw ${EFIMNT} ; then /sbin/umount ${EFIMNT} ; fi # Unmount/remove stuff: cleanup -- cgit v1.2.3