diff options
author | Eric Hameleers <alien@slackware.com> | 2016-06-15 11:03:54 +0200 |
---|---|---|
committer | Eric Hameleers <alien@slackware.com> | 2016-06-15 11:03:54 +0200 |
commit | 3d9ba231c8fc58a1226c52d14fe500cdb409e6aa (patch) | |
tree | ab0de2c6da1a896b25bfada06fda7bf2fd6c1a7e /iso2usb.sh | |
parent | dfafdd9c4094a7f987a18a583bb972ac6e71b41e (diff) | |
download | liveslak-3d9ba231c8fc58a1226c52d14fe500cdb409e6aa.tar.gz liveslak-3d9ba231c8fc58a1226c52d14fe500cdb409e6aa.tar.xz |
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.
Diffstat (limited to 'iso2usb.sh')
-rw-r--r-- | iso2usb.sh | 267 |
1 files changed, 171 insertions, 96 deletions
@@ -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 <<EOT # -i|--infile <filename> Full path to the ISO image file. # -o|--outdev <filename> The device name of your USB drive. # -p|--persistence <dirname> 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<number> Add <number> 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 <<EOT +if [ $REFRESH -eq 0 ]; then + # We are creating a USB stick from scratch, + # i.e. not refreshing the Live content. + # Confirm wipe: + cat <<EOT # # We are going to format this device (erase all data) - '$TARGET': +EOT +else + # We are refreshing the Live content. + # Confirm refresh: + cat <<EOT +# +# We are going to refresh the Live OS on this device - '$TARGET': +EOT +fi + # Continue with the common text message: + cat <<EOT # 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 |/sbin/gdisk -l $TARGET 2>/dev/null | while read LINE ; do echo "# $LINE" ; done -if [ $UNATTENDED -eq 0 ]; then - cat <<EOT + echo q |/sbin/gdisk -l $TARGET 2>/dev/null | \ + while read LINE ; do echo "# $LINE" ; done + + if [ $UNATTENDED -eq 0 ]; then + cat <<EOT *** *** *** If this is the wrong drive, then press CONTROL-C now! *** *** *** EOT - read -p "Or press ENTER to continue: " JUNK - # OK... the user was sure about the drive... -fi + read -p "Or press ENTER to continue: " JUNK + # OK... the user was sure about the drive... + fi -# Get the LABEL used for the ISO: -LIVELABEL=$(/sbin/blkid -s LABEL -o value ${SLISO}) - -# Use sgdisk to wipe and then setup the USB device: -# - 1 MB BIOS boot partition -# - 100 MB EFI system partition -# - Let Slackware have the rest -# - Make the Linux partition "legacy BIOS bootable" -# Make sure that there is no MBR nor a partition table anymore: -dd if=/dev/zero of=$TARGET bs=512 count=1 conv=notrunc -# The first sgdisk command is allowed to have non-zero exit code: -/sbin/sgdisk -og $TARGET || true -/sbin/sgdisk \ - -n 1:2048:4095 -c 1:"BIOS Boot Partition" -t 1:ef02 \ - -n 2:4096:208895 -c 2:"EFI System Partition" -t 2:ef00 \ - -n 3:208896:0 -c 3:"Slackware Linux" -t 3:8300 \ - $TARGET -/sbin/sgdisk -A 3:set:2 $TARGET -# Show what we did to the USB stick: -/sbin/sgdisk -p -A 3:show $TARGET - -# Create filesystems: -# Not enough clusters for a 32 bit FAT: -/sbin/mkdosfs -s 2 -n "DOS" ${TARGET}1 -/sbin/mkdosfs -F32 -s 2 -n "EFI" ${TARGET}2 -# KDE tends to automount.. so try an umount: -if /sbin/mount |grep -qw ${TARGET}3 ; then /sbin/umount ${TARGET}3 || true ; fi -/sbin/mkfs.ext4 -F -F -L "${LIVELABEL}" -m 0 ${TARGET}3 -/sbin/tune2fs -c 0 -i 0 ${TARGET}3 - -# Create temporary mount points for the ISO file: +if [ $REFRESH -eq 0 ]; then + # Continue with the wipe/partitioning/formatting. + + # Get the LABEL used for the ISO: + LIVELABEL=$(/sbin/blkid -s LABEL -o value ${SLISO}) + + # Use sgdisk to wipe and then setup the USB device: + # - 1 MB BIOS boot partition + # - 100 MB EFI system partition + # - Let Slackware have the rest + # - Make the Linux partition "legacy BIOS bootable" + # Make sure that there is no MBR nor a partition table anymore: + dd if=/dev/zero of=$TARGET bs=512 count=1 conv=notrunc + # The first sgdisk command is allowed to have non-zero exit code: + /sbin/sgdisk -og $TARGET || true + /sbin/sgdisk \ + -n 1:2048:4095 -c 1:"BIOS Boot Partition" -t 1:ef02 \ + -n 2:4096:208895 -c 2:"EFI System Partition" -t 2:ef00 \ + -n 3:208896:0 -c 3:"Slackware Linux" -t 3:8300 \ + $TARGET + /sbin/sgdisk -A 3:set:2 $TARGET + # Show what we did to the USB stick: + /sbin/sgdisk -p -A 3:show $TARGET + + # Create filesystems: + # Not enough clusters for a 32 bit FAT: + /sbin/mkdosfs -s 2 -n "DOS" ${TARGET}1 + /sbin/mkdosfs -F32 -s 2 -n "EFI" ${TARGET}2 + # KDE tends to automount.. so try an umount: + if /sbin/mount |grep -qw ${TARGET}3 ; then + /sbin/umount ${TARGET}3 || true + fi + /sbin/mkfs.ext4 -F -F -L "${LIVELABEL}" -m 0 ${TARGET}3 + /sbin/tune2fs -c 0 -i 0 ${TARGET}3 + +fi # End [ $REFRESH -eq 0 ] + +# Create temporary mount points for the ISO file and USB device: mkdir -p /mnt -EFIMNT=$(mktemp -d -p /mnt -t alienefi.XXXXXX) -if [ ! -d $EFIMNT ]; then - echo "*** Failed to create a temporary mount point for the ISO!" - cleanup - exit 1 -else - chmod 711 $EFIMNT -fi +# ISO mount: ISOMNT=$(mktemp -d -p /mnt -t alieniso.XXXXXX) if [ ! -d $ISOMNT ]; then echo "*** Failed to create a temporary mount point for the ISO!" @@ -470,23 +508,7 @@ if [ ! -d $ISOMNT ]; then else chmod 711 $ISOMNT fi - -# Find out if the ISO contains an EFI bootloader and use it: -EFIBOOT=0 -EFIOFFSET=$(/sbin/fdisk -lu ${SLISO} 2>/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 |