mirror of
https://github.com/mvallim/live-custom-ubuntu-from-scratch.git
synced 2025-08-03 16:33:19 +00:00
319 lines
9.0 KiB
Bash
Executable File
319 lines
9.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e # exit on error
|
|
set -o pipefail # exit on pipeline error
|
|
set -u # treat unset variable as error
|
|
#set -x
|
|
|
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
|
|
|
CMD=(setup_host debootstrap run_chroot build_iso)
|
|
|
|
DATE=`TZ="UTC" date +"%y%m%d-%H%M%S"`
|
|
|
|
function help() {
|
|
# if $1 is set, use $1 as headline message in help()
|
|
if [ -z ${1+x} ]; then
|
|
echo -e "This script builds a bootable ubuntu ISO image"
|
|
echo -e
|
|
else
|
|
echo -e $1
|
|
echo
|
|
fi
|
|
echo -e "Supported commands : ${CMD[*]}"
|
|
echo -e
|
|
echo -e "Syntax: $0 [start_cmd] [-] [end_cmd]"
|
|
echo -e "\trun from start_cmd to end_end"
|
|
echo -e "\tif start_cmd is omitted, start from first command"
|
|
echo -e "\tif end_cmd is omitted, end with last command"
|
|
echo -e "\tenter single cmd to run the specific command"
|
|
echo -e "\tenter '-' as only argument to run all commands"
|
|
echo -e
|
|
exit 0
|
|
}
|
|
|
|
function find_index() {
|
|
local ret;
|
|
local i;
|
|
for ((i=0; i<${#CMD[*]}; i++)); do
|
|
if [ "${CMD[i]}" == "$1" ]; then
|
|
index=$i;
|
|
return;
|
|
fi
|
|
done
|
|
help "Command not found : $1"
|
|
}
|
|
|
|
function chroot_enter_setup() {
|
|
sudo mount --bind /dev chroot/dev
|
|
sudo mount --bind /run chroot/run
|
|
sudo chroot chroot mount none -t proc /proc
|
|
sudo chroot chroot mount none -t sysfs /sys
|
|
sudo chroot chroot mount none -t devpts /dev/pts
|
|
}
|
|
|
|
function chroot_exit_teardown() {
|
|
sudo chroot chroot umount /proc
|
|
sudo chroot chroot umount /sys
|
|
sudo chroot chroot umount /dev/pts
|
|
sudo umount chroot/dev
|
|
sudo umount chroot/run
|
|
}
|
|
|
|
function check_host() {
|
|
local os_ver
|
|
os_ver=`lsb_release -i | grep -E "(Ubuntu|Debian)"`
|
|
if [[ -z "$os_ver" ]]; then
|
|
echo "WARNING : OS is not Debian or Ubuntu and is untested"
|
|
fi
|
|
|
|
if [ $(id -u) -eq 0 ]; then
|
|
echo "This script should not be run as 'root'"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Load configuration values from file
|
|
function load_config() {
|
|
if [[ -f "$SCRIPT_DIR/config.sh" ]]; then
|
|
. "$SCRIPT_DIR/config.sh"
|
|
elif [[ -f "$SCRIPT_DIR/default_config.sh" ]]; then
|
|
. "$SCRIPT_DIR/default_config.sh"
|
|
else
|
|
>&2 echo "Unable to find default config file $SCRIPT_DIR/default_config.sh, aborting."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Verify that necessary configuration values are set and they are valid
|
|
function check_config() {
|
|
local expected_config_version
|
|
expected_config_version="0.4"
|
|
|
|
if [[ "$CONFIG_FILE_VERSION" != "$expected_config_version" ]]; then
|
|
>&2 echo "Invalid or old config version $CONFIG_FILE_VERSION, expected $expected_config_version. Please update your configuration file from the default."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
function setup_host() {
|
|
echo "=====> running setup_host ..."
|
|
sudo apt update
|
|
sudo apt install -y binutils debootstrap squashfs-tools xorriso grub-pc-bin grub-efi-amd64-bin mtools dosfstools unzip grub2-common
|
|
sudo mkdir -p chroot
|
|
}
|
|
|
|
function debootstrap() {
|
|
echo "=====> running debootstrap ... will take a couple of minutes ..."
|
|
sudo debootstrap --arch=amd64 --variant=minbase $TARGET_UBUNTU_VERSION chroot $TARGET_UBUNTU_MIRROR
|
|
}
|
|
|
|
function run_chroot() {
|
|
echo "=====> running run_chroot ..."
|
|
|
|
chroot_enter_setup
|
|
|
|
# Setup build scripts in chroot environment
|
|
sudo ln -f $SCRIPT_DIR/chroot_build.sh chroot/root/chroot_build.sh
|
|
sudo ln -f $SCRIPT_DIR/default_config.sh chroot/root/default_config.sh
|
|
if [[ -f "$SCRIPT_DIR/config.sh" ]]; then
|
|
sudo ln -f $SCRIPT_DIR/config.sh chroot/root/config.sh
|
|
fi
|
|
|
|
# Launch into chroot environment to build install image.
|
|
sudo chroot chroot /usr/bin/env DEBIAN_FRONTEND=${DEBIAN_FRONTEND:-readline} /root/chroot_build.sh -
|
|
|
|
# Cleanup after image changes
|
|
sudo rm -f chroot/root/chroot_build.sh
|
|
sudo rm -f chroot/root/default_config.sh
|
|
if [[ -f "chroot/root/config.sh" ]]; then
|
|
sudo rm -f chroot/root/config.sh
|
|
fi
|
|
|
|
chroot_exit_teardown
|
|
}
|
|
|
|
function build_iso() {
|
|
echo "=====> running build_iso ..."
|
|
|
|
rm -rf image
|
|
mkdir -p image/{casper,isolinux,install}
|
|
|
|
# copy kernel files
|
|
sudo cp chroot/boot/vmlinuz-**-**-generic image/casper/vmlinuz
|
|
sudo cp chroot/boot/initrd.img-**-**-generic image/casper/initrd
|
|
|
|
# memtest86
|
|
sudo cp chroot/boot/memtest86+.bin image/install/memtest86+
|
|
|
|
wget --progress=dot https://www.memtest86.com/downloads/memtest86-usb.zip -O image/install/memtest86-usb.zip
|
|
unzip -p image/install/memtest86-usb.zip memtest86-usb.img > image/install/memtest86
|
|
rm -f image/install/memtest86-usb.zip
|
|
|
|
# grub
|
|
touch image/ubuntu
|
|
cat <<EOF > image/isolinux/grub.cfg
|
|
|
|
search --set=root --file /ubuntu
|
|
|
|
insmod all_video
|
|
|
|
set default="0"
|
|
set timeout=30
|
|
|
|
menuentry "${GRUB_LIVEBOOT_LABEL}" {
|
|
linux /casper/vmlinuz boot=casper nopersistent toram quiet splash ---
|
|
initrd /casper/initrd
|
|
}
|
|
|
|
menuentry "${GRUB_INSTALL_LABEL}" {
|
|
linux /casper/vmlinuz boot=casper only-ubiquity quiet splash ---
|
|
initrd /casper/initrd
|
|
}
|
|
|
|
menuentry "Check disc for defects" {
|
|
linux /casper/vmlinuz boot=casper integrity-check quiet splash ---
|
|
initrd /casper/initrd
|
|
}
|
|
|
|
menuentry "Test memory Memtest86+ (BIOS)" {
|
|
linux16 /install/memtest86+
|
|
}
|
|
|
|
menuentry "Test memory Memtest86 (UEFI, long load time)" {
|
|
insmod part_gpt
|
|
insmod search_fs_uuid
|
|
insmod chain
|
|
loopback loop /install/memtest86
|
|
chainloader (loop,gpt1)/efi/boot/BOOTX64.efi
|
|
}
|
|
EOF
|
|
|
|
# generate manifest
|
|
sudo chroot chroot dpkg-query -W --showformat='${Package} ${Version}\n' | sudo tee image/casper/filesystem.manifest
|
|
sudo cp -v image/casper/filesystem.manifest image/casper/filesystem.manifest-desktop
|
|
for pkg in $TARGET_PACKAGE_REMOVE; do
|
|
sudo sed -i "/$pkg/d" image/casper/filesystem.manifest-desktop
|
|
done
|
|
|
|
# compress rootfs
|
|
sudo mksquashfs chroot image/casper/filesystem.squashfs \
|
|
-noappend -no-duplicates -no-recovery \
|
|
-wildcards \
|
|
-e "var/cache/apt/archives/*" \
|
|
-e "root/*" \
|
|
-e "root/.*" \
|
|
-e "tmp/*" \
|
|
-e "tmp/.*" \
|
|
-e "swapfile"
|
|
printf $(sudo du -sx --block-size=1 chroot | cut -f1) > image/casper/filesystem.size
|
|
|
|
# create diskdefines
|
|
cat <<EOF > image/README.diskdefines
|
|
#define DISKNAME ${GRUB_LIVEBOOT_LABEL}
|
|
#define TYPE binary
|
|
#define TYPEbinary 1
|
|
#define ARCH amd64
|
|
#define ARCHamd64 1
|
|
#define DISKNUM 1
|
|
#define DISKNUM1 1
|
|
#define TOTALNUM 0
|
|
#define TOTALNUM0 1
|
|
EOF
|
|
|
|
# create iso image
|
|
pushd $SCRIPT_DIR/image
|
|
(
|
|
cd isolinux && \
|
|
dd if=/dev/zero of=efiboot.img bs=1M count=10 && \
|
|
sudo mkfs.vfat efiboot.img && \
|
|
LOOP_DEVICE=`sudo losetup --find --show $PWD/efiboot.img` && \
|
|
mkdir efi && \
|
|
sudo mount $LOOP_DEVICE efi && \
|
|
sudo grub-install --efi-directory=efi --uefi-secure-boot --removable --no-nvram $LOOP_DEVICE && \
|
|
sudo umount $LOOP_DEVICE && \
|
|
sudo losetup --detach $LOOP_DEVICE && \
|
|
rm -rf efi
|
|
)
|
|
|
|
grub-mkstandalone \
|
|
--format=i386-pc \
|
|
--output=isolinux/core.img \
|
|
--install-modules="linux16 linux normal iso9660 biosdisk memdisk search tar ls" \
|
|
--modules="linux16 linux normal iso9660 biosdisk search" \
|
|
--locales="" \
|
|
--fonts="" \
|
|
"boot/grub/grub.cfg=isolinux/grub.cfg"
|
|
|
|
cat /usr/lib/grub/i386-pc/cdboot.img isolinux/core.img > isolinux/bios.img
|
|
|
|
sudo /bin/bash -c "(find . -type f -print0 | xargs -0 md5sum | grep -v -e 'md5sum.txt' -e 'bios.img' -e 'efiboot.img' > md5sum.txt)"
|
|
|
|
sudo xorriso \
|
|
-as mkisofs \
|
|
-iso-level 3 \
|
|
-full-iso9660-filenames \
|
|
-volid "$TARGET_NAME" \
|
|
-eltorito-boot boot/grub/bios.img \
|
|
-no-emul-boot \
|
|
-boot-load-size 4 \
|
|
-boot-info-table \
|
|
--eltorito-catalog boot/grub/boot.cat \
|
|
--grub2-boot-info \
|
|
--grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \
|
|
-eltorito-alt-boot \
|
|
-e EFI/efiboot.img \
|
|
-no-emul-boot \
|
|
-append_partition 2 0xef isolinux/efiboot.img \
|
|
-output "$SCRIPT_DIR/$TARGET_NAME.iso" \
|
|
-m "isolinux/efiboot.img" \
|
|
-m "isolinux/bios.img" \
|
|
-graft-points \
|
|
"/EFI/efiboot.img=isolinux/efiboot.img" \
|
|
"/boot/grub/grub.cfg=isolinux/grub.cfg" \
|
|
"/boot/grub/bios.img=isolinux/bios.img" \
|
|
"."
|
|
|
|
popd
|
|
}
|
|
|
|
# ============= main ================
|
|
|
|
# we always stay in $SCRIPT_DIR
|
|
cd $SCRIPT_DIR
|
|
|
|
load_config
|
|
check_config
|
|
check_host
|
|
|
|
# check number of args
|
|
if [[ $# == 0 || $# > 3 ]]; then help; fi
|
|
|
|
# loop through args
|
|
dash_flag=false
|
|
start_index=0
|
|
end_index=${#CMD[*]}
|
|
for ii in "$@";
|
|
do
|
|
if [[ $ii == "-" ]]; then
|
|
dash_flag=true
|
|
continue
|
|
fi
|
|
find_index $ii
|
|
if [[ $dash_flag == false ]]; then
|
|
start_index=$index
|
|
else
|
|
end_index=$(($index+1))
|
|
fi
|
|
done
|
|
if [[ $dash_flag == false ]]; then
|
|
end_index=$(($start_index + 1))
|
|
fi
|
|
|
|
#loop through the commands
|
|
for ((ii=$start_index; ii<$end_index; ii++)); do
|
|
${CMD[ii]}
|
|
done
|
|
|
|
echo "$0 - Initial build is done!"
|