Hello all!
I've finally managed to get slackware 13.37 (32 bit) to run from a USB stick. Note, actually run as opposed to running the installer.
By and large it is a modification of the instructions found
here.
To do this, I used the following;
* A copy of slackware 13.37 32 bit from DVD
* A compaq CQ60 64-bit laptop running slackware 13.37 from the hard drive
* A copy of the latest version of qemu installed on the compaq laptop's hard drive (version 0.14.50).
* An 8GB SD Card (could also be a USB stick if you don't want to use a SD card).
* Syslinux (the default version in slackware 13.37).
Before you begin....
This procedure will need to be done on a reasonably new PC that is fast enough and can boot from USB properly (not all systems can). Also even some newer systems might not work, for example the laptop I was using (a 64-bit Compaq CQ60) works fine (as does an older Asus EEEPC 904HD), whereas my normal desktop PC (using a M3A78EM motherboard) would not boot properly and would hang, for reasons unknown :-( .
Instructions
Before you begin, you'll need this file (must be named init) -
Code:
#!/bin/ash
#
# /init: init script to load kernel modules from an initramfs
# This requires that your kernel supports initramfs!!!
#
# Copyright 2004 Slackware Linux, Inc., Concord, CA, USA
# Copyright 2007, 2008, 2009, 2010 Patrick J. Volkerding, Sebeka, MN, USA
# 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.
# With a generic kernel, you need to load the modules needed to mount the
# root partition. This might mean a SCSI, RAID, or other drive controller
# module, as well as the module to support the root filesystem. Once the
# root partition is mounted all the other modules will be available so you
# don't need to load them here.
#
# Config files used by this script:
#
# /rootdev Contains the name of the root device, such as: /dev/hda1
#
# /rootfs Contains the root filesystem type, such as: xfs
#
# /initrd-name Contains the name of the initrd file.
#
# /resumedev Contains the name of the device to resume from hibernation.
#
# /luksdev Contains colon separated list of luks encrypted devices to
# be unlocked.
#
# /lukskey Contains the path to a LUKS key-file for automatic unlock
# Format: LABEL=<partition_label>:/path/to/file
# UUID=<partition_uuid>:/path/to/file
#
# /wait-for-root Contains a number - the init script will wait this amount
# of seconds before creating device nodes.
#
# /keymap Contains the name for a custom keyboard map
#
# Optional:
#
# /load_kernel_modules
# A script that uses modprobe to load the desired modules.
#
# There's an example in here. To actually use it, you'll
# need to make it executable:
#
# chmod 755 load_kernel_modules
INITRD=$(cat /initrd-name)
#ROOTDEV=$(cat /rootdev)
#ROOTFS=$(cat /rootfs)
LUKSDEV=$(cat /luksdev)
LUKSKEY=$(cat /lukskey)
RESUMEDEV=$(cat /resumedev)
WAIT=$(cat /wait-for-root)
KEYMAP=$(cat /keymap)
INIT=/sbin/init
PATH="/sbin:/bin:/usr/sbin:/usr/bin"
# Mount /proc and /sys:
mount -n proc /proc -t proc
mount -n sysfs /sys -t sysfs
if grep devtmpfs /proc/filesystems 1>/dev/null 2>/dev/null ; then
DEVTMPFS=1
mount -n devtmpfs /dev -t devtmpfs
fi
# NEW - Added label and uuid *) below.
# Parse command line
for ARG in $(cat /proc/cmdline); do
case $ARG in
0|1|2|3|4|5|6|S|s|single)
RUNLEVEL=$ARG
;;
label=*)
LABEL_FOR_ROOT=`echo $ARG | cut -f2 -d=`
;;
uuid=*)
UUID_FOR_ROOT=`echo $ARG | cut -f2 -d=`
;;
install)
RESCUE=2
;;
init=*)
INIT=$(echo $ARG | cut -f2 -d=)
;;
luksdev=/dev/*)
LUKSDEV=$(echo $ARG | cut -f2 -d=)
;;
lukskey=*)
LUKSKEY=$(echo $ARG | cut -f2- -d=)
;;
rescue)
RESCUE=1
;;
resume=*)
RESUMEDEV=$(echo $ARG | cut -f2 -d=)
;;
root=/dev/*)
ROOTDEV=$(echo $ARG | cut -f2 -d=)
;;
root=LABEL=*)
ROOTDEV=$(echo $ARG | cut -f2- -d=)
;;
root=UUID=*)
ROOTDEV=$(echo $ARG | cut -f2- -d=)
;;
rootfs=*)
ROOTFS=$(echo $ARG | cut -f2 -d=)
;;
waitforroot=*)
WAIT=$(echo $ARG | cut -f2 -d=)
;;
esac
done
# Load kernel modules:
if [ ! -d /lib/modules/$(uname -r) ]; then
echo "No kernel modules found for Linux $(uname -r)."
elif [ -x ./load_kernel_modules ]; then # use load_kernel_modules script:
echo "${INITRD}: Loading kernel modules from initrd image:"
. ./load_kernel_modules
else # load modules (if any) in order:
if ls /lib/modules/$(uname -r)/*.*o 1> /dev/null 2> /dev/null ; then
echo "${INITRD}: Loading kernel modules from initrd image:"
for module in /lib/modules/$(uname -r)/*.*o ; do
/sbin/modprobe $module
done
unset module
fi
fi
# Sometimes the devices need extra time to be available.
# A root filesystem on USB is a good example of that.
sleep $WAIT
# If udevd is available, use it to generate block devices
# else use mdev to read sysfs and generate the needed devices
if [ -x /sbin/udevd -a -x /sbin/udevadm ]; then
/sbin/udevd --daemon --resolve-names=never
/sbin/udevadm trigger --subsystem-match=block --action=add
/sbin/udevadm settle --timeout=10
else
[ "$DEVTMPFS" != "1" ] && mdev -s
fi
# Load a custom keyboard mapping:
if [ -n "$KEYMAP" ]; then
echo "${INITRD}: Loading '$KEYMAP' keyboard mapping:"
tar xzOf /etc/keymaps.tar.gz ${KEYMAP}.bmap | loadkmap
fi
if [ "$RESCUE" = "" ]; then
# Initialize RAID:
if [ -x /sbin/mdadm ]; then
/sbin/mdadm -E -s >/etc/mdadm.conf
/sbin/mdadm -S -s
/sbin/mdadm -A -s
# This seems to make the kernel see partitions more reliably:
fdisk -l /dev/md* 1> /dev/null 2> /dev/null
fi
echo "1"
/bin/blkid
read key1
# NEW
if [ "$ROOTDEV" = "" ]; then
echo "Waiting 10 seconds ...."
sleep 10
echo "LABEL_FOR_ROOT=" $LABEL_FOR_ROOT
while [ "$ROOTDEV" = "" ]
do
PARTITIONS=`cat /proc/partitions`
BLKID=`/bin/blkid -c /dev/null`
echo $BLKID
echo $PARTITIONS
if [ ! "$LABEL_FOR_ROOT" = "" ]; then
BLKID_ROOT=`/bin/blkid -c /dev/null -s TYPE -t LABEL=$LABEL_FOR_ROOT`
else
BLKID_ROOT=`/bin/blkid -c /dev/null -s TYPE -t UUID=$UUID_FOR_ROOT`
fi
echo "Found: "$BLKID_ROOT
ROOTDEV=`echo $BLKID_ROOT | awk 'BEGIN{FS=":"}{print $1}'`
ROOTFS=`echo $BLKID_ROOT | awk 'BEGIN{FS="="}{l=length($2);print substr($2,2,l-2)}'`
done
fi
# NEW-END
echo "2"
# Unlock any encrypted partitions necessary to access the
# root filesystem, such as encrypted LVM Physical volumes, disk
# partitions or mdadm arrays.
# Unavailable devices such as LVM Logical Volumes will need to be
# deferred until they become available after the vgscan.
if [ -x /sbin/cryptsetup ]; then
echo "3"
# Determine if we have to use a LUKS keyfile:
if [ ! -z "$LUKSKEY" ]; then
mkdir /mountkey
KEYPART=$(echo $LUKSKEY |cut -f1 -d:)
LUKSPATH="/mountkey$(echo $LUKSKEY |cut -f2 -d:)"
# Catch possible mount failure:
if blkid -t TYPE=vfat $KEYPART 1>/dev/null 2>&1 ; then
MOUNTOPTS="-t vfat -o shortname=mixed"
else
MOUNTOPTS="-t auto"
fi
mount $MOUNTOPTS $(findfs $KEYPART) /mountkey 2>/dev/null
# Check if we can actually use this file:
if [ ! -f $LUKSPATH ]; then
LUKSKEY=""
else
echo ">>> Using LUKS key file: '$LUKSKEY'"
LUKSKEY="-d $LUKSPATH"
fi
fi
echo "4"
LUKSLIST_DEFERRED=""
LUKSLIST=$(echo $LUKSDEV | tr -s ':' ' ')
for LUKSDEV in $LUKSLIST ; do
if /sbin/cryptsetup isLuks ${LUKSDEV} 1>/dev/null 2>/dev/null ; then
if echo $ROOTDEV | grep -q "LABEL=" || echo $ROOTDEV | grep -q "UUID=" ; then
CRYPTDEV="luks$(basename $LUKSDEV)"
elif [ "x$ROOTDEV" = "x$(basename $ROOTDEV)" ]; then
CRYPTDEV="$ROOTDEV"
else
CRYPTDEV="luks$(basename $LUKSDEV)"
fi
echo "Unlocking LUKS encrypted device '${LUKSDEV}' as luks mapped device '$CRYPTDEV':"
/sbin/cryptsetup ${LUKSKEY} luksOpen ${LUKSDEV} ${CRYPTDEV} </dev/tty0 >/dev/tty0 2>&1
if [ "$ROOTDEV" = "$LUKSDEV" -o "$ROOTDEV" = "$CRYPTDEV" ] ; then
ROOTDEV="/dev/mapper/$CRYPTDEV"
fi
else
LUKSLIST_DEFERRED="${LUKSLIST_DEFERRED} ${LUKSDEV}"
fi
done
fi
echo "5"
# Initialize LVM:
if [ -x /sbin/vgchange ]; then
/sbin/vgchange -ay --ignorelockingfailure
fi
echo "6"
# Unlock any LUKS encrypted devices that were deferred above but have now
# become available due to the vgscan (i.e. filesystems on LVM Logical Volumes)
if [ -x /sbin/cryptsetup -a -n "${LUKSLIST_DEFERRED}" ]; then
for LUKSDEV in ${LUKSLIST_DEFERRED} ; do
if /sbin/cryptsetup isLuks ${LUKSDEV} 1>/dev/null 2>/dev/null ; then
if echo $ROOTDEV | grep -q "LABEL=" || echo $ROOTDEV | grep -q "UUID=" ; then
CRYPTDEV="luks$(basename $LUKSDEV)"
elif [ "x$ROOTDEV" = "x$(basename $ROOTDEV)" ]; then
CRYPTDEV="$ROOTDEV"
else
CRYPTDEV="luks$(basename $LUKSDEV)"
fi
echo "Unlocking LUKS encrypted device '${LUKSDEV}' as luks mapped device '$CRYPTDEV':"
/sbin/cryptsetup ${LUKSKEY} luksOpen ${LUKSDEV} ${CRYPTDEV} </dev/tty0 >/dev/tty0 2>&1
if [ "$ROOTDEV" = "$LUKSDEV" -o "$ROOTDEV" = "$CRYPTDEV" ] ; then
ROOTDEV="/dev/mapper/$CRYPTDEV"
fi
else
echo "LUKS device '${LUKSDEV}' unavailable for unlocking!"
fi
done
fi
echo "7"
# Find root device if a label or UUID was given:
if echo $ROOTDEV | grep -q "LABEL=" || \
echo $ROOTDEV | grep -q "UUID=" ; then
ROOTDEV=$(findfs $ROOTDEV)
fi
echo "8"
# Clean up after LUKS unlock using a keyfile:
if grep -q mountkey /proc/mounts 2>/dev/null ; then
umount -l /mountkey
rmdir /mountkey 2>/dev/null
fi
echo "9"
# Resume state from swap
if [ "$RESUMEDEV" != "" ]; then
if ls -l $RESUMEDEV | grep -q "^l" ; then
RESUMEDEV=$(ls -l $RESUMEDEV | awk '{ print $NF }')
fi
echo "Trying to resume from $RESUMEDEV"
RESMAJMIN=$(ls -l $RESUMEDEV | tr , : | awk '{ print $5$6 }')
echo $RESMAJMIN > /sys/power/resume
fi
echo "10"
# Switch to real root partition:
echo 0x0100 > /proc/sys/kernel/real-root-dev
echo "rootfs is "$ROOTFS
echo "rootdev is "$ROOTDEV
mount -o ro -t $ROOTFS $ROOTDEV /mnt
if [ ! -r /mnt/sbin/init ]; then
echo "ERROR: No /sbin/init found on rootdev (or not mounted). Trouble ahead."
echo " You can try to fix it. Type 'exit' when things are done."
echo
/bin/sh
fi
else
echo
echo "RESCUE mode"
echo
echo " You can try to fix or rescue your system now. If you want"
echo " to boot into your fixed system, mount your root filesystem"
echo " read-only under /mnt:"
echo
echo " # mount -o ro -t filesystem root_device /mnt"
echo
echo " Type 'exit' when things are done."
echo
/bin/sh
fi
echo "11"
if pgrep udevd >/dev/null ; then
/sbin/udevadm settle --timeout=30
pkill udevd
fi
echo "12"
unset ERR
echo "13"
mount -o move /proc /mnt/proc
echo "14"
mount -o move /sys /mnt/sys
[ "$DEVTMPFS" = "1" ] && mount -o move /dev /mnt/dev
echo "15"
echo "${INITRD}: exiting"
exec switch_root /mnt $INIT $RUNLEVEL
Note
In the above init file there are 3 lines;
Code:
echo "1"
/bin/blkid
read key1
You can omit the "read key1" line I simpy put this in a test to see what was happening inside the script when modifying it.
1. Open a terminal (e.g. konsole) and insert the SD card or USB stick.
2. Find out the sd/USB device name by running dmesg as root. (Mine appeared as sdb).
3. Type exit (no longer root).
4. Boot the slackware DVD by using qemu; (Note, /dev/sdb is the sd/USB device!).
Code:
qemu -boot d -cdrom /dev/sr0 -hda /dev/sdb
5. Let the DVD boot normally in qemu then create two partitions with cfdisk with the first partition as w95fat32 (type B), the second linux, e.g.
Code:
Name Flags Part Type Fs Type [label] Size(MB)
sda1 Boot Primary W95 FAT32 98.71
sda2 Primary Linux 7849.51*
Note that the SD/USB device will appear as /dev/sda in qemu, so the dos partition from within qemu will be /dev/sda1, with the linux partition as /dev/sda2.
6. Continue to do a normal slackware install. As a test, just install A, AP and Y. From memory, the linux partition was formatted with slackware 13.37's default, ext4.
7. Let the installer continue as normal but
don't install Lilo, just its package!.
8. Once the installer finishes, exit and let qemu restart. Then when qemu restarts and boots the slackware DVD at the boot prompt type;
Code:
boot: hugesmp.s root=/dev/sda2 rdinit= ro
9. This should now boot you into the newly installed system. Let it boot.
10. From the newly installed system, type;
11. Now type the following;
Code:
mkdir /tmp/0
mount /dev/sda1 /tmp/0
cd /boot
mkinitrd
12. And now these;
Code:
cd initrd-tree
rm bin/awk
rm bin/cut
cp /lib/libblkid.so.1 lib/
cp /lib/libext2fs.so.2 lib/
cp /lib/libc.so.6 lib/
cp /lib/libuuid.so.1 lib/
cp /lib/libcom_err.so.2 lib/
cp /lib/ld-linux.so.2 lib/
cp /lib/libpthread.so.0 lib/
cp /lib/libdl.so.2 lib/
cp /lib/libm.so.6 lib/
cp /usr/bin/awk bin/
cp /sbin/blkid bin/
cp /bin/cut bin/
cd ..
mount /dev/dvd /mnt/dvd
installpkg -root /boot/initrd-tree /mnt/dvd/slackware/a/devs*
13. Copy the init file above from whereever you stored it and then copy it into /boot/initrd-tree.
14. Then run these commands;
15. Next modify the newly installed systems' /etc/fstab. With a text editor (e.g. jed) change the first line of /etc/fstab from
Code:
/dev/sda2 / ext4 defaults 1 1
to
Code:
/dev/root / ext4 defaults 1 1
16. Next label the
second partition on the SD/USB device by typing;
Code:
e2label /dev/sda2 TEST
17. Copy the files needed to boot from the SD/USB device onto the dos partition (e.g. /dev/sda1) and make the directory - we'll use SYSLINUX to boot with.
Code:
mkdir /tmp/0/syslinux
cp /boot/vmlinuz /tmp/0/syslinux
cp /boot/initrd.gz /tmp/0/syslinux
18. Next create the syslinux.cfg file for syslinux - it needs to be placed into the dos partition - /syslinux/syslinux.cfg (eg /tmp/0/syslinux/syslinux.cfg);
Code:
default vmlinuz initrd=initrd.gz label="TEST"
Note that the word label must be in lower case, it dosen't seem to work in upperase.
19. Now type;
Code:
cd /tmp/0
syslinux -s /dev/sda1
20 And then create an MBR for linux on the SD/USB device;
Finally,
Unmount any other mounted devices, type sync, wait for any devices to finish writing, reboot and hope it works!
Hopefully I didn't forget anything above :-) !
ljones