From 8966351b12bbcf2f8fffbd8c3a4b00e7529349b8 Mon Sep 17 00:00:00 2001 From: Aaron Griffin Date: Sat, 6 Sep 2008 20:39:35 -0500 Subject: Split mkarchiso and configs into logical parts Signed-off-by: Aaron Griffin --- archiso/Makefile | 20 ++++ archiso/gen_grubscan | 30 ++++++ archiso/hooks/archiso | 97 ++++++++++++++++++ archiso/hooks/boot-cd | 37 +++++++ archiso/hooks/boot-usb | 35 +++++++ archiso/install/archiso | 11 ++ archiso/install/boot-cd | 17 ++++ archiso/install/boot-usb | 16 +++ archiso/mkarchiso | 260 +++++++++++++++++++++++++++++++++++++++++++++++ archiso/mkusbimg | 78 ++++++++++++++ archiso/testiso | 7 ++ 11 files changed, 608 insertions(+) create mode 100644 archiso/Makefile create mode 100644 archiso/gen_grubscan create mode 100644 archiso/hooks/archiso create mode 100644 archiso/hooks/boot-cd create mode 100644 archiso/hooks/boot-usb create mode 100644 archiso/install/archiso create mode 100644 archiso/install/boot-cd create mode 100644 archiso/install/boot-usb create mode 100755 archiso/mkarchiso create mode 100755 archiso/mkusbimg create mode 100755 archiso/testiso (limited to 'archiso') diff --git a/archiso/Makefile b/archiso/Makefile new file mode 100644 index 0000000..72abd11 --- /dev/null +++ b/archiso/Makefile @@ -0,0 +1,20 @@ +all: + +install: all + # install to sbin since script only usable by root + mkdir -p $(DESTDIR)/usr/sbin + install -m 755 mkarchiso $(DESTDIR)/usr/sbin + install -m 755 mkusbimg $(DESTDIR)/usr/sbin + # testiso can be used by anyone + mkdir -p $(DESTDIR)/usr/bin + install -m 755 testiso $(DESTDIR)/usr/bin + # hooks/install are needed by mkinitcpio + mkdir -p $(DESTDIR)/lib/initcpio/{hooks,install} + install -m 644 hooks/{archiso,boot-cd,boot-usb} $(DESTDIR)/lib/initcpio/hooks/ + install -m 644 install/{archiso,boot-cd,boot-usb} $(DESTDIR)/lib/initcpio/install/ + +uninstall: + rm -f $(DESTDIR)/usr/sbin/mkarchiso + rm -f $(DESTDIR)/usr/bin/testiso + rm -f $(DESTDIR)/lib/initcpio/hooks/{archiso,boot-cd,boot-usb} + rm -f $(DESTDIR)/lib/initcpio/install/{archiso,boot-cd,boot-usb} diff --git a/archiso/gen_grubscan b/archiso/gen_grubscan new file mode 100644 index 0000000..a2ac4df --- /dev/null +++ b/archiso/gen_grubscan @@ -0,0 +1,30 @@ +#!/bin/bash + +count=0 +fallback="" +for hd in $(seq 0 3); do + for part in $(seq 0 17); do + count=$(($count + 1)) + fallback="${fallback} ${count}" + done +done + +echo "timeout 0" +echo "default 0" +echo "fallback ${fallback}" +echo "color light-blue/blue black/light-grey" +echo "splashimage=/boot/splash.xpm.gz" +echo "" + +for hd in $(seq 0 3); do + for part in $(seq 0 17); do + echo "title Testing disk ${hd}, partition ${part}" + echo "set scan_dev=(hd${hd},${part})" + echo "fexists \$(scan_dev)/boot/grub/menu.lst" + echo "configfile \$(scan_dev)/boot/grub/menu.lst" + echo "" + done +done + +echo "title Failed" +echo "pause Scanning for installed grub failed" diff --git a/archiso/hooks/archiso b/archiso/hooks/archiso new file mode 100644 index 0000000..8a6b648 --- /dev/null +++ b/archiso/hooks/archiso @@ -0,0 +1,97 @@ +# args: source, mountpoint +_mnt_bind() +{ + msg "::: Binding ${1} to ${2}" + mkdir -p /real_root${2} + /bin/mount -o bind ${addon_dir}/${1} /real_root${2} +} + +# args: image file +_mnt_squashfs() +{ + msg "::: Adding new union branch: ${1}" + /bin/modprobe -q loop >/dev/null 2>&1 + mkdir -p "/tmpfs/mnt/loop${LOOP_NUM}" + if ! /bin/losetup "/dev/loop${LOOP_NUM}" ${1} > /dev/null 2>&1; then + echo "ERROR: Cannot mount loop device /dev/loop${LOOP_NUM}" + echo " Couldn't mount all addons" + break + fi + /bin/mount -r -t squashfs "/dev/loop${LOOP_NUM}" "/tmpfs/mnt/loop${LOOP_NUM}" + /bin/mount -t unionfs -o remount,add=:/tmpfs/mnt/loop${LOOP_NUM}=ro none "/real_root" + export LOOP_NUM=$(( $LOOP_NUM + 1 )) +} + +run_hook () +{ + if [ "x${ramdisk_size}" = "x" ]; then + ramdisk_size="75%" + fi + msg -n ":: Mounting tmpfs, size=${ramdisk_size}..." + mount -t tmpfs -o "size=${ramdisk_size}" tmpfs /tmpfs + msg "done." + + if [ "x${BOOT_MOUNT}" = "x" ]; then + echo "ERROR: BOOT_MOUNT is not set. The boot-cd or boot-usb hook MUST" + echo " be run before this one. This image was improperly built" + exit 1 + fi + + base_img="${BOOT_MOUNT}/archlive.sqfs" + if [ "${copytoram}" = "y" ]; then + msg ":: Copying squashfs image to RAM" + /bin/cat ${base_img} > /tmpfs/archlive.sqfs + base_img="/tmpfs/archlive.sqfs" + fi + + msg ":: Mounting squashfs image" + /bin/modprobe -q squashfs >/dev/null 2>&1 + + msg ":: Mounting root (union) filesystem" + /bin/modprobe -q unionfs >/dev/null 2>&1 + /bin/mount -t unionfs -o dirs=/tmpfs=rw none /real_root + + export LOOP_NUM="0" + addon_dir="${BOOT_MOUNT}/addons" + + # always layer default configuration + _mnt_squashfs "${addon_dir}/default-config.sqfs" + + if [ -e "${addon_dir}/config" ]; then + msg ":: Mounting addons" + while read img mountpoint type; do + # check if this line is a comment (starts with #) + [ "${img#"#"}" != "${img}" ] && continue + + if [ "${type}" = "bind" ]; then + _mnt_bind ${img} ${mountpoint} + elif [ "${type}" = "squashfs" ]; then + _mnt_squashfs "${addon_dir}/${img}" + fi + done < ${addon_dir}/config + fi + + # layer the "pristine" base system image last + _mnt_squashfs ${base_img} + + if [ -d /proc/sys/dev/cdrom ]; then + echo 0 > /proc/sys/dev/cdrom/lock + echo 0 > /proc/sys/dev/cdrom/autoeject + fi + + if [ "${break}" = "y" ]; then + echo ":: Break requested, type 'exit' to resume operation" + echo " NOTE: klibc contains no 'ls' binary, use 'echo *' instead" + PS1="ramfs$ " /bin/sh -i + fi + + udevpid=$(/bin/minips -C udevd -o pid=) + [ "x${udevpid}" != "x" ] && /bin/kill -9 $udevpid 2>&1 >/dev/null + #Yep, we're bailing out here. We don't need kinit. + msg ":: Passing control to Archlinux Initscripts...Please Wait" + /bin/umount /sys + /bin/umount /proc + exec /bin/run-init -c /dev/console /real_root /sbin/init ${CMDLINE} +} + +# vim:ft=sh:ts=4:sw=4:et: diff --git a/archiso/hooks/boot-cd b/archiso/hooks/boot-cd new file mode 100644 index 0000000..1670c6b --- /dev/null +++ b/archiso/hooks/boot-cd @@ -0,0 +1,37 @@ +run_hook () +{ + # external drives may need to settle + msg ":: Waiting for usb devices to settle..." + /sbin/udevtrigger --subsystem-match=usb + /sbin/udevsettle + sleep 5 + + msg ":: Scanning for boot cdrom device..." + + /bin/mkdir -p /bootmnt + bootmnt="/bootmnt" + found=0 + + /bin/modprobe -q isofs >/dev/null 2>&1 + for cdrom in /dev/cd/*; do + if mount -r -t iso9660 "${cdrom}" ${bootmnt} >/dev/null 2>&1; then + if [ -e "${bootmnt}/archlive.sqfs" ]; then + found=1 + msg "${cdrom}" + break + fi + else + echo "Failed to mount ${cdrom}" + fi + [ ${found} -eq 0 ] && umount ${bootmnt} >/dev/null 2>&1 + done + + if [ ${found} -eq 0 ]; then + echo "ERROR: cannot find booted cdrom device, cannot continue..." + exit 1 + else + export BOOT_MOUNT="${bootmnt}" + fi +} + +# vim:ft=sh:ts=4:sw=4:et: diff --git a/archiso/hooks/boot-usb b/archiso/hooks/boot-usb new file mode 100644 index 0000000..e84dd1c --- /dev/null +++ b/archiso/hooks/boot-usb @@ -0,0 +1,35 @@ +run_hook () +{ + msg ":: Waiting for usb devices to settle..." + /sbin/udevtrigger --subsystem-match=usb + /sbin/udevsettle + sleep 5 + msg ":: Scanning for boot usb device..." + + /bin/mkdir -p /bootmnt + bootmnt="/bootmnt" + found=0 + + for usb in /dev/sd[a-z][0-9]; do + if mount -r -t vfat "${usb}" ${bootmnt} >/dev/null 2>&1 ||\ + mount -r -t ext2 "${usb}" ${bootmnt} >/dev/null 2>&1; then + if [ -e "${bootmnt}/archlive.sqfs" ]; then + found=1 + msg "${usb}" + break + fi + else + echo "Failed to mount ${usb}" + fi + [ ${found} -eq 0 ] && umount ${bootmnt} >/dev/null 2>&1 + done + + if [ ${found} -eq 0 ]; then + echo "ERROR: cannot find booted usb device, cannot continue..." + exit 1 + else + export BOOT_MOUNT="${bootmnt}" + fi +} + +# vim:ft=sh:ts=4:sw=4:et: diff --git a/archiso/install/archiso b/archiso/install/archiso new file mode 100644 index 0000000..7b58831 --- /dev/null +++ b/archiso/install/archiso @@ -0,0 +1,11 @@ +install () +{ + MODULES="cdrom ide-cd_mod ide-core ide-generic unionfs squashfs isofs loop $(all_modules '/kernel/fs' | grep -v "nls") " + BINARIES="" + FILES="" + add_dir /real_root + add_dir /tmpfs + SCRIPT="archiso" +} + +# vim:ft=sh:ts=4:sw=4:et: diff --git a/archiso/install/boot-cd b/archiso/install/boot-cd new file mode 100644 index 0000000..2d96869 --- /dev/null +++ b/archiso/install/boot-cd @@ -0,0 +1,17 @@ +install () +{ + MODULES="cdrom ide-cd_mod ide-core ide-generic unionfs squashfs isofs $(all_modules '/kernel/fs' | grep -v "nls") " + + # need usb modules for external drives + MODULES="${MODULES} $(checked_modules "/usb/host" | grep -ve "_cs" -e "sl1811-hcd" -e "isp116x-hcd")" + MODULES=$(echo ${MODULES}) #trim whitespace + if [ "x${MODULES}" != "x" ]; then + MODULES="${MODULES} usb_storage sd_mod sr_mod" + fi + + BINARIES="" + FILES="" + SCRIPT="boot-cd" +} + +# vim:ft=sh:ts=4:sw=4:et: diff --git a/archiso/install/boot-usb b/archiso/install/boot-usb new file mode 100644 index 0000000..32d451f --- /dev/null +++ b/archiso/install/boot-usb @@ -0,0 +1,16 @@ +install () +{ + MODULES="cdrom ide-cd_mod ide-core ide-generic unionfs squashfs $(all_modules '/kernel/fs' | grep -v "nls") " + + MODULES="${MODULES} $(checked_modules "/usb/host" | grep -ve "_cs" -e "sl1811-hcd" -e "isp116x-hcd")" + + MODULES=$(echo ${MODULES}) #trim whitespace + if [ "x${MODULES}" != "x" ]; then + MODULES="${MODULES} usb_storage sd_mod sr_mod" + fi + BINARIES="" + FILES="" + SCRIPT="boot-usb" +} + +# vim:ft=sh:ts=4:sw=4:et: diff --git a/archiso/mkarchiso b/archiso/mkarchiso new file mode 100755 index 0000000..52087fa --- /dev/null +++ b/archiso/mkarchiso @@ -0,0 +1,260 @@ +#!/bin/bash + +CPIOCONFIG="$(pwd)/archiso-mkinitcpio.conf" +DEF_CONFIG_DIR="$(pwd)/default-config" +PKGFILE="$(pwd)/packages.list" +PKGLIST="" +QUIET="y" +FORCE="n" +ADDON_DIR="" + +command_name="" +work_dir="" +imgname="" + +APPNAME=$(basename "${0}") + +# usage: usage +usage () +{ + echo "usage ${APPNAME} [options] command " + echo " general options:" + echo " -f Force overwrite of working files/squashfs image/bootable image" + echo " -i CPIO_CONFIG Use CONFIG file for mkinitcpio. default: ${CPIOCONFIG}" + echo " -P PKGFILE File with list of packages to install. default: ${PKGFILE}" + echo " -p PACKAGE Additional package to install, can be used multiple times" + echo " -a ADDON_DIR Use addons from DIR. default: none" + echo " -t Type of image to create. Defaults to iso." + echo " -v Enable verbose output." + echo " -h This message." + echo " commands:" + echo " install : where to build the image root" + echo " squash : generate a squashfs image of the installed root" + echo " img : build an image from the working directory" + echo " all : perform all of the above, in order" + exit $1 +} + +while getopts 'i:P:p:a:t:fvh' arg; do + case "${arg}" in + i) CPIOCONFIG="${OPTARG}" ;; + P) PKGFILE="${OPTARG}" ;; + p) PKGLIST="${PKGLIST} ${OPTARG}" ;; + a) ADDON_DIR="${OPTARG}" ;; + t) IMG_TYPE="${OPTARG}" ;; + f) FORCE="y" ;; + v) QUIET="n" ;; + h|?) usage 0 ;; + *) echo "invalid argument '${arg}'"; usage 1 ;; + esac +done + +shift $(($OPTIND - 1)) +echo "ARGS: $@" + +[ $# -le 1 ] && usage 1 + +# do UID checking here so someone can at least get usage instructions +if [ "$EUID" != "0" ]; then + echo "error: This script must be run as root." + exit 1 +fi + +command_name="${1}" +case "${command_name}" in + install) work_dir="${2}" ;; + squash) work_dir="${2}" ;; + img) work_dir="${2}"; imgname="${3}" ;; + all) work_dir="${2}"; imgname="${3}" ;; + *) echo "invalid command name '${command_name}'"; usage 1 ;; +esac + +[ "x${work_dir}" = "x" ] && (echo "please specify a working directory" && usage 1) + +imgroot="${work_dir}/img" +instroot="${work_dir}/install" + +_kversion () +{ + source ${instroot}/etc/mkinitcpio.d/kernel26.kver + echo ${ALL_kver} +} + +# usage: _pacman ... +_pacman () +{ + local ret + if [ "${QUIET}" = "y" ]; then + mkarchroot -f ${instroot} $* 2>&1 >/dev/null + ret=$? + else + mkarchroot -f ${instroot} $* + ret=$? + fi + if [ $ret -ne 0 ]; then + exit 1 + fi +} + +# usage: install_pkgfile +install_pkgfile () +{ + if [ -e "${1}" ]; then + toinstall="" + while read pkg; do + toinstall="${toinstall} ${pkg}" + done < ${1} + _pacman "${toinstall}" + else + echo "error: Package file '${1}' does not exist, aborting." + exit 1 + fi +} + +# Go through the main commands in order. If 'all' was specified, then we want +# to do everything. Start with 'install'. +if [ "${command_name}" = "install" -o "${command_name}" = "all" ]; then + echo "====> Installing/building image root" + if [ -e "${work_dir}" -a "${FORCE}" = "n" ]; then + echo "error: Working dir '${work_dir}' already exists, aborting." + exit 1 + fi + + mkdir -p "${imgroot}" + mkdir -p "${instroot}" + + echo "Installing packages..." + echo " Installing packages from '${PKGFILE}'" + install_pkgfile "${PKGFILE}" + + for pkg in ${PKGLIST}; do + echo " Installing package '${pkg}'" + _pacman "${pkg}" + done + + echo "Updating kernel module dependencies" + kernelver=$(_kversion) + depmod -a -b "${instroot}" "${kernelver}" + # remove the initcpio images that were generated for the host system + find "${instroot}/boot" -name *.img -delete + + echo "Creating default home directory" + install -d -o1000 -g100 -m0755 "${instroot}/home/arch" + + # Cleanup + echo "Cleaning up image root files..." + find "${instroot}" -name *.pacnew -name *.pacsave -name *.pacorig -delete + + # delete a lot of unnecessary cache/log files + kill_dirs="var/abs var/cache/man var/cache/pacman var/log/* var/mail tmp/* initrd" + for x in ${kill_dirs}; do + if [ -e "${instroot}/${x}" ]; then + rm -rf "${instroot}/${x}" + fi + done + + # pacman DBs are big, delete all sync dbs + rm -rf "${instroot}/var/lib/pacman/sync" + + # copy over kernel and grub configs for boot + if [ -e "${instroot}/boot" -a -e "${DEF_CONFIG_DIR}/boot" ]; then + rm -rf "${imgroot}/boot" + cp -r "${instroot}/boot" "${imgroot}" + cp -rf "${DEF_CONFIG_DIR}/boot" "${imgroot}" + fi + + # TODO: this might belong somewhere else + mkdir -p "${imgroot}/addons" + if [ -d "${ADDON_DIR}" ]; then + echo "Copying addons from ${ADDON_DIR}..." + cp -r ${ADDON_DIR}/* "${imgroot}/addons" + fi + + # always make an addon out of DEF_CONFIG_DIR + echo "Creating default-config addon..." + if [ "${QUIET}" = "y" ]; then + mksquashfs "${DEF_CONFIG_DIR}" "${imgroot}/addons/default-config.sqfs" -noappend >/dev/null + else + mksquashfs "${DEF_CONFIG_DIR}" "${imgroot}/addons/default-config.sqfs" -noappend + fi +fi + +# Squash is the next step. +if [ "${command_name}" = "squash" -o "${command_name}" = "all" ]; then + echo "====> Generating SquashFS image" + imagename="${imgroot}/archlive.sqfs" + if [ -e "${imagename}" ]; then + if [ "${FORCE}" = "y" ]; then + echo -n "Removing old SquashFS image..." + rm "${imagename}" + echo "done." + else + echo "error: SquashFS image '${imagename}' already exists, aborting." + exit 1 + fi + fi + + echo "Creating squashfs image. This may take some time..." + start=$(date +%s) + if [ "${QUIET}" = "y" ]; then + mksquashfs "${instroot}" "${imagename}" -noappend >/dev/null + else + mksquashfs "${instroot}" "${imagename}" -noappend + fi + minutes=$(echo $start $(date +%s) | awk '{ printf "%0.2f",($2-$1)/60 }') + echo "Image creation done in $minutes minutes." +fi + +# Finally, make the image. +if [ "${command_name}" = "img" -o "${command_name}" = "all" ]; then + echo "====> Making bootable image" + [ "x${imgname}" = "x" ] && (echo "Bootable image name must be specified" && usage 1) + if [ -e "${imgname}" ]; then + if [ "${FORCE}" = "y" ]; then + echo "Removing existing bootable image..." + rm -rf "${imgname}" + else + echo "error: Image '${imgname}' already exists, aborting." + exit 1 + fi + fi + if [ ! -e "${CPIOCONFIG}" ]; then + echo "error: mkinitcpio config '${CPIOCONFIG}' does not exist, aborting." + exit 1 + fi + + kernelver=$(_kversion) + basedir=${instroot} + [ "${instroot:0:1}" != "/" ] && basedir="$(pwd)/${instroot}" + echo "Generating initcpio for image..." + if [ "${QUIET}" = "y" ]; then + mkinitcpio -c "${CPIOCONFIG}" -b "${basedir}" -k "${kernelver}" -g "${imgroot}/boot/archlive.img" >/dev/null + ret=$? + else + mkinitcpio -c "${CPIOCONFIG}" -b "${basedir}" -k "${kernelver}" -g "${imgroot}/boot/archlive.img" + ret=$? + fi + if [ $ret -ne 0 ]; then + echo "error: initcpio image creation failed..." + exit 1 + fi + + cp ${instroot}/usr/lib/grub/i386-pc/* "${imgroot}/boot/grub" + + if [ "x$IMG_TYPE" == "xdisk" ]; then + echo "Creating DISK image..." + mkusbimg "${imgroot}" "${imgname}" + else + echo "Creating ISO image..." + q="" + [ "${QUIET}" = "y" ] && qflag="-q" + mkisofs ${qflag} -r -l -b "boot/grub/stage2_eltorito" -uid 0 -gid 0 \ + -no-emul-boot -boot-load-size 4 -boot-info-table \ + -publisher "Arch Linux " \ + -input-charset=UTF-8 -p "prepared by $NAME" \ + -A "Arch Linux Live/Rescue CD" \ + -o "${imgname}" "${imgroot}" + fi +fi + +# vim:ts=4:sw=4:et: diff --git a/archiso/mkusbimg b/archiso/mkusbimg new file mode 100755 index 0000000..727bb80 --- /dev/null +++ b/archiso/mkusbimg @@ -0,0 +1,78 @@ +#!/bin/bash +# +# mkusbimg - creates a bootable disk image +# Copyright (C) 2008 Simo Leone +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# usage(exitvalue) +# outputs a usage message and exits with value +APPNAME=$(basename "${0}") +usage() +{ + echo "usage: ${APPNAME} " + exit $1 +} + +################################################## + +if [ $# -ne 2 ]; then + usage 1 +fi + +DISKIMG="${2}" +IMGROOT="${1}" +TMPDIR=$(mktemp -d) +FSIMG=$(mktemp) + +# ext2 overhead's upper bound is 6% +# empirically tested up to 1GB +rootsize=$(du -bs ${IMGROOT}|cut -f1) +IMGSZ=$(( (${rootsize}*106)/100/512 + 1)) # image size in sectors + +# create the filesystem image file +dd if=/dev/zero of="$FSIMG" bs=512 count="$IMGSZ" + +# create a filesystem on the image +mke2fs -m 0 -F "$FSIMG" + +# mount the filesystem and copy data +mount -o loop "$FSIMG" "$TMPDIR" +cp -a "$IMGROOT"/* "$TMPDIR" + +# unmount filesystem +umount "$TMPDIR" + +# add sectors 0-62, then glue together +dd if=/dev/zero of="$DISKIMG" bs=512 count=63 +cat "$FSIMG" >> "$DISKIMG" + +# create a partition table +# if this looks like voodoo, it's because it is +sfdisk -uS -f "$DISKIMG" << EOF +63,$IMGSZ,83,* +0,0,00 +0,0,00 +0,0,00 +EOF + +# install grub on the image +grub --no-floppy --batch << EOF +device (hd0) $DISKIMG +root (hd0,0) +setup (hd0) +EOF + +# all done :) +rm -fr "$TMPDIR" "$FSIMG" diff --git a/archiso/testiso b/archiso/testiso new file mode 100755 index 0000000..9de347a --- /dev/null +++ b/archiso/testiso @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ $# -ne 1 ]; then + echo "usage: testiso " + exit 1 +fi +qemu -boot d -kernel-kqemu -m 256 -cdrom "${1}" -- cgit v1.2.3-70-g09d2