Skip to content

Instantly share code, notes, and snippets.

@sathlan
Created April 8, 2013 13:38
Show Gist options
  • Save sathlan/5336809 to your computer and use it in GitHub Desktop.
Save sathlan/5336809 to your computer and use it in GitHub Desktop.
create a multiboot freebsd/linux usb key.
#!/bin/sh -x
START_DIR=$CWD
SHARE_DIR=/backup001/chem/home/chem/src/mfsbsd
KEYBOARD=dvorak
WANT_PHORONIX_TEST_SUITE=4.4.1 # set it to no to disable
# catch error from my own error function even in subshell.
err_handler ()
{
rc=$?
if [ $rc -eq 42 ]; then
{
for i in $MOUNT_POINTS; do
umount $i
done
for i in $MDDEVICES; do
mdconfig -d -u "${i#md}"
done
}
exit $rc
fi
}
trap err_handler CHLD
usage ()
{
echo "USAGE: TODO"
}
PACKAGES_DIR='/backup001/chem/packages'
#PARTITIONS="MFS DIST BOOT_1 LINUX"
PART_COUNT='6'
PART_BOOT_1_SIZE='100'
PART_BOOT_2_SIZE=$PART_BOOT_1_SIZE
PART_DIST_SIZE="3000"
PART_LINUX_SIZE="All"
PART_BOOT_1_IDX=1
PART_BOOT_2_IDX=2
#PART_MFS_IDX=2
PART_DIST_IDX=3
PART_LINUX_IDX=4
PART_MFS_TYPE=freebsd
PART_DIST_TYPE=freebsd
PART_BOOT_1_TYPE=freebsd
PART_BOOT_2_TYPE=freebsd
PART_LINUX_TYPE='!131'
MFS_PATH='http://mfsbsd.vx.sk/files/iso/amd64/9/mfsbsd-9.1-RELEASE-amd64.iso'
ISO_PATH='ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/9.1/FreeBSD-9.1-RELEASE-amd64-disc1.iso'
MDDEVICES=""
MOUNT_POINTS=""
USB_DEVICE=""
ERASE_DISK=""
while getopts :m:i:l:d:u:e: OPT; do
case $OPT in
m|+m)
MFS_PATH="$OPTARG"
;;
i|+i)
ISO_PATH="$OPTARG"
;;
l|+l)
LINUX_PATH="$OPTARG"
;;
d|+d)
USB_DEVICE="$OPTARG"
;;
u:+u)
UPDATE_WHAT="$OPTARG"
;;
e:+e)
ERASE_DISK="YES"
;;
*)
usage
exit 2
esac
done
shift `expr $OPTIND - 1`
OPTIND=1
error ()
{
echo "$@" >&2
exit 42
}
SECTOR_SIZE=""
DISKINFO=`mktemp -t "make_usb_diskinfo"`
if ! diskinfo -v /dev/$USB_DEVICE 2>/dev/null; then
error "The device is not valid"
fi > "$DISKINFO"
OIFS="$IFS"
IFS="\n"
while read input; do
expr "$input" : '.*sectorsize' >/dev/null && sector_size=${input% *# *}
expr "$input" : '.*size in bytes' >/dev/null && sizeb=${input% *# *}
expr "$input" : '.*size in sectors' >/dev/null && sizes=${input% *# *}
done < "$DISKINFO"
rm "$DISKINFO"
IFS="$OIFS"
if [ -z "$sector_size" ]; then
error "Cannot figure out the sector_size"
fi
TMP_DIR=`mktemp -d -t make_usb`
__fetch ()
{
local file="$1"
if [ -z "$file" ]; then
error "You must provide a non empty name"
fi
if expr "$file" : '[hHFf][tT][tTpP]' >/dev/null 2>&1; then
fetch -o $TMP_DIR $file
file="$TMP_DIR/${file##*/}"
fi
if ! [ -e "$file" ]; then
error "Cannot find the iso $file"
fi
echo $file
}
__get_size ()
{
local file="$1"
local type="$2"
eval eval local size="\$\{PART_${type}_SIZE\}"
if [ "$size" = "All" ]; then
echo 'All'
return 0
fi
if ! [ -e "$file" ]; then
error "The file \"$file\" doesn't exist"
fi
# 20% more for ufs formating
local size_disk=`ls -l "$file" | awk '{print int(($5/1024/1024) * 1.2 )}'`
if [ -n "$size" ]; then
if [ $size -ge $size_disk ]; then
echo $size
return 0
fi
fi
echo $size_disk
}
fetch_dist_iso ()
{
PART_DIST_PATH=`__fetch $ISO_PATH`
}
get_dist_size ()
{
__get_size "$PART_DIST_PATH" DIST
}
fetch_linux_iso ()
{
if [ -z "$LINUX_PATH" ]; then
error "Cannot guess the Linux distribution you want. Use -l to specify the iso path."
fi
PART_LINUX_PATH=`__fetch $LINUX_PATH`
}
get_linux_size ()
{
__get_size "$PART_LINUX_PATH" LINUX
}
fetch_mfs_iso ()
{
PART_MFS_PATH=`__fetch $MFS_PATH`
}
get_mfs_size ()
{
__get_size "$PART_MFS_PATH" MFS
}
delete_partition ()
{
local idx="$1"
if [ -z "$idx" ]; then
error "You must specify the partition index."
fi
if ! gpart delete -i $idx $USB_DEVICE; then
error "Could not delete partion $idx from $USB_DEVICE"
fi
}
cleanup_mbr ()
{
dd if=/dev/zero of=/dev/$USB_DEVICE bs=512 count=1
}
detroy_geom ()
{
if ! gpart destroy $USB_DEVICE; then
error "Could not destroy geom $USB_DEVICE"
fi
cleanup_mbr
}
erase_disk ()
{
if ! gpart show | egrep -q "\\<$USB_DEVICE\\>"; then
return 0
fi
local gpart=`mktemp -t "make_usb_erase_disk"`
if ! gpart show -p $USB_DEVICE; then
error "The device cannot be viewed with gpart."
fi > "$gpart"
(
IFS="\n"
while read input; do
expr "$input" : '.*- free -' && continue
index=$(expr "$input" : '.*'${USB_DEVICE}'s\([0-9]\)')
test -n "$index" && delete_partition $index
done < "$gpart"
rm "$gpart"
)
detroy_geom
}
create_disk_table ()
{
if ! gpart create -s MBR $USB_DEVICE; then
error "Cannot create the partitioning scheme for $USB_DEVICE"
fi
}
create_partitions ()
{
local type="$1"
echo "$IFS"
eval eval local part_type="\$\{PART_${type}_TYPE\}"
eval eval local idx="\$\{PART_${type}_IDX\}"
eval eval size="\$\{PART_${type}_SIZE\}"
case $size in
All)
size_cmd=""
;;
[0-9]*)
if ! printf "%d" $size >/dev/null 2>&1; then
error "Number \"$size\" is not valid for $type"
fi
size_cmd=" -s ${size}M "
;;
*)
error "Number \"$size\" is not valid for $type"
esac
if ! gpart add -t $part_type -i $idx $size_cmd $USB_DEVICE; then
error "Could not create partition $part_type of sector size $sector_size on $USB_DEVICE of size $size M."
fi
}
insert_bootcode ()
{
if ! gpart bootcode -b /boot/boot0 $USB_DEVICE; then
error "Could not insert bootcode stage 0 on $USB_DEVICE"
fi
}
__create_and_copy_dest ()
{
local type="$1"
local source_dir="$2"
local find_user_args="${3:-.}"
eval eval local slice="/dev/${USB_DEVICE}s\$\{PART_${type}_IDX\}"
case $type in
MFS|BOOT*|DIST)
if ! gpart bootcode -p /boot/boot -i "${slice#/dev/${USB_DEVICE}s}" ${USB_DEVICE}; then
error "Could not insert bootcode 1 on $USB_DEVICE"
fi
if ! bsdlabel -w $slice; then
error "Could not write bsd partitions"
fi
if ! newfs -O1 -m0 -L `echo $type | tr -d '_'` -n ${slice}a; then
error "Could not create freebsd filesystem on ${slice}a"
fi
;;
DOS)
;;
LINUX)
if ! mkfs.ext2 -L $type -m0 ${slice}; then
error "Could not create linux filesystem on ${slice}"
fi
;;
*)
error "Cannot find commands for fs creation for type \"$type\""
esac
eval eval PART_${type}_DEST=`mktemp -d -t make_usb_${type}_dest`
eval eval local dest="\$\{PART_${type}_DEST\}"
if [ ! -d "$dest" ]; then
eval eval error "Destination directory doesn't exists (\$\{PART_${type}_DEST\})"
fi
case $type in
MFS|BOOT*|DIST)
if ! mount ${slice}a $dest; then
error "Could not mount freebsd filesystem on ${slice}a"
fi
;;
DOS)
;;
LINUX)
if ! mount -t ext2fs ${slice} ${dest}; then
error "Could not mount linux filesystem on ${slice}"
fi
if ! grub-install --force --no-floppy --root-directory=${dest} ${slice}; then
error "Could not install linux bootstrap code for \"${slice}\" in \"${dest}\""
fi
;;
*)
error "Cannot find commands for mounting for type \"$type\""
esac
MOUNT_POINTS="$MOUNT_POINTS ${dest}"
{
eval cd $source_dir
eval find "$find_user_args" | cpio -dumpv $dest
if [ $? -ne 0 ]; then
error "Problem copying the data from \"$source_dir\" to \"$dest\""
fi
}
}
__copy_data ()
{
local type="$1"
eval eval PART_${type}_MD=\`mdconfig -a -t vnode -f \$PART_${type}_PATH\`
eval eval local mount_src="/dev/\$\{PART_${type}_MD\}"
MDDEVICES="$MDDEVICES ${mount_src#/dev/}"
eval eval PART_${type}_MNT=\`mktemp -d -t make_usb_${type}_mnt\`
eval eval local source_dir="\$\{PART_${type}_MNT\}"
if [ -z "${mount_src#/dev/}" -o -z "$source_dir" ]; then
error "Could not create the logical device."
fi
eval mount -t cd9660 $mount_src $source_dir
if [ $? -ne 0 ]; then
eval eval error "Could not mount cdrom \$PART_${type}_PATH"
fi
MOUNT_POINTS="$MOUNT_POINTS ${source_dir}"
__create_and_copy_dest $type $source_dir
}
copy_linux_data ()
{
__copy_data LINUX
}
copy_mfs_data ()
{
__copy_data MFS
}
copy_dist_data ()
{
__copy_data DIST
}
copy_boot_data ()
{
local type="BOOT_${1}"
local source_dir='/'
local find_args='boot -name "kernel.old" -prune -o \! -name "*.symbols"'
__create_and_copy_dest $type $source_dir "$find_args"
}
copy_boot_1_data ()
{
copy_boot_data 1
}
copy_boot_2_data ()
{
copy_boot_data 2
}
setup_keyboard ()
{
local distribution="$1"
local dest_dir="$2"
if [ -z "$dest_dir" ]; then
error "You must precise the destination directory to setup the keyboard."
fi
if [ -z "$distribution" ]; then
distribution=freebsd
fi
case $distribution in
freebsd)
case $KEYBOARD in
dvorak)
echo 'keymap="us.dvorak"' >> "${dest_dir}/etc/rc.conf";;
esac
;;
linux)
:
;;
esac
}
mungle_mfs ()
{
:
}
mungle_dist ()
{
for i in destroygeom zfsinstall; do
if ! cat $SHARE_DIR/$i > $PART_DIST_DEST/$i; then
error "Could not copy file $i to $PART_DIST_DEST/$i"
fi
done
if ! echo '/dev/ufs/DIST / ufs ro,noatime 1 1' > $PART_DIST_DEST/etc/fstab; then
error "Could not update the fstab."
fi
setup_keyboard freebsd $PART_DIST_DEST
if ! pkg info > $PART_DIST_DEST/pkg.list; then
error "Could not save the list of installed package."
fi
if [ -z "${PACKAGES_DIR}" -o -z "${PART_DIST_DEST}" ]; then
error "Packages dir and part_dist_dest must be definied"
fi
if ! rsync -Wav "${PACKAGES_DIR}" "${PART_DIST_DEST}/"; then
error "Could not rsync from \"${PACKAGES_DIR}\" to \"${PART_DIST_DEST}/\""
fi
if [ "$WANT_PHORONIX_TEST_SUITE" != 'no' ]; then
{
cd $PART_DIST_DEST
fetch http://www.phoronix-test-suite.com/releases/phoronix-test-suite-${WANT_PHORONIX_TEST_SUITE}.tar.gz
}
fi
}
mungle_boot ()
{
eval eval local dest="\$\{PART_BOOT_${1}_DEST\}"
if ! pkg info > $dest/pkg.list; then
error "Could not save the list of installed package."
fi
}
mungle_linux ()
{
if ! cp $PART_LINUX_DEST/boot/grub/grub-*.cfg $PART_LINUX_DEST/boot/grub/grub.cfg; then
error "Could not find the grub configuration."
fi
}
clean_up ()
{
# force sync to wait for usb to fill up
sleep 2
sync
sleep 2
sync
for mnt in $MOUNT_POINTS; do
if ! umount $mnt; then
error "Could not umount $mnt"
fi
done
for md in $MDDEVICES; do
if ! mdconfig -d -u "${md#md}"; then
error "Could not detach device ${md}"
fi
done
}
__create ()
{
local type="$1"
if echo $type | grep -iqv boot; then
eval fetch_${type}_iso
eval eval PART_${type}_SIZE=`get_${type}_size`
fi
if [ -n "$ERASE_DISK" ]; then
erase_disk
create_disk_table
insert_bootcode
fi
create_partition `echo $type | tr '[a-z]' '[A-Z]'`
eval copy_${type}_data
eval mungle_${type}
clean_up
}
create_all ()
{
# fetch_mfs_iso
fetch_dist_iso
fetch_linux_iso
# PART_MFS_SIZE=`get_mfs_size`
PART_DIST_SIZE=`get_dist_size`
PART_LINUX_SIZE=`get_linux_size`
erase_disk
create_disk_table
insert_bootcode
create_partitions BOOT_1
create_partitions BOOT_2
# create_partitions MFS
create_partitions DIST
create_partitions LINUX
#
copy_boot_1_data
copy_boot_2_data
# copy_mfs_data
copy_dist_data
copy_linux_data
mungle_boot 1
mungle_boot 2
# mungle_mfs
mungle_dist
mungle_linux
#
clean_up
}
update ()
{
local dist="$1"
eval fetch_${dist}_iso
eval update_${dist}_data
eval mungle_${dist}
clean up
}
case $1 in
create)
create_all;;
update)
case "$UPDATE_WHAT" in
mfs|boot_1|boot_2|dist|linux)
:
;;
*)
error "When updating you must specify what : msf, boot_1, boot_2, dist, linux"
;;
esac
update $UPDATE_WHAT
;;
*)
error "Valid action are 'create', 'update'"
;;
esac
exit 0
@NitroNils
Copy link

I'm looking for a way to multiboot from USB with several BSDs, illumoses and Linuxen - is this a valid option? Don't have the skill to assess it myself.

@sathlan
Copy link
Author

sathlan commented Jan 12, 2021

It has worked at least once, several years ago, not sure it's production ready today, sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment