diff options
Diffstat (limited to 'liveinit.tpl')
-rw-r--r-- | liveinit.tpl | 690 |
1 files changed, 553 insertions, 137 deletions
diff --git a/liveinit.tpl b/liveinit.tpl index e25bf9b..c4fd29a 100644 --- a/liveinit.tpl +++ b/liveinit.tpl @@ -1,8 +1,8 @@ -#!/bin/ash +#!/bin/sh # # Copyright 2004 Slackware Linux, Inc., Concord, CA, USA # Copyright 2007, 2008, 2009, 2010, 2012 Patrick J. Volkerding, Sebeka, MN, USA -# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021 Eric Hameleers, Eindhoven, NL +# Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Eric Hameleers, Eindhoven, NL # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -38,7 +38,10 @@ MEDIALABEL="@MEDIALABEL@" LIVEMAIN="@LIVEMAIN@" MARKER="@MARKER@" + PERSISTENCE="@PERSISTENCE@" +PERSISTPART="" +PERSISTPATH="." DISTRO="@DISTRO@" CDISTRO="@CDISTRO@" @@ -65,15 +68,19 @@ DEF_TZ=@DEF_TZ@ # By default, let the media determine if we can write persistent changes: # However, if we define TORAM=1, we will also set VIRGIN=1 when we want -# to avoid anything that writes to disk after we copy the OS to RAM. +# to avoid anything that writes to disk after we copy the OS to RAM; +# unless we explicitly use a persistence directory on the computer's local disk. VIRGIN=0 # If set to '1', existing persistent data will be wiped: WIPE_PERSISTENCE=0 # Used for debugging the init; -# Set DEBUG to '1' to enable explicit pauses; '2' enables verbose script exec; -# and '4' dumps you into a debug shell right before the switch_root: +# Set DEBUG to '1' to enable explicit pauses showing blkid/mount info; +# '2' and higher enable verbose script execution; +# '3' pauses like '1' or '2' but won't show blkid/mount info; +# '4' dumps you into a debug shell right before the switch_root; +# '5' additionally saves the verbose init execution output to 'debug_init.log': DEBUG=0 DEBUGV=" " @@ -106,6 +113,35 @@ HNMAC_ALLOWED="YES" INTERFACE="" NFSHOST="" +# Assume the default to be a readonly media - we write to RAM: +UPPERDIR=/mnt/live/changes +OVLWORK=/mnt/live/.ovlwork + +# Persistence directory on writable media gets mounted below /mnt/media. +# If the user specifies a system partition instead, +# then the mount point will be a subdirectory of /mnt/live instead: +PPATHINTERNAL=/mnt/media + +# Where will we mount the partition containing the ISO we are booting? +SUPERMNT=/mnt/super + +# LUKS containers on writable media are found below /mnt/media, +# unless liveslak boots off an ISO image, in which case the container files +# are found below /mnt/super - the filesystem of the USB partition containing +# our ISO: +CPATHINTERNAL=/mnt/media + +# If we boot directly off the ISO file, we want to know to enable extras. +# Possible values for ISOBOOT are 'diskpart','ventoy': +ISOBOOT="" +# The configuration file with customization for an ISO boot. +# Defaults to full pathname of the ISO, with extension 'cfg' instead of 'iso'. +ISOCFG="" + +# The extension for containerfiles accompanying an ISO is '.icc', +# for a persistent USB stick the extension is '.img' and this is the default: +CNTEXT=".img" + # Password handling, assign random initialization: DEFPW="7af0aed2-d900-4ed8-89f0" ROOTPW=$DEFPW @@ -132,6 +168,11 @@ if grep devtmpfs /proc/filesystems 1>/dev/null 2>/dev/null ; then mount -n devtmpfs /dev -t devtmpfs -o size=8M fi +# Mount if this directory exists (so the kernel supports efivarfs): +if [ -d /sys/firmware/efi/efivars ]; then + mount -o rw -t efivarfs none /sys/firmware/efi/efivars +fi + # Parse command line for ARG in $(cat /proc/cmdline); do case $ARG in @@ -159,7 +200,7 @@ for ARG in $(cat /proc/cmdline); do # generic syntax: hostname=newname[,qualifier] LIVE_HOSTNAME=$(echo $ARG | cut -f2 -d= | cut -f1 -d,) # Allow for the user to (mistakenly) add a domain component: - if [ $(echo $LIVE_HOSTNAME |cut -d. -f1- --output-delimiter ' '|wc -w) -gt 1 ]; then + if [ -n "$(echo "$LIVE_HOSTNAME". |cut -d. -f2-)" ]; then LIVE_DOMAIN=$(echo $LIVE_HOSTNAME |cut -d. -f2-) LIVE_HOSTNAME=$(echo $LIVE_HOSTNAME |cut -d. -f1) fi @@ -180,6 +221,7 @@ for ARG in $(cat /proc/cmdline); do livemedia=*) # generic syntax: livemedia=/dev/sdX # ISO syntax: livemedia=/dev/sdX:/path/to/slackwarelive.iso + # Scan partitions for ISO: livemedia=scandev:/path/to/slackwarelive.iso LM=$(echo $ARG | cut -f2 -d=) LIVEMEDIA=$(echo $LM | cut -f1 -d:) LIVEPATH=$(echo $LM | cut -f2 -d:) @@ -229,7 +271,22 @@ for ARG in $(cat /proc/cmdline); do fi ;; persistence=*) - PERSISTENCE=$(echo $ARG | cut -f2 -d=) + # Generic syntax: persistence=/path/to/persistencedir + # Dir on harddisk partition: persistence=/dev/sdX:/path/to/persistencedir + # Instead of device name, the value of its LABEL or UUID can be used too. + PD=$(echo $ARG | cut -f2 -d=) + PERSISTPART=$(echo $PD | cut -f1 -d:) + PERSISTPATH=$(dirname $(echo $PD | cut -f2 -d:)) + PERSISTENCE=$(basename $(echo $PD | cut -f2 -d:)) + unset PD + if [ "${PERSISTENCE})" = "changes" ]; then + echo "${MARKER}: Persistence directory cannot be called 'changes'." + echo "${MARKER}: Disabling persistence and recording changes in RAM." + PERSISTPART="" + PERSISTPATH="." + PERSISTENCE="@PERSISTENCE@" + VIRGIN=1 + fi ;; rescue) RESCUE=1 @@ -245,13 +302,29 @@ for ARG in $(cat /proc/cmdline); do VIRGIN=1 # prevent writes to disk since we are supposed to run from RAM ;; toram=*) + # Generic syntax: toram=type[,memperc] + # type: string value; os,core,all,none + # memperc: integer value, percentage RAM to reserve for liveslak + # You can use this parameter to change the percentage RAM + # used by liveslak, which is 50% for normal operation. + # For instance when you have an insane amount of RAM, you can specify + # a much lower percentage to be reserved for liveslak: + # toram=none,12 TORAM=1 - if [ "$(echo $ARG | cut -f2 -d=)" = "os" ]; then + TRTYPE="$(echo $ARG |cut -f2 -d= |cut -f1 -d,)" + if [ "$TRTYPE" = "os" ]; then VIRGIN=0 # load OS modules into RAM, write persistent data to disk - elif [ "$(echo $ARG | cut -f2 -d=)" = "core" ]; then + elif [ "$TRTYPE" = "core" ]; then CORE2RAM=1 # load Core OS modules into RAM - elif [ "$(echo $ARG | cut -f2 -d=)" = "all" ]; then + elif [ "$TRTYPE" = "all" ]; then VIRGIN=1 # prevent writes to disk since we are supposed to run from RAM + elif [ "$TRTYPE" = "none" ]; then + TORAM=0 # we only want to change the percentage reserved memory + fi + RAMSIZE="$(echo $ARG |cut -f2 -d= |cut -f2 -d,)" + if [ "$RAMSIZE" = "$TRTYPE" ]; then + # memperc was not supplied on commandline: + unset RAMSIZE fi ;; tweaks=*) @@ -276,7 +349,17 @@ for ARG in $(cat /proc/cmdline); do done # Verbose boot script execution: -[ $DEBUG -ge 2 ] && set -x +if [ $DEBUG -ge 2 ]; then + if [ $DEBUG -ge 5 ]; then + # We save (verbose) shell output to local file; + # These busybox compile options make it possible: + # CONFIG_SH_IS_ASH=y + # CONFIG_ASH_BASH_COMPAT=y + exec 5> debug_init.log + export BASH_XTRACEFD="5" + fi + set -x +fi debugit () { if [ $DEBUG -eq 0 -o $DEBUG -gt 3 ]; then @@ -339,6 +422,7 @@ fi # Sometimes the devices need extra time to be available. # A root filesystem on USB is a good example of that. +echo "${MARKER}: Sleeping $WAIT seconds to give slow USB devices some time." sleep $WAIT # Fire at least one blkid: blkid 1>/dev/null 2>/dev/null @@ -397,6 +481,8 @@ if [ "$RESCUE" = "" ]; then echo "/run/dhcpcd-${MYDEV}.pid" elif [ -s /run/dhcpcd-${MYDEV}-4.pid ]; then echo "/run/dhcpcd-${MYDEV}-4.pid" + elif [ -s /run/${MYDEV}.pid ]; then + echo "/run/${MYDEV}.pid" else echo UNKNOWNLOC fi @@ -499,7 +585,7 @@ if [ "$RESCUE" = "" ]; then find_loop() { # The losetup of busybox is different from the real losetup - watch out! - lodev=$(losetup -f) + lodev=$(losetup -f 2>/dev/null) if [ -z "$lodev" ]; then # We exhausted the available loop devices, so create the block device: for NOD in $(seq 0 ${MAXLOOPS}); do @@ -514,13 +600,13 @@ if [ "$RESCUE" = "" ]; then mknod -m660 $lodev b 7 $(echo $lodev |sed 's%/dev/loop%%') fi echo "$lodev" - } + } # End find_loop() mod_base() { MY_MOD="$1" echo $(basename ${MY_MOD}) |rev |cut -d. -f2- |rev - } + } # End mod_base() find_mod() { MY_LOC="$1" @@ -542,7 +628,7 @@ if [ "$RESCUE" = "" ]; then done ) | sort fi - } + } # End find_mod() find_modloc() { MY_LOC="$1" @@ -560,14 +646,19 @@ if [ "$RESCUE" = "" ]; then fi echo "${MY_LOC}" - } + } # End find_modloc() load_modules() { # SUBSYS can be 'system', 'addons', 'optional', 'core2ram': SUBSYS="$1" # Find all supported modules: - for MODULE in $(find_mod /mnt/media/${LIVEMAIN}/${SUBSYS}/) ; do + SUBSYSSET="$(find_mod /mnt/media/${LIVEMAIN}/${SUBSYS}/) $(find_mod ${SUPERMNT}/${LIVESLAKROOT}/${LIVEMAIN}/${SUBSYS}/)" + if [ "$SUBSYS" = "optional" ]; then + # We need to load any core2ram modules first: + SUBSYSSET="$(find_mod /mnt/media/${LIVEMAIN}/core2ram/) $(find_mod ${SUPERMNT}/${LIVESLAKROOT}/${LIVEMAIN}/core2ram/ ${SUBSYSSET})" + fi + for MODULE in ${SUBSYSSET} ; do # Strip path and extension from the modulename: MODBASE="$(mod_base ${MODULE})" if [ "$SUBSYS" = "optional" ]; then @@ -615,10 +706,10 @@ if [ "$RESCUE" = "" ]; then echo "${MARKER}: '$SUBSYS' modules were not found. Trouble ahead..." fi fi - } + } # End load_modules() # Function input is a series of device node names. Return all block devices: - ret_blockdev () { + ret_blockdev() { local OUTPUT="" for IDEV in $* ; do if [ -e /sys/block/$(basename $IDEV) ]; then @@ -628,10 +719,10 @@ if [ "$RESCUE" = "" ]; then done # Trim trailing space: echo $OUTPUT |cat - } + } # End ret_blockdev() # Function input is a series of device node names. Return all partitions: - ret_partition () { + ret_partition() { local OUTPUT="" for IDEV in $* ; do if [ -e /sys/class/block/$(basename $IDEV)/partition ]; then @@ -641,22 +732,178 @@ if [ "$RESCUE" = "" ]; then done # Trim trailing space: echo $OUTPUT |cat - } + } # End ret_partition() + + # Return device node of Ventoy partition if found: + # Function input: + # (param 1) Ventoy OS parameter block (512 bytes file). + # (param 2) action + # 'isopath' request: return full path to the ISO on the USB filesystem; + # 'devpartition' request: + # return the device node for the partition containing the ISO file; + # 'diskuuid' request: return the UUID for the disk; + # 'partnr' request: return the number of the partition containing the ISO; + ret_ventoy() { + local VOSPARMS="$1" + local VACTION="$2" + local DISKSIZE="" + local BDEV="" + local IPART="" + local VENTPART="" + + if [ "$VACTION" == "isopath" ]; then + echo $(hexdump -s 45 -n 384 -e '384/1 "%01c""\n"' $VOSPARMS) + elif [ "$VACTION" == "diskuuid" ]; then + echo $(hexdump -s 481 -n 4 -e '4/1 "%02x "' ${VOSPARMS} \ + | awk '{ for (i=NF; i>1; i--) printf("%s",$i); print $i; }' ) + elif [ "$VACTION" == "partnr" ]; then + echo $(( 0x$(hexdump -s 41 -n 2 -e '2/1 "%02x "' ${VOSPARMS} \ + | awk '{ for (i=NF; i>1; i--) printf("%s",$i); print $i; }' ) + )) + elif [ "$VACTION" == "devpartition" ]; then + PARTNR=$(( 0x$(hexdump -s 41 -n 2 -e '2/1 "%02x "' ${VOSPARMS} \ + | awk '{ for (i=NF; i>1; i--) printf("%s",$i); print $i; }' ) + )) + DISKSIZE=$(( 0x$(hexdump -s 33 -n 8 -e '8/1 "%02x "' ${VOSPARMS} \ + | awk '{ for (i=NF; i>1; i--) printf("%s",$i); print $i; }' ) + )) + # Determine which block device (only one!) reports this disk size (bytes): + for BDEV in $(find /sys/block/* |grep -Ev '(ram|loop)') ; do + BDEV=$(basename $BDEV) + # The 'size' value is sectors, not bytes! + # Logical block size in Linux is commonly 512 bytes: + BDEVSIZE=$(( $(cat /sys/block/${BDEV}/size) * $(cat /sys/block/${BDEV}/queue/logical_block_size) )) + if [ $BDEVSIZE -eq $DISKSIZE ]; then + # Found a block device with matching size in bytes: + for IPART in $(ret_partition $(blkid |cut -d: -f1) | grep -v loop) ; + do + if [ -e /sys/block/$BDEV/$(basename $IPART)/partition ]; then + if [ $(cat /sys/block/$BDEV/$(basename $IPART)/partition) -eq $PARTNR ]; then + # Found the correct partition number on matching disk: + VENTPART="$IPART $VENTPART" + fi + fi + done + fi + done + if [ $(echo $VENTPART |wc -w) -eq 1 ]; then + # We found the Ventoy ISO-containing partition. + # Trim leading/trailing spaces: + echo $VENTPART |xargs + else + # Zero or multiple matching block devices found, fall back to 'scandev': + echo scandev + fi + fi + } # End ret_ventoy() + + # Find partition on which a file resides: + # Function input: + # (param 1) Full path to the file we are looking for + # (param 2) Directory to mount the partition containing our file + # Use $(df $MYMNT |tail -1 |tr -s ' ' |cut -d' ' -f1) to find that partition, + # it will remain mounted on the provided mountpoint upon function return. + scan_part() { + local FILEPATH="$1" + local MYMNT="$2" + local ISOPART="" + local PARTFS="" + echo "${MARKER}: Scanning for '$FILEPATH'..." + for ISOPART in $(ret_partition $(blkid |cut -d: -f1)) $(ret_blockdev $(blkid |cut -d: -f1)) ; do + PARTFS=$(blkid $ISOPART |rev |cut -d'"' -f2 |rev) + mount -t $PARTFS -o ro $ISOPART ${MYMNT} + if [ -f "${MYMNT}/${FILEPATH}" ]; then + # Found our file! + unset ISOPART + break + else + umount $ISOPART + fi + done + if [ -n "$ISOPART" ]; then + echo "${MARKER}: Partition scan unable to find $(basename $FILEPATH), trouble ahead." + return 1 + else + return 0 + fi + } # End scan_part() ## End support functions ## # We need a mounted filesystem here to be able to do a switch_root later, # so we create one in RAM: if [ $TORAM -eq 1 ]; then - RAMSIZE=90% # need to be able to load the entire OS in RAM + RAMSIZE="${RAMSIZE:-90}%" # 90% by default to load the entire OS in RAM else - RAMSIZE=50% # the default value. + RAMSIZE="${RAMSIZE:-50}%" # 50% is the default value. fi mount -t tmpfs -o defaults,size=${RAMSIZE} none /mnt # Find the Slackware Live media. # TIP: Increase WAIT to give USB devices a chance to be seen by the kernel. mkdir /mnt/media + + # Multi ISO boot managers first. + + # --- Ventoy --- + # If we boot an ISO via Ventoy, this creates a device-mapped file + # '/dev/mapper/ventoy' which liveslak could use to mount that ISO, + # but specifying '-t iso9660' will fail to mount it. + # Omitting the '-t iso9660' makes the mount succceed. + # liveslak is 'Ventoy compatible': + # Ventoy will not execute its hooks and leaves all the detection to us. + # It will create the device-mapped file /dev/mapper/ventoy still. + VENTID="VentoyOsParam-77772020-2e77-6576-6e74-6f792e6e6574" + VENTVAR="/sys/firmware/efi/vars/${VENTID}" + if [ ! -d "${VENTVAR}" ]; then + # Newer Slackware will use 'efivars' rather than 'vars' directory; + VENTVAR="/sys/firmware/efi/efivars/${VENTID}" + fi + if [ -d "${VENTVAR}" ]; then + echo "${MARKER}: (UEFI) Ventoy ISO boot detected..." + ISOBOOT="ventoy" + VENTOSPARM="${VENTVAR}/data" + elif [ -f "${VENTVAR}" ]; then + # Kernel >= 6.x does not offer a clean data sctructure, so we need to + # find the offset of the data block in the efivars file: + cat "${VENTVAR}" > /vent.dmp + else + # Detect Ventoy in memory (don't use the provided hooks), see + # https://www.ventoy.net/en/doc_compatible_format.html: + dd if=/dev/mem of=/vent.dmp bs=1 skip=$((0x80000)) count=$((0xA0000-0x80000)) 2>/dev/null + fi + if [ -f /vent.dmp ]; then + # Use 'strings' to find the decimal offset of the magic string; + # With 'xargs' we remove leading and ending spaces: + if strings -t d /vent.dmp 1>/dev/null 2>/dev/null ; then + # Busybox in Slackware 15.0 or newer: + OFFSET=$(strings -t d /vent.dmp |grep ' www.ventoy.net' |xargs |cut -d' ' -f1) + else + # Busybox in Slackware 14.2 or older: + OFFSET=$(strings -o /vent.dmp |grep ' www.ventoy.net' |xargs |cut -d' ' -f1) + fi + if [ -n "${OFFSET}" ]; then + echo "${MARKER}: (BIOS) Ventoy ISO boot detected..." + ISOBOOT="ventoy" + # Save the 512-byte Ventoy OS Parameter block: + dd if=/vent.dmp of=/vent_os_parms bs=1 count=512 skip=$OFFSET 2>/dev/null + VENTOSPARM="/vent_os_parms" + fi + fi + if [ "$ISOBOOT" == "ventoy" ]; then + LIVEPATH=$(ret_ventoy $VENTOSPARM isopath) + if [ -e /dev/mapper/ventoy ]; then + LIVEMEDIA=$(dmsetup table /dev/mapper/ventoy |tr -s ' ' |cut -d' ' -f 4) + LIVEMEDIA=$(readlink -f /dev/block/${LIVEMEDIA}) + # Having the ISO device-mapped to /dev/dm-0 prevents liveslak from + # mounting the underlying partition, so we delete the mapped device: + dmsetup remove /dev/mapper/ventoy + else + # Return Ventoy device partition (or 'scandev'): + LIVEMEDIA=$(ret_ventoy $VENTOSPARM devpartition) + fi + fi + if [ -n "$NFSHOST" ]; then # NFS root. First configure our network interface: setnet @@ -672,6 +919,7 @@ if [ "$RESCUE" = "" ]; then VIRGIN=1 elif [ -z "$LIVEMEDIA" ]; then # LIVEMEDIA not specified on the boot commandline using "livemedia=" + # Start digging: # Filter out the block devices, only look at partitions at first: # The blkid function in busybox behaves differently than the regular blkid! # It will return all devices with filesystems and list LABEL UUID and TYPE. @@ -690,6 +938,7 @@ if [ "$RESCUE" = "" ]; then # We found a block device with the correct label (non-UEFI media). # Determine filesystem type ('iso9660' means we found a CDROM/DVD) LIVEFS=$(blkid $LIVEMEDIA |rev |cut -d'"' -f2 |rev) + [ "$LIVEFS" = "swap" ] && continue mount -t $LIVEFS -o ro $LIVEMEDIA /mnt/media else # Bummer.. label not found; the ISO was extracted to a different device. @@ -697,8 +946,10 @@ if [ "$RESCUE" = "" ]; then for SLDEVICE in $(ret_partition $(blkid |cut -d: -f1)) $(ret_blockdev $(blkid |cut -d: -f1)) ; do # We rely on the fact that busybox blkid puts TYPE"..." at the end: SLFS=$(blkid $SLDEVICE |rev |cut -d'"' -f2 |rev) + [ "$SLFS" = "swap" ] && continue mount -t $SLFS -o ro $SLDEVICE /mnt/media - if [ -d /mnt/media/${LIVEMAIN} ]; then + if [ -f /mnt/media/${LIVEMAIN}/system/0099-${DISTRO}_zzzconf-*.s* ]; + then # Found our media! LIVEALL=$SLDEVICE LIVEMEDIA=$SLDEVICE @@ -717,7 +968,8 @@ if [ "$RESCUE" = "" ]; then fi sleep 1 else - # LIVEMEDIA was specified on the boot commandline using "livemedia=" + # LIVEMEDIA was specified on the boot commandline using "livemedia=", + # or ISO was booted by a compatible multi ISO bootmanager: if [ "$LIVEMEDIA" != "scandev" -a ! -b "$LIVEMEDIA" ]; then # Passed a UUID or LABEL? LIVEALL=$(findfs UUID=$LIVEMEDIA 2>/dev/null) || LIVEALL=$(findfs LABEL=$LIVEMEDIA 2>/dev/null) @@ -734,39 +986,31 @@ if [ "$RESCUE" = "" ]; then # instead of just: "livemedia=/dev/sdX". # # First mount the partition and then loopmount the ISO: - SUPERMNT=/mnt/super_$(od -An -N1 -tu1 /dev/urandom |tr -d ' ') mkdir -p ${SUPERMNT} # if [ "$LIVEMEDIA" = "scandev" ]; then - # Scan partitions to find the one with the ISO and set LIVEMEDIA: - echo "${MARKER}: Scanning for '$LIVEPATH'..." - for ISOPART in $(ret_partition $(blkid |cut -d: -f1)) $(ret_blockdev $(blkid |cut -d: -f1)) ; do - PARTFS=$(blkid $ISOPART |rev |cut -d'"' -f2 |rev) - # Abuse the $SUPERMNT a bit, we will actually use it later: - mount -t $PARTFS -o ro $ISOPART ${SUPERMNT} - if [ -f ${SUPERMNT}/${LIVEPATH} ]; then - # Found our ISO! - LIVEMEDIA=$ISOPART - umount $ISOPART - unset ISOPART - break - else - umount $ISOPART - fi - done - if [ -n "$ISOPART" ]; then - echo "${MARKER}: Partition scan unable to find ISO, trouble ahead." - fi + # Scan partitions to find the one with the ISO and set LIVEMEDIA. + # Abuse the $SUPERMNT a bit, we will actually use it later. + # TODO: proper handling of scan_part return code. + scan_part ${LIVEPATH} ${SUPERMNT} + LIVEMEDIA="$(df ${SUPERMNT} 2>/dev/null |tail -1 |tr -s ' ' |cut -d' ' -f1)" + umount ${SUPERMNT} fi # At this point we know $LIVEMEDIA - either because the bootparameter - # specified it or else because the 'scandev' found it for us: + # specified it or else because the 'scandev' found it for us. + # Next we will re-define LIVEMEDIA to point to the actual ISO file + # on the mounted live media: SUPERFS=$(blkid $LIVEMEDIA |rev |cut -d'"' -f2 |rev) - mount -t $SUPERFS -o ro $LIVEMEDIA ${SUPERMNT} - if [ -f "${SUPERMNT}/$LIVEPATH" ]; then - LIVEFS=$(blkid "${SUPERMNT}/$LIVEPATH" |rev |cut -d'"' -f2 |rev) - LIVEALL="${SUPERMNT}/$LIVEPATH" + SUPERPART=$LIVEMEDIA + mount -t ${SUPERFS} -o ro ${SUPERPART} ${SUPERMNT} + if [ -f "${SUPERMNT}/${LIVEPATH}" ]; then + LIVEFS=$(blkid "${SUPERMNT}/${LIVEPATH}" |rev |cut -d'"' -f2 |rev) + LIVEALL="${SUPERMNT}/${LIVEPATH}" LIVEMEDIA="$LIVEALL" MOUNTOPTS="loop" + if [ -z "$ISOBOOT" ]; then + ISOBOOT="diskpart" + fi fi fi LIVEFS=$(blkid $LIVEMEDIA |rev |cut -d'"' -f2 |rev) @@ -774,11 +1018,23 @@ if [ "$RESCUE" = "" ]; then fi fi - # Finished determining the media availability, it should be mounted now. + if [ -n "${ISOBOOT}" ]; then + # Containerfiles used in conjunction with ISO files have '.icc' extension, + # aka 'ISO Container Companion' ;-) + CNTEXT=".icc" + # Search for containers in another place than the default /mnt/media: + CPATHINTERNAL=${SUPERMNT} + fi + + # ---------------------------------------------------------------------- # + # # + # Finished determining the media availability, it should be mounted now. # + # # + # ---------------------------------------------------------------------- # if [ ! -z "$LIVEMEDIA" ]; then echo "${MARKER}: Live media found at ${LIVEMEDIA}." - if [ ! -d /mnt/media/${LIVEMAIN} ]; then + if [ ! -f /mnt/media/${LIVEMAIN}/system/0099-${DISTRO}_zzzconf-*.s* ]; then echo "${MARKER}: However, live media was not mounted... trouble ahead." fi if [ "$LIVEMEDIA" != "$LIVEALL" ]; then @@ -808,7 +1064,7 @@ if [ "$RESCUE" = "" ]; then BLACKLIST KEYMAP LIVE_HOSTNAME LOAD LOCALE LUKSVOL \ NOLOAD RUNLEVEL TWEAKS TZ XKB ; do - if [ -n "$(eval echo \$${LIVEPARM})" ]; then + if [ -z "$(eval echo \$${LIVEPARM})" ]; then eval $(grep -w ^${LIVEPARM} /mnt/media/${LIVEMAIN}/${DISTROCFG}) fi done @@ -831,6 +1087,32 @@ if [ "$RESCUE" = "" ]; then fi fi + # When booted from an ISO, liveslak optionally reads parameters + # from a file with the same full filename as the ISO, + # but with '.cfg' extension instead of '.iso': + if [ -n "$ISOBOOT" ] && [ -z "$CFGACTION" ]; then + # The partition's filesystem containing the ISO is mounted at ${SUPERMNT}: + ISOCFG="${SUPERMNT}/$(dirname ${LIVEPATH})/$(basename ${LIVEPATH} .iso).cfg" + if [ -f "$ISOCFG" ]; then + # Read ISO live customization from disk file if present, + # and set any variable from that file: + echo "${MARKER}: Reading ISO boot config from ${ISOCFG#$SUPERMNT})" + for LISOPARM in \ + BLACKLIST KEYMAP LIVE_HOSTNAME LIVESLAKROOT LOAD LOCALE LUKSVOL \ + NOLOAD ISOPERSISTENCE RUNLEVEL TWEAKS TZ XKB ; + do + eval $(grep -w ^${LISOPARM} ${ISOCFG}) + done + # Handle any customization. + if [ -n "${ISOPERSISTENCE}" ]; then + # Persistence container located on the USB stick - strip the extension: + PERSISTENCE=$(basename ${ISOPERSISTENCE%.*}) + PERSISTPATH=$(dirname ${ISOPERSISTENCE}) + PERSISTPART=${SUPERPART} + fi + fi + fi + # Some variables require a value before continuing, so if they were not set # on the boot commandline nor in a config file, we take care of it now: if [ -z "$KEYMAP" ]; then @@ -845,7 +1127,7 @@ if [ "$RESCUE" = "" ]; then # Load a custom keyboard mapping: if [ -n "$KEYMAP" ]; then - echo "${MARKER}: Loading '$KEYMAP' keyboard mapping:" + echo "${MARKER}: Loading '$KEYMAP' keyboard mapping." tar xzOf /etc/keymaps.tar.gz ${KEYMAP}.bmap | loadkmap fi @@ -867,6 +1149,7 @@ if [ "$RESCUE" = "" ]; then if [ $CORE2RAM -eq 1 ]; then # Only load the Core OS modules: + echo "${MARKER}: Loading Core OS into RAM." load_modules core2ram else # First, the base Slackware system components: @@ -907,64 +1190,180 @@ if [ "$RESCUE" = "" ]; then fi fi - # Setup persistence in case our media is writable, *and* the user - # has created a directory "persistence" in the root of the media. - # otherwise we let the block changes accumulate in RAM only. + # --------------------------------------------------------------- # + # # + # Setup persistence in case our media is writable, *and* the user # + # has created a persistence directory or container on the media, # + # otherwise we let the block changes accumulate in RAM only. # + # # + # --------------------------------------------------------------- # + + # Was a partition specified containing a persistence directory, + # and is it different from the live medium? + if [ -n "${PERSISTPART}" ]; then + # If partition was specified as UUID/LABEL, or as 'scandev', + # we need to figure out the partition device ourselves: + if [ "${PERSISTPART}" != "scandev" -a ! -b "${PERSISTPART}" ]; then + TEMPP=$(findfs UUID=${PERSISTPART} 2>/dev/null) || TEMPP=$(findfs LABEL=${PERSISTPART} 2>/dev/null) + if [ -n "${TEMPP}" ]; then + PERSISTPART=${TEMPP} + else + echo "${MARKER}: Partition '${PERSISTPART}' needed for persistence was not found." + echo "${MARKER}: Falling back to recording changes in RAM." + PERSISTPART="" + VIRGIN=1 + fi + unset TEMPP + elif [ "${PERSISTPART}" = "scandev" ]; then + # Scan partitions to find the one with the persistence directory: + echo "${MARKER}: Scanning for partition with '${PERSISTENCE}'..." + ppartdir=".persistence_$(od -An -N1 -tu1 /dev/urandom|tr -d ' ')" + mkdir -p /mnt/live/${ppartdir} + for PPART in $(ret_partition $(blkid |cut -d: -f1)) ; do + PPARTFS=$(blkid $PPART |rev |cut -d'"' -f2 |rev) + # Mount the partition and peek inside for a directory or container: + mount -t $PPARTFS -o ro ${PPART} /mnt/live/${ppartdir} + if [ -d /mnt/live/${ppartdir}/${PERSISTPATH}/${PERSISTENCE} ] || [ -f /mnt/live/${ppartdir}/${PERSISTPATH}/${PERSISTENCE}${CNTEXT} ]; then + # Found our persistence directory/container! + PERSISTPART=$PPART + unset PPART + umount /mnt/live/${ppartdir} + break + else + umount /mnt/live/${ppartdir} + fi + done + rmdir /mnt/live/${ppartdir} + if [ -n "$PPART" ]; then + echo "${MARKER}: Partition scan unable to find persistence." + echo "${MARKER}: Falling back to recording changes in RAM." + PERSISTPART="" + VIRGIN=1 + fi + fi + fi + + debugit + + # ------------------------------------------------------------------ # + # # + # At this point, we either have determined the persistence partition # + # via UUID/LABEL/scandev, or else we failed to find one, # + # and then VIRGIN has been set to '1' and PERSISTPART to "". # + # # + # ------------------------------------------------------------------ # + + if [ -n "${PERSISTPART}" ]; then + # Canonicalize the input and the media devices, + # to ensure that we are talking about two different devices: + MPDEV=$(df /mnt/media |tail -1 |tr -s ' ' |cut -d' ' -f1) + REALMP=$(readlink -f ${MPDEV}) + REALPP=$(readlink -f ${PERSISTPART}) + if [ "${REALMP}" != "${REALPP}" ]; then + # The liveslak media is different from the persistence partition. + # Mount the partition readonly to access the persistence directory: + ppdir=".persistence_$(od -An -N1 -tu1 /dev/urandom|tr -d ' ')" + mkdir -p /mnt/live/${ppdir} + mount -o ro ${PERSISTPART} /mnt/live/${ppdir} + if [ $? -ne 0 ]; then + echo "${MARKER}: Failed to mount persistence partition '${PERSISTPART}' readonly." + echo "${MARKER}: Falling back to recording changes in RAM." + rmdir /mnt/live/${ppdir} + VIRGIN=1 + else + # Explicitly configured persistence has priority over regular + # persistence settings, and also overrides the boot parameter 'nop': + if [ -n "${ISOBOOT}" ]; then + # Boot from ISO, persistence is on the filesystem containing the ISO: + PPATHINTERNAL=${SUPERMNT} + else + # We use the above created directory: + PPATHINTERNAL=/mnt/live/${ppdir} + fi + VIRGIN=0 + fi + fi + fi + + debugit + + # At this point, if we use persistence then its partition is either + # the live media (mounted on /mnt/media), a system partition + # (mounted on /mnt/live/${ppdir}) or the partition containing the ISO if we + # booted off that. + # The variable ${PPATHINTERNAL} points to its mount point, + # and the partition is mounted read-only. + + # Create the mount point for the writable upper directory of the overlay. + # First, we deal with the case of persistence (VIRGIN=0) and then we + # deal with a pure Live system without persistence (VIRGIN=1): - # Create the mount point for the writable upper directory of the overlay: - # Assume the default to be a readonly media - we write to RAM: - UPPERDIR=/mnt/live/changes - OVLWORK=/mnt/live/.ovlwork if [ $VIRGIN -eq 0 ]; then - if [ "LIVEFS" != "iso9660" -a -d /mnt/media/${PERSISTENCE} ]; then - # Looks OK, but we need to remount the media in order to write - # to the persistence directory: - mount -o remount,rw /mnt/media + if [ -d ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE} ] || [ -f ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}${CNTEXT} ]; then + # Remount the partition r/w - we need to write to the persistence area. + # The value of PPATHINTERNAL will be different for USB stick or harddisk: + mount -o remount,rw ${PPATHINTERNAL} + if [ $? -ne 0 ]; then + echo "${MARKER}: Failed to mount persistence partition '${PERSISTPART}' read/write." + echo "${MARKER}: Falling back to recording changes in RAM." + VIRGIN=1 + fi + fi + fi + + # We have now checked whether the persistence area is actually writable. + + if [ $VIRGIN -eq 0 ]; then + # Persistence directory (either on writable USB or else on system harddisk): + if [ -d ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE} ]; then # Try a write... just to be dead sure: - if touch /mnt/media/${PERSISTENCE}/.rwtest 2>/dev/null && rm /mnt/media/${PERSISTENCE}/.rwtest 2>/dev/null ; then + if touch ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}/.rwtest 2>/dev/null && rm ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}/.rwtest 2>/dev/null ; then # Writable media and we are allowed to write to it. - if [ "$WIPE_PERSISTENCE" = "1" -o -f /mnt/media/${PERSISTENCE}/.wipe ]; then - echo "${MARKER}: Wiping existing persistent data in '/${PERSISTENCE}'." - rm -f /mnt/media/${PERSISTENCE}/.wipe 2>/dev/null - find /mnt/media/${PERSISTENCE}/ -mindepth 1 -exec rm -rf {} \; 2>/dev/null + if [ "$WIPE_PERSISTENCE" = "1" -o -f ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}/.wipe ]; then + echo "${MARKER}: Wiping existing persistent data in '${PERSISTPATH}/${PERSISTENCE}'." + rm -f ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}/.wipe 2>/dev/null + find ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}/ -mindepth 1 -exec rm -rf {} \; 2>/dev/null fi - echo "${MARKER}: Writing persistent changes to media directory '/${PERSISTENCE}'." - UPPERDIR=/mnt/media/${PERSISTENCE} - OVLWORK=/mnt/media/.ovlwork + echo "${MARKER}: Writing persistent changes to media directory '${PERSISTENCE}'." + UPPERDIR=${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE} + OVLWORK=${PPATHINTERNAL}/${PERSISTPATH}/.ovlwork + else + echo "${MARKER}: Failed to write to persistence directory '${PERSISTENSE}'." + echo "${MARKER}: Falling back to recording changes in RAM." + VIRGIN=1 fi - elif [ "LIVEFS" != "iso9660" -a -f /mnt/media/${PERSISTENCE}.img ]; then - # Use a container file; the filesystem needs to be writable: - mount -o remount,rw /mnt/media + # Use a container file instead of a directory for persistence: + elif [ -f ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}${CNTEXT} ]; then # Find a free loop device to mount the persistence container file: prdev=$(find_loop) - prdir=$(basename ${PERSISTENCE})_$(od -An -N1 -tu1 /dev/urandom |tr -d ' ') + prdir=persistence_$(od -An -N1 -tu1 /dev/urandom |tr -d ' ') mkdir -p /mnt/live/${prdir} - losetup $prdev /mnt/media/${PERSISTENCE}.img + losetup $prdev ${PPATHINTERNAL}/${PERSISTPATH}/${PERSISTENCE}${CNTEXT} # Check if the persistence container is LUKS encrypted: if cryptsetup isLuks $prdev 1>/dev/null 2>/dev/null ; then - echo "${MARKER}: Unlocking LUKS encrypted persistence file '/${PERSISTENCE}.img'" - cryptsetup luksOpen $prdev $(basename ${PERSISTENCE}) </dev/tty0 >/dev/tty0 2>&1 + echo "${MARKER}: Unlocking LUKS encrypted persistence file '${PERSISTPATH}/${PERSISTENCE}${CNTEXT}'" + cryptsetup luksOpen $prdev ${PERSISTENCE} </dev/tty0 >/dev/tty0 2>&1 if [ $? -ne 0 ]; then - echo "${MARKER}: Failed to unlock persistence file '/${PERSISTENCE}.img'." + echo "${MARKER}: Failed to unlock persistence file '${PERSISTPATH}/${PERSISTENCE}${CNTEXT}'." echo "${MARKER}: Falling back to RAM." else # LUKS properly unlocked; from now on use the mapper device instead: - prdev=/dev/mapper/$(basename ${PERSISTENCE}) + prdev=/dev/mapper/${PERSISTENCE} fi fi - prfs=$(blkid $prdev |rev |cut -d'"' -f2 |rev) + prfs=$(blkid $prdev 2>/dev/null |rev |cut -d'"' -f2 |rev) mount -t $prfs $prdev /mnt/live/${prdir} 2>/dev/null if [ $? -ne 0 ]; then - echo "${MARKER}: Failed to mount persistence file '/${PERSISTENCE}.img'." + echo "${MARKER}: Failed to mount persistence file '${PERSISTPATH}/${PERSISTENCE}${CNTEXT}'." echo "${MARKER}: Falling back to RAM." else - if [ "$WIPE_PERSISTENCE" = "1" -o -f /mnt/live/${prdir}/$(basename ${PERSISTENCE})/.wipe ]; then - echo "${MARKER}: Wiping existing persistent data in '/${PERSISTENCE}.img'." - rm -f /mnt/live/${prdir}/$(basename ${PERSISTENCE})/.wipe 2>/dev/null - find /mnt/live/${prdir}/$(basename ${PERSISTENCE})/ -mindepth 1 -exec rm -rf {} \; 2>/dev/null + if [ "$WIPE_PERSISTENCE" = "1" -o -f /mnt/live/${prdir}/${PERSISTENCE}/.wipe ]; then + echo "${MARKER}: Wiping existing persistent data in '${PERSISTPATH}/${PERSISTENCE}${CNTEXT}'." + rm -f /mnt/live/${prdir}/${PERSISTENCE}/.wipe 2>/dev/null + find /mnt/live/${prdir}/${PERSISTENCE}/ -mindepth 1 -exec rm -rf {} \; 2>/dev/null fi - echo "${MARKER}: Writing persistent changes to file '/${PERSISTENCE}.img'." - UPPERDIR=/mnt/live/${prdir}/$(basename ${PERSISTENCE}) + echo "${MARKER}: Writing persistent changes to file '${PERSISTPATH}/${PERSISTENCE}${CNTEXT}'." + UPPERDIR=/mnt/live/${prdir}/${PERSISTENCE} OVLWORK=/mnt/live/${prdir}/.ovlwork fi fi @@ -973,7 +1372,13 @@ if [ "$RESCUE" = "" ]; then if [ ! -z "$LUKSVOL" ]; then # Even without persistence, we need to be able to write to the partition # if we are using a LUKS container file: - mount -o remount,rw /mnt/media + if [ -n "$ISOBOOT" ]; then + mount -o remount,rw ${SUPERMNT} + else + mount -o remount,rw /mnt/media + fi + else + mount -o remount,ro /mnt/media fi fi @@ -1039,6 +1444,12 @@ if [ "$RESCUE" = "" ]; then mount --bind /mnt/live/toram /mnt/overlay/mnt/livemedia fi + if [ -n "$ISOBOOT" ]; then + # Expose the filesystem on the USB stick when we booted off an ISO there: + mkdir -p /mnt/overlay/mnt/supermedia + mount --bind ${SUPERMNT} /mnt/overlay/mnt/supermedia + fi + if [ ! -z "$USE_SWAP" ]; then # Use any available swap device: for SWAPD in $(blkid |grep TYPE="\"swap\"" |cut -d: -f1) ; do @@ -1047,6 +1458,44 @@ if [ "$RESCUE" = "" ]; then done fi + if [ ! -z "$LUKSVOL" ]; then + # Bind any LUKS container into the Live filesystem: + for luksvol in $(echo $LUKSVOL |tr ',' ' '); do + luksfil="$(echo $luksvol |cut -d: -f1)" + luksmnt="$(echo $luksvol |cut -d: -f2)" + luksnam="$(echo $(basename $luksfil) |tr '.' '_')" + if [ "$luksmnt" = "$luksfil" ]; then + # No optional mount point specified, so we use the default: /home/ + luksmnt="/home" + fi + + # Find a free loop device: + lodev=$(find_loop) + + losetup $lodev ${CPATHINTERNAL}/$luksfil + echo "Unlocking LUKS encrypted container '$luksfil' at mount point '$luksmnt'" + cryptsetup luksOpen $lodev $luksnam </dev/tty0 >/dev/tty0 2>&1 + if [ $? -ne 0 ]; then + echo "${MARKER}: Failed to unlock LUKS container '$luksfil'... trouble ahead." + else + # Create the mount directory if it does not exist (unlikely): + mkdir -p /mnt/overlay/$luksmnt + + # Let Slackware mount the unlocked container: + luksfs=$(blkid /dev/mapper/$luksnam |rev |cut -d'"' -f2 |rev) + if ! grep -q "^/dev/mapper/$luksnam" /mnt/overlay/etc/fstab ; then + echo "/dev/mapper/$luksnam $luksmnt $luksfs defaults 1 1" >> /mnt/overlay/etc/fstab + fi + # On shutdown, ensure that the container gets locked again: + if ! grep -q "$luksnam $luksmnt" /mnt/overlay/etc/crypttab ; then + echo "$luksnam $luksmnt" >> /mnt/overlay/etc/crypttab + fi + fi + done + fi + + debugit + if [ ! -z "$KEYMAP" ]; then # Configure custom keyboard mapping in console and X: echo "${MARKER}: Switching live console to '$KEYMAP' keyboard" @@ -1224,7 +1673,7 @@ EOPW mkdir -p /mnt/overlay/run/dhcpcd mount --bind /run/dhcpcd /mnt/overlay/run/dhcpcd fi - cp -a /run/dhcpcd* /mnt/overlay/run/ + cp -a /run/dhcpcd* /run/${INTERFACE}.pid /mnt/overlay/run/ cat /etc/resolv.conf > /mnt/overlay/etc/resolv.conf # Disable NetworkManager: @@ -1378,7 +1827,7 @@ EOT done if [ $RUN_DEPMOD -eq 1 ]; then # This costs a few seconds in additional boot-up time unfortunately: - echo "${MARKER}: Additional kernel module(s) found... need a bit" + echo "${MARKER}: Additional kernel module(s) found... need a bit" chroot /mnt/overlay /sbin/depmod -a fi unset RUN_DEPMOD @@ -1389,52 +1838,19 @@ EOT # In case of network boot, do not kill the network, umount NFS prematurely # or stop udevd on shutdown: if [ -n "$NFSHOST" ]; then - sed -i /mnt/overlay/etc/rc.d/rc.0 \ - -e "/on \/ type nfs/s%grep -q 'on / type nfs'%egrep -q 'on / type (nfs|tmpfs)'%" \ - -e '/umount.*nfs/s/nfs,//' \ - -e 's/rc.udev force-stop/rc.udev stop/' \ - -e 's/$(pgrep mdmon)/& $(pgrep udevd)/' + for RUNLVL in 0 6 ; do + sed -i /mnt/overlay/etc/rc.d/rc.${RUNLVL} \ + -e "/on \/ type nfs/s%grep -q 'on / type nfs'%egrep -q 'on / type (nfs|tmpfs)'%" \ + -e "s%'on / type nfs4'%& -e 'on / type overlay'%" \ + -e '/umount.*nfs/s/nfs,//' \ + -e 's/rc.udev force-stop/rc.udev stop/' \ + -e 's/$(pgrep mdmon)/& $(pgrep udevd)/' + done fi # Copy contents of rootcopy directory (may be empty) to overlay: cp -af /mnt/media/${LIVEMAIN}/rootcopy/* /mnt/overlay/ 2>/dev/null - # Bind any LUKS container into the Live filesystem: - if [ ! -z "$LUKSVOL" ]; then - for luksvol in $(echo $LUKSVOL |tr ',' ' '); do - luksfil="$(echo $luksvol |cut -d: -f1)" - luksmnt="$(echo $luksvol |cut -d: -f2)" - luksnam="$(echo $(basename $luksfil) |tr '.' '_')" - if [ "$luksmnt" = "$luksfil" ]; then - # No optional mount point specified, so we use the default: /home/ - luksmnt="/home" - fi - - # Find a free loop device: - lodev=$(find_loop) - - losetup $lodev /mnt/media/$luksfil - echo "Unlocking LUKS encrypted container '$luksfil' at mount point '$luksmnt'" - cryptsetup luksOpen $lodev $luksnam </dev/tty0 >/dev/tty0 2>&1 - if [ $? -ne 0 ]; then - echo "${MARKER}: Failed to unlock LUKS container '$luksfil'... trouble ahead." - else - # Create the mount directory if it does not exist (unlikely): - mkdir -p /mnt/overlay/$luksmnt - - # Let Slackware mount the unlocked container: - luksfs=$(blkid /dev/mapper/$luksnam |rev |cut -d'"' -f2 |rev) - if ! grep -q /dev/mapper/$luksnam /mnt/overlay/etc/fstab ; then - echo "/dev/mapper/$luksnam $luksmnt $luksfs defaults 1 1" >> /mnt/overlay/etc/fstab - fi - # On shutdown, ensure that the container gets locked again: - if ! grep -q "$luksnam $luksmnt" /mnt/overlay/etc/crypttab ; then - echo "$luksnam $luksmnt" >> /mnt/overlay/etc/crypttab - fi - fi - done - fi - [ $DEBUG -gt 3 ] && rescue "DEBUG SHELL" # --------------------------------------------------------------------- # @@ -1466,8 +1882,8 @@ fi /sbin/udevadm control --exit unset ERR -umount /proc -umount /sys +umount /proc 2>/dev/null +umount /sys 2>/dev/null umount /run 2>/dev/null echo "${MARKER}: Slackware Live system is ready." |