Created
April 8, 2013 13:38
-
-
Save sathlan/5336809 to your computer and use it in GitHub Desktop.
create a multiboot freebsd/linux usb key.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
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
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.