#!/bin/bash set +o posix shopt -s extglob ########################################################################################### # Script : inst_dskimg-aio.build # Purpose: Build All-in-One Slackware Installer disc images. # These disc images that contain the bootable Slackware Installer with the # packages bundled on a dedicated partition) Slackware Installer images. # Author : Stuart Winter # Version: 1.01 # Date...: 01-Apr-2025 ########################################################################################### # # Copyright 2022-2025 Stuart Winter, Earth, Milky Way, "". # 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. ########################################################################################### # Usage: # Without options, this script will use the settings configured from within the # Slackware ARM Development kit 'slackkit' to locate the required assets. # If you want to build A-i-O images from test builds using the 'build_test_kernels.sh' # script within 'source/k', # $ inst_dskimg-aio.build -s /tmp/SLKtestbuilds/publish/experimental/bootware/installer -d /tmp/SLKtestbuilds/aio # Write A-i-O images to the SD card: # $ time dd if=aio.img of=/dev/XX bs=4M iflag=fullblock ########################################################################################### # Changelog # Version: 1.00, 03-Dec-2022 # Created. # Version: 1.01, 01-Apr-2025 # Symlink creation has been removed to simplify the build process for non-SD card images. # Symlinks were unnecessary, as the Hardware Model Installation Guides refer to the images # without specifying the exact image version—making it unclear which version was actually # used. It was a good idea initially though ;-) # Compress the images natively on ARM, since the primary builder is 16 core, 32GB RAM # and more powerful than the x86_64! ########################################################################################### # Load the Slackware ARM development kit: source /usr/share/slackdev/buildkit.sh # Settings PROGNAME="inst_dskimg-aio.build" VERSION="1.01" # Location of public versions of the Slackware tree. These trees have all of the # packages signed and tag files. # We'll find $SLACKREL within this directory. # This is configured within the Slackware ARM development kit: #SLACKPUBTREEDIR=/mnt/prisroot/devel/armedslack-distrib/slackwarearm/ # Default source and destination base paths. Note that you still need to specify # the version of Slackware using -r/--release to select which directory: #SRCDIR=$SLACKPLATFORMDIR/bootware/installer/ # We'll use the public tree otherwise if we build the A-i-O Installers prior to creating # the public tree, we can end up with the most recent Kernel and Installer, but with an # older Kernel package installed into the OS, which causes os-initrd-mgr to (gracefully) # fail. SRCDIR=$SLACKPUBTREEDIR/platform/$SLKPORTARCH/bootware/installer/ #DESTDIR=$SLACKPLATFORMDIR/bootware/installer-aio/ # The A-i-O images will be written directly to the public tree as there's no # need to have 2 copies of the same thing, and due to the workflow these will # be handled after the public tree has been created, and will be pushed separately. DESTDIR=$SLACKPUBTREEDIR/platform/$SLKPORTARCH/bootware/installer-aio/ # We'll default to -current: SLACKREL=slackware${SLKPORTARCH}-current ########################################################################################### # Functions ########################################################################################### function display_usage () { printf "Usage: ${PROGNAME} [options]\n" [ ! -z "$1" ] && { echo "Use $( basename $0 ) --help for a list of options" ;} } function display_help () { #printf "${VERSION}\n\n$( display_usage ) printf "$( display_usage ) Options: -h, --help Output these options. -s, --srcdir Directory containing regular Slackware Installer disc images. [ default: $SRCDIR ] -d, --destdir Directory to store the All-in-One Installer images. [ default: $DESTDIR ] -p, --pubtree Directory that contains the public versions of the Slackware trees. The Slackware packages will be copied from here. -r, --release Specify the Slackware release directory name that will be picked from the source directory, and created within the destination directory. This directory name will also be used to locate the Slackware packages (set by -p) that will be copied to the All-in-One partition on the disc image. [ default: $SLACKREL ] -H, --hack Pause before umounting the A-i-O image to enable manual editing. " } # Determine the compression type for the Installer image: # $1 = compressed img file name # $2 = file name to decompress the img into function unpackimg() { local file_in="$1" local file_out="$2" local comp_type local file_type=$(file -L "${file_in}") # Map the compression type (as discovered by 'file -L') to # its decompression tool: declare -A decompress_cmds=( ["XZ"]="xz -dc" ["bzip2"]="bzip2 -dc" ["gzip"]="gzip -dc" ) # Determine which decompression command to use: for comp_type in "${!decompress_cmds[@]}"; do if [[ "${file_type}" == *"${comp_type} compressed data"* ]]; then echo "Extracting ${file_in} using ${decompress_cmds[${comp_type}]}" ${decompress_cmds[${comp_type}]} "$file_in" > "${file_out}" || return 1 return fi done echo "No matching decompression tool found for $file" exit 1 } ########################################################################################### # Main logic ########################################################################################### # Set up temp dir: TMPDIR="$(mktemp -d /tmp/SLKins_aio.XXXXXX)" # Collect parameters: PARAMS="$( getopt -qn "$( basename $0 )" -o Hhs:d:r:p: -l hack,help,srcdir:,destdir:,release:,pubtree: -- "$@" )" # If params are incorrect then display help: [ $? -gt 0 ] && { display_help ; exit 2 ;} eval set -- "${PARAMS}" for param in $*; do case "$param" in -d|--destdir) DESTDIR="$2" shift 2;; -s|--srcdir) SRCDIR="$2" shift 2;; -r|--release) SLACKREL="$2" shift 2;; -p|--pubtree) SLACKPUBTREEDIR="$2" shift 2;; -h|--help) display_help exit ;; -H|--hack) HACKING=Yes shift 1 ;; --) shift; break;; esac done # Sanity check: [ ! -d "$SRCDIR/$SLACKREL" ] && { echo "Error: Installer source $SRCDIR directory not found" ; exit 1 ;} [ ! -d "$DESTDIR" ] && { echo "Error: Destination directory $DESTDIR not found" ; exit 1 ;} # Slackware ARM uses 'slackware' (not 'slackware64') for both 32 and 64bit. [ ! -d "$SLACKPUBTREEDIR/$SLACKREL/slackware" ] && { echo "Error: Slackware public tree $SLACKPUBTREEDIR not found" ; exit 1 ;} echo "Slackware release...............: $SLACKREL" echo "Installer source directory......: $SRCDIR" echo "Slackware public tree directory : $SLACKPUBTREEDIR/$SLACKREL" echo "A-i-O destination directory.....: $DESTDIR" echo "Temporary working directory.....: $TMPDIR" # Set up the target directory: mkdir -pm755 $DESTDIR/$SLACKREL # If it already existed, empty it of anything other than any README's: #rm -fv $DESTDIR/$SLACKREL/!(*README*) 2> /dev/null # We now have ISOs, so let's restrict our destruction to 'img' files # We wipe any image and its associated sig and md5 prior to moving it from the working space # into the destination directory, so let's not wipe anything up front. #rm -fv $DESTDIR/$SLACKREL/*.img* 2> /dev/null # For Slackware stable releases and -current AiO Installers we don't keep the kernel version in the file name # since it's superfluous: The Kernel within /boot and the Kernel package you'll install are bundled in so # they'll always align. # The reason why the 'naked' Installers (those without the packages bundled into the disc images) contain # the Kernel version is so that you can ensure you align it with the Kernel packages. # Rename: bcm2711_rpi4-sdimg_5.19.16_1.img.xz to bcm2711_rpi4 - lop off everything after sdimg # -current output file name: bcm2711_rpi4-aio-slackwareaarch64-current_25Nov2022.img # Stable Release file name : bcm2711_rpi4-aio-15.1.img # # No longer - it's unnecessary. See info about the symlinks - it proved superfluous. #[[ "$SLACKREL" =~ (-current) ]] && imgsuffix="_$( date "+%d%h%Y" )" # Enter the directory in which the 'bare' Slackware Installer disc images live: cd $SRCDIR/$SLACKREL || exit 1 # Walk the source directory and unpack each image into the temporary dir: #find . -type f -name '*.img.??*' -not -name '*.asc' -printf "%f\n" | while read instimg ; do find . -type f -regex '.*\.img\.\(xz\|bz2\)$' -not -name '*.asc' -printf "%f\n" | while read instimg ; do # Assemble the AiO image file name: outimg=${instimg%%-*}-aio-${SLACKREL}${imgsuffix}.img # Unpack the compressed image: echo "Unpacking $instimg -> $outimg ..." #xzcat $instimg > $TMPDIR/$outimg unpackimg $instimg $TMPDIR/$outimg || exit 1 # If we're working with -current we'll symlink it to the dated version: # This is to help with documentation. # Note: No longer doing this - it complicates the build process and # achieves nothing, since the Installation Guide instructions download # via the symlink, so we never know which version they obtained! # It was a good idea originally though ;-) #[[ "$SLACKREL" =~ (-current) ]] && { # bcm2711_rpi4-aio-slackwareaarch64-current.img -> bcm2711_rpi4-aio-slackwareaarch64-current_25Nov2022.img #ln -rfs $DESTDIR/$SLACKREL/$outimg $DESTDIR/$SLACKREL/${instimg%%-*}-aio-${SLACKREL}.img ;} done # Re-set up symlinks. This is to help with Hardware Models such as the RPi3 where we use a generic # image for both the RPi3 & 4, and symlink to it for documentation purposes. ### # No longer creating symlinks - see reasoning above. ## ### # # Enter the directory in which the 'bare' Slackware Installer disc images live: cd $SRCDIR/$SLACKREL || exit 1 #find . -name '*.img*' -not -name '*.asc' -type l -printf "lnktgt=%f lnkdst=%l\n" | while read imgsymlink ; do # eval $imgsymlink # if [ "${lnktgt%%.*}" != "${lnkdst%%-*}" ]; then # # If first part of file name != 2nd part, make symlink. # # e.g. if 'bcm2837_rpi3' != bcm2711_rpi4 # # -current........: this would be a symlink pointing to a symlink (apart from see note below re. relative symlinks). # # Symlink output: bcm2711_rpi3-aio-slackwareaarch64-current.img -> bcm2711_rpi4-aio-slackwareaarch64-current.img # # Stable releases : symlink direct to image file. # # Symlink output: bcm2711_rpi3-aio-slackwareaarch64-15.1.img -> bcm2711_rpi4-aio-slackwareaarch64-15.1.img # # Using 'relative' symlinks causes 'ln' to collapse the symlink chain so that we're not # # pointing a symlink to a symlink (contrary to the expected design noted above). # # This of course is preferable. # ln -rfs $DESTDIR/$SLACKREL/${lnkdst%%-*}-aio-${SLACKREL}.img $DESTDIR/$SLACKREL/${lnktgt%%.*}-aio-${SLACKREL}.img # fi #done # Set up base symlinks to help with documentation so that we can reference # installer-aio/slackwareaarch64-current/rk3399_generic.img.xz # For each Hardware Model, its Slackware bare installer images has a symlink of '_latest' which points # to the file that bares its creation date, so we'll take each symlink (which includes the Rpi3 that utilises # the named RPi4 image via symlinks). # Not creating symlinks - see above. #find . -not -name '*.asc' -name '*.img*' -name '*_latest*' -type l -printf "lnktgt=%f lnkdst=%l\n" | while read imgsymlink ; do # eval $imgsymlink # # rk3399_generic.img -> rk3399_generic-aio-slackwareaarch64-current_25Nov2022.img # # [ resolved from rk3399_generic-aio-slackwareaarch64-current.img ] # ln -rfs $DESTDIR/$SLACKREL/${lnkdst%%-*}-aio-${SLACKREL}.img $DESTDIR/$SLACKREL/${lnktgt%%.*}.img #done # Walk the uncompressed bare Installer images for each Hardware Model and convert them into # All-in-One Installer disc images: cd $TMPDIR find . -mindepth 1 -maxdepth 1 -type f -name '*.img' -printf "%f\n" | while read imgfile; do echo "Processing bare Installer image: $imgfile" # Increase the image file size to 13G so that it fits on the 16GB minimum required # size in the docs: fallocate -l 13G $imgfile # Add it as a device and find out where it's gone (probably /dev/loop0): devloc=$( losetup -f --show $imgfile ) echo "Image file device location: $devloc" # Wait a moment for the devices to settle/appear: sync # Add the partition for the Slackware installation media of minimum size 5GB and # let it fill the rest of the available space on the image file (that's what the 100% does). # This will create a larger partition, increasing it up to the max of the 13GB image file. # The Slackware tree weighs in at just over 5GB. When mounted on the target Hardware Model: # rk3399_generic: /dev/mmcblk1p2 5.2G 4.0G 940.6M 81% /p # rpi: /dev/mmcblk1p3 5.2G 4.0G 940.6M 81% /4 parted -fs ${devloc} "mkpart primary ext4 5G 100%" # "Fix" any errors: parted -fs ${devloc} # As we created these Slackware Installer images, we know that the last partition # is the one we just created so we don't need to do any sanity checking here. media_partition=$( fdisk -l $devloc | grep '^/dev' | tail -n1 | awk '{print $1}' ) echo "Partition: ${media_partition}" # Wait a moment for the devices to settle/appear: sync sleep 1 # Create file system: mkfs.ext4 -O64bit ${media_partition} || { echo "Error: Unable to create file system" ; exit 1 ;} # Label it. This is read by /usr/lib/setup/INS-all-in-one within the Slackware Installer # and is used to confirm we've found the correct partition: e2label ${media_partition} SLKins_aio-pkgs || { echo "Error: Unable to label partition" ; exit 1 ;} # Mount the file system on which the Slackware Installation Media will live: echo "Mounting A-i-O image filesystem" mkdir -pm755 $TMPDIR/imgmnt mount -v ${media_partition} $TMPDIR/imgmnt || { echo "Error: Unable to mount file system" ; exit 1 ;} # The Slackware media lives within the 'slackware' directory within the root of the file system. mkdir -pm755 $TMPDIR/imgmnt/slackware # The Slackware tree bundled is identified in this file. This file is read by # /usr/lib/setup/INS-all-in-one within the Slackware Installer to identify which # Slackware release/tree is in play for this particular A-i-O image: echo "${SLACKREL}/slackware" > $TMPDIR/imgmnt/slackware/.slktree # Copy Slackware tree. We'll include /extra even though it won't be considered by the # Slackware Installer; it's just so that the user has it available if needed for # subsequent installation. rsync -PavL \ --exclude '*/source' \ --exclude '*/installer' \ $SLACKPUBTREEDIR/$SLACKREL \ $TMPDIR/imgmnt/slackware/ # Pause to enable hacking: [ "$HACKING" = "Yes" ] && { echo "Pausing to enable manual hacking." echo "The mounted tree is: $TMPDIR/imgmnt" read -p "Press ENTER to continue" ;} # Let the users know what this is when they find it later: cat << 'EOF' > $TMPDIR/imgmnt/README.txt This file system contains the Slackware repository that is used during the installation of Slackware. Once you've booted into your OS you can delete or change this partition if you wish, or perhaps you might like to retain it for future reference. EOF # umount the file system: umount $TMPDIR/imgmnt || { echo "Error: unable to umount disc file system" ; exit 1 ;} # fsck so it's clean when mounted within the Slackware Installer: fsck -yf ${media_partition} || { echo "Failed to fsck" ; exit 1 ;} echo "Detaching loopback image" losetup -vd ${devloc} || { echo "Error: Unable to umount loopback image" ; exit 1 ;} # Compress: # This will be performed on the x86_64 platform from the distribution polishing scripts. # The symlinks will also be corrected, and the images GPG signed. #xz --threads $(( $(nproc) -1 )) -vzef9 export XZ_OPTS="--threads=0 -vze9f -C crc32" echo "Compressing ${imgfile}..." time xz $imgfile # Generate an MD5 sum: # We'll use globbing here to support different compression formats going forward, # as $imgfile no longer holds the exact filename—it now includes a .xz suffix. echo "Generating MD5 sum of ${imgfile}" openssl md5 -r ${imgfile}* | awk '{print $1}' > $( echo ${imgfile}* ).md5 # Sanity check it's not larger than 12Gbytes. # The images are presently 10737418240 bytes (10GB): # This is superfluous because the image files can only be a certain size # otherwise rsync fails to copy the data, since the image is a fixed size. #[ $( stat -c %s $imgfile ) -gt 12737418240 ] && { echo "Error: $imgfile larger than expected" ; exit 1; } # Remove any existing compressed image file of this name and its accompanying GPG signature # and md5 sum: rm -fv $DESTDIR/$SLACKREL/${imgfile}.* # Move image into place within the specified A-i-O destination directory: echo "Moving $imgfile into destination directory $DESTDIR/$SLACKREL" mv -fv ${imgfile}* $DESTDIR/$SLACKREL/ done # Clean up: rm -rf $TMPDIR