#! /bin/bash PKGLIST="" QUIET="y" FORCE="n" PACCONFIG="/etc/pacman.conf" export LABEL="ARCH_$(date +%Y%m)" PUBLISHER="Arch Linux <http://www.archlinux.org>" APPLICATION="Arch Linux Live/Rescue CD" CREATE_DEFAULT="n" APPNAME=$(basename "${0}") # usage: usage <exitvalue> usage () { echo "usage ${APPNAME} [options] command <command options>" echo " general options:" echo " -f Force overwrite of working files/squashfs image/bootable image" echo " -p PACKAGE(S) Additional package(s) to install, can be used multiple times" echo " -C <file> Config file for pacman. Default $PACCONFIG" echo " -L <label> Set a label for the disk" echo " -P <publisher> Set a publisher for the disk" echo " -A <application> Set an application name for the disk" echo " -d Create default user directory /home/arch" echo " -v Enable verbose output" echo " -h This message" echo " commands:" echo " create <dir>" echo " create a base directory layout to work with" echo " includes all specified packages" echo " iso <dir> <image name>" echo " build an iso image from the working dir" exit $1 } while getopts 'p:C:L:P:A:dfvh' arg; do case "${arg}" in p) PKGLIST="${PKGLIST} ${OPTARG}" ;; C) PACCONFIG="${OPTARG}" ;; L) LABEL="${OPTARG}" ;; P) PUBLISHER="${OPTARG}" ;; A) APPLICATION="${OPTARG}" ;; d) CREATE_DEFAULT="y" ;; f) FORCE="y" ;; v) QUIET="n" ;; h|?) usage 0 ;; *) echo "invalid argument '${arg}'"; usage 1 ;; esac done #trim spaces PKGLIST="$(echo $PKGLIST)" shift $(($OPTIND - 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 if [ ! -f "$PACCONFIG" ]; then echo "error: pacman config file '$PACCONFIG' does not exist" exit 1 fi command_name="${1}" work_dir="" imgname="" case "${command_name}" in create) work_dir="${2}"; imgname="none" ;; iso) work_dir="${2}"; imgname="${3}" ;; *) echo "invalid command name '${command_name}'"; usage 1 ;; esac [ "x${imgname}" = "x" ] && echo "Image name must be specified" && usage 1 [ "x${work_dir}" = "x" ] && echo "Please specify a working directory" && usage 1 echo "${APPNAME} : Configuration Settings" echo " working directory: ${work_dir}" echo " image name: ${imgname}" # usage: _pacman <packages>... _pacman () { local ret if [ "${QUIET}" = "y" ]; then mkarchroot -C "$PACCONFIG" -f "${work_dir}/root-image" $* 2>&1 >/dev/null ret=$? else mkarchroot -C "$PACCONFIG" -f "${work_dir}/root-image" $* ret=$? fi # Cleanup find "${work_dir}" -name *.pacnew -name *.pacsave -name *.pacorig -delete if [ $ret -ne 0 ]; then exit 1 fi } command_create () { echo "====> Creating working directory: ${work_dir}" mkdir -p "${work_dir}/iso/" mkdir -p "${work_dir}/root-image/" echo "# archiso isomounts file # img - location of image/directory to mount relative to addons directory # arch - architecture of this image # mount point - absolute location on the post-initrd root # type - either 'bind' or 'squashfs' for now # syntax: <img> <arch> <mount point> <type> # NOTE: Order matters. If the same file exists in multiple # images, the FIRST one mounted, top-down, will take precedence root-image.sqfs i686 / squashfs #root-image-x86_64.sqfs x86_64 / squashfs" > "${work_dir}/isomounts" echo "README for this archiso created directory All directories in this dir, except for 'iso' will be squashed with squashfs and put into the iso dir as iso/<dirname>.sqfs This should be reflected in the isomounts file The iso dir is later used to build the actual bootable iso. Please ensure the proper bootloader is installed or copied to the iso/ directory. ...TODO: Write more..." > "${work_dir}/README" if [ "${PKGLIST}" != "" ]; then echo "====> Installing packages to '${work_dir}/root-image/'" _pacman "${PKGLIST}" echo "Cleaning up what we can" if [ -d "${work_dir}/root-image/boot/" ]; then # remove the initcpio images that were generated for the host system find "${work_dir}/root-image/boot" -name '*.img' -delete fi if [ ${CREATE_DEFAULT} == "y" ]; then if [ -d "${work_dir}/root-image/home/" ]; then echo "Creating default home directory" install -d -o1000 -g100 -m0755 "${work_dir}/root-image/home/arch" fi fi # Delete pacman database sync cache files (*.tar.gz) find "${work_dir}/root-image/var/lib/pacman" -maxdepth 1 -type f -delete # Delete pacman database sync cache find "${work_dir}/root-image/var/lib/pacman/sync" -delete # Delete pacman package cache find "${work_dir}/root-image/var/cache/pacman/pkg" -type f -delete # Delete all log files, keeps empty dirs. find "${work_dir}/root-image/var/log" -type f -delete # Delete all temporary files and dirs find "${work_dir}/root-image/var/tmp" -mindepth 1 -delete # Delete all temporary files and dirs find "${work_dir}/root-image/tmp" -mindepth 1 -delete fi } # _mksquash dirname _mksquash () { if [ ! -d "$1" ]; then echo "Error: '$1' is not a directory" return 1 fi sqimg="${work_dir}/iso/$(basename ${1}).sqfs" echo "====> Generating SquashFS image for '${1}'" if [ -e "${sqimg}" ]; then dirhaschanged=$(find ${1} -newer ${sqimg}) if [ "${dirhaschanged}" != "" ]; then echo "SquashFS image '${sqimg}' is not up to date, rebuilding..." rm "${sqimg}" else echo "SquashFS image '${sqimg}' is up to date, skipping." return fi fi echo "Creating SquashFS image. This may take some time..." start=$(date +%s) if [ "${QUIET}" = "y" ]; then mksquashfs "${1}" "${sqimg}" -noappend >/dev/null else mksquashfs "${1}" "${sqimg}" -noappend fi minutes=$(echo $start $(date +%s) | awk '{ printf "%0.2f",($2-$1)/60 }') echo "Image creation done in $minutes minutes." } _imgcommon () { for d in $(find "${work_dir}" -maxdepth 1 -type d -name '[^.]*'); do if [ "$d" != "${work_dir}/iso" -a \ "$(basename "$d")" != "iso" -a \ "$d" != "${work_dir}" ]; then _mksquash "$d" fi done echo "====> Making bootable image" # Sanity checks if [ ! -d "${work_dir}/iso" ]; then echo "Error: '${work_dir}/iso' doesn't exist. What did you do?!" exit 1 fi if [ ! -f "${work_dir}/isomounts" ]; then echo "Error: the isomounts file doesn't exist. This image won't do anything" echo " Protecting you from yourself and erroring out here..." exit 1 fi 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 cp "${work_dir}/isomounts" "${work_dir}/iso/" if ! sed "s|archisolabel=[^ ]*|archisolabel=${LABEL}|" -i ${work_dir}/iso/boot/isolinux/isolinux.cfg; then echo "Error: ${work_dir}/iso/boot/isolinux/isolinux.cfg, doesn't exist, aborting." exit 1 fi } command_iso () { _imgcommon echo "Creating ISO image..." qflag="" [ "${QUIET}" = "y" ] && qflag="-quiet" mkisofs ${qflag} -r -l \ -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat \ -uid 0 -gid 0 \ -udf -allow-limited-size -iso-level 3 \ -input-charset utf-8 -p "prepared by mkarchiso" \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -publisher "${PUBLISHER}" \ -A "${APPLICATION}" \ -V "${LABEL}" \ -o "${imgname}" "${work_dir}/iso/" isohybrid "${imgname}" } # Go through the main commands in order. If 'all' was specified, then we want # to do everything. Start with 'install'. if [ "${command_name}" = "create" ]; then command_create fi if [ "${command_name}" = "iso" ]; then command_iso fi # vim:ts=4:sw=4:et: