#!/bin/sh # Boilerplate _root="$(dirname "${0}")"; . "${_root}/lib/env.sh" # Load needed modules want root log alias meh=log alias omg=warn alias wtf=err # Root directory of makeworld ROOT="$(realpath "$(dirname "${0}")/../worlds")" # Makeworld dir structure should contain, at minimum: # script # makeworld (this file) # seed # base # (arch of build host: i386, amd64, etc) # base.* (virgin base tree of same arch as host, used to seed chroot for clean build) # (i386, amd64, etc) # (GENERIC, SABA, SS4200, etc) # config # make.conf # src.conf # CONFIG (Matches config name: GENERIC, SABA, SS4200, etc) # Compute number of simultaneous make jobs (usually 2x cpu/thread count) to set make -j make_cpus="$(sysctl -n hw.ncpu)" make_jobs="$(( ${make_cpus} * 2 ))" # Was the config specified on the command line? if [ "${1}" ] then TARGET="${1%%/*}" CONFIG="${1##*/}" fi # Going to build this config: TARGET="${TARGET:-i386}" CONFIG="${CONFIG:-GENERIC}" MAKEOPTS="-j${make_jobs} ${MAKEOPTS}" # Check if it exists [ -d "${ROOT}/${TARGET}/${CONFIG}" ] || wtf "${TARGET}/${CONFIG} doesn't exist" # Target world directory world="${ROOT}/${TARGET}/${CONFIG}" # Source chroot seed directory seed="${ROOT}/seed/base/$(uname -m)" # Root directory for chroot build="${ROOT}/seed/chroot-${TARGET}-${CONFIG}" # Default build phases phases="${phases:-buildworld buildkernel distrib-dirs installworld installkernel distribution}" date="$(date +%Y%m%d)" # Functions # Prepare chroot for build prepare() { mount | grep -q "${build}" && wtf "Stuff is mounted under ${build}; cannot continue" # Cleanup trap here, so that an abort during prepare can clean up properly trap "cleanup" exit hup int term kill meh "Preparing build chroot" [ -d "${build}" ] && wtf "${build}: directory exists" mkdir -p "${build}" || wtf ls -1 "${seed}"/base.?? >/dev/null 2>&1 || wtf "Populate seed directory ${seed} first" cat "${seed}"/base.?? | tar xCf "${build}" - || wtf mkdir -p "${build}/usr/obj" || wtf meh "Mounting chroot filesystems" mkdir -p "${world}/obj" mkdir -p "${world}/root" mount -t devfs devfs "${build}/dev" || wtf # Mount /usr/src as a union, so that changes to it will not affect the underlying tree # unionfs suffers from deadlocks; don't use it mount -t nullfs -r /usr/src "${build}/usr/src" || wtf mount -t nullfs "${world}/obj" "${build}/usr/obj" || wtf mount -t nullfs "${world}/root" "${build}/mnt" || wtf if [ -d "${world}/config" ] then meh "Installing build-time configuration" [ -f "${world}/config/${CONFIG}" ] && cp "${world}/config/${CONFIG}" "/usr/src/sys/${TARGET}/conf/" [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/" [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/" fi } # Cleanup chroot cleanup() { meh "Cleaning up" umount -f "${build}/mnt" umount -f "${build}/usr/obj" umount -f "${build}/usr/src" umount -f "${build}/dev" mount | grep -q "${build}" && wtf "Stuff is still mounted under ${build}; not removing" chflags -R noschg "${build}" rm -Rf "${build}" trap "" exit hup int term kill } if [ -d "${build}" ] then omg "${build}: directory exists; purging" cleanup fi meh "Making world for ${TARGET}/${CONFIG}" prepare meh "Seed: ${seed}" meh "Config: ${TARGET}/${CONFIG}" meh "Builddir: ${build}" meh "make ${MAKEOPTS}" meh "DESTDIR=${world}/root" # Construct environment for chroot build env=" USER=root HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin SHELL=/bin/sh " for phase in ${phases} do meh "==> Phase: ${phase}" script "${world}/${date}-${phase}.log" env -i ${env} chroot "${build}" sh -c \ "cd /usr/src; time make ${MAKEOPTS} ${phase} TARGET=${TARGET} KERNCONF=${CONFIG} DESTDIR=/mnt" || wtf "chroot-cmd ${phase}" done # Copy the config files into the target, to keep a record of the build options [ -f "${world}/config/${CONFIG}" ] && cp "${world}/config/${CONFIG}" "${build}/boot/kernel/" [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/" [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/"