#!/bin/sh # # Copyright (c) 1994-2009 Poul-Henning Kamp. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD: stable/11/tools/tools/sysbuild/sysbuild.sh 286904 2015-08-18 20:19:48Z phk $ # set -e exec < /dev/null if [ `uname -m` = "i386" -o `uname -m` = "amd64" ] ; then TARGET_PART=`df / | sed ' 1d s/[ ].*// s,/dev/,, s,s1a,s3a, s,s2a,s1a, s,s3a,s2a, '` FREEBSD_PART=`sed -n \ -e 's/#.*//' \ -e '/[ ]\/freebsd[ ]/!d' \ -e 's/[ ].*//p' \ /etc/fstab` # Calculate a suggested gpart command TARGET_DISK=`expr ${TARGET_PART} : '\(.*\)s[12]a$' || true` TARGET_SLICE=`expr ${TARGET_PART} : '.*s\([12]\)a$' || true` GPART_SUGGESTION="gpart set -a active -i $TARGET_SLICE /dev/$TARGET_DISK" unset TARGET_DISK TARGET_SLICE else TARGET_PART=unknown FREEBSD_PART=unknown GPART_SUGGESTION=unknown fi # Relative to /freebsd PORTS_PATH=ports SRC_PATH=src # OBJ_PATH=obj # Name of kernel KERNCONF=GENERIC # srcconf #SRCCONF="SRCCONF=/usr/src/src.conf" # -j arg to make(1) ncpu=`sysctl -n kern.smp.cpus` if [ $ncpu -gt 1 ] ; then JARG="-j $ncpu" fi # serial console ? SERCONS=false PKG_DIR=/usr/ports/packages/All # Remotely mounted distfiles # REMOTEDISTFILES=fs:/rdonly/distfiles # Proxy #FTP_PROXY=http://127.0.0.1:3128/ #HTTP_PROXY=http://127.0.0.1:3128/ #export FTP_PROXY HTTP_PROXY PORTS_WE_WANT=' ' PORTS_OPTS="BATCH=YES A4=yes" CONFIGFILES=' ' SBMNT="/mnt.sysbuild" cleanup() ( ) before_ports() ( ) before_ports_chroot() ( ) final_root() ( ) final_chroot() ( ) ####################################################################### # -P is a pretty neat way to clean junk out from your ports dist-files: # # mkdir /freebsd/ports/distfiles.old # mv /freebsd/ports/distfiles/* /freebsd/ports/distfiles.old # sh sysbuild.sh -c $yourconfig -P /freebsd/ports/distfiles.old # rm -rf /freebsd/ports/distfiles.old # # Unfortunately bsd.ports.mk does not attempt to use a hard-link so # while this runs you need diskspace for both your old and your "new" # distfiles. # ####################################################################### usage () { ( echo "Usage: $0 [-b/-k/-w] [-c config_file]" echo " -b suppress builds (both kernel and world)" echo " -k suppress buildkernel" echo " -w suppress buildworld" echo " -p used cached packages" echo " -P prefetch ports" echo " -c specify config file" ) 1>&2 exit 2 } ####################################################################### ####################################################################### if [ ! -f $0 ] ; then echo "Must be able to access self ($0)" 1>&2 exit 1 fi if grep -q 'Magic String: 0`0nQT40W%l,CX&' $0 ; then true else echo "self ($0) does not contain magic string" 1>&2 exit 1 fi ####################################################################### set -e log_it() ( a="$*" set `cat /tmp/_sb_log` TX=`date +%s` echo "$1 $TX" > /tmp/_sb_log DT=`expr $TX - $1 || true` DL=`expr $TX - $2 || true` echo -n "### `date +%H:%M:%S`" printf " ### %5d ### %5d ### %s\n" $DT $DL "$a" ) ####################################################################### ports_recurse() ( cd /usr/ports t=$1 shift if [ "x$t" = "x." ] ; then true > /tmp/_.plist true > /tmp/_.plist.tdone echo 'digraph {' > /tmp/_.plist.dot fi if grep -q "^$t\$" /tmp/_.plist.tdone ; then return fi echo "$t" >> /tmp/_.plist.tdone for d do if [ ! -d $d ] ; then echo "Missing port $d" 1>&2 continue fi d=`cd /usr/ports && cd $d && /bin/pwd` if [ ! -f $d/Makefile ] ; then echo "Missing port $d" 1>&2 continue fi if [ "x$t" != "x." ] ; then echo "\"$t\" -> \"$d\"" >> /tmp/_.plist.dot fi if grep -q "^$d\$" /tmp/_.plist ; then true elif grep -q "^$d\$" /tmp/_.plist.tdone ; then true else ( cd $d l="" for a in `make -V _UNIFIED_DEPENDS ${PORTS_OPTS}` do x=`expr "$a" : '.*:\(.*\)'` l="${l} ${x}" done ports_recurse $d $l # -> _UNIFIED_DEPENDS #ports_recurse $d `make -V _DEPEND_DIRS ${PORTS_OPTS}` #ports_recurse $d `make all-depends-list` ) echo "$d" >> /tmp/_.plist fi done if [ "x$t" = "x." ] ; then echo '}' >> /tmp/_.plist.dot fi ) ports_build() ( ports_recurse . $PORTS_WE_WANT if [ "x${PKG_DIR}" != "x" ] ; then mkdir -p ${PKG_DIR} fi pd=`cd /usr/ports && /bin/pwd` # Now build & install them for p in `cat /tmp/_.plist` do b=`echo $p | tr / _` t=`echo $p | sed "s,${pd},,"` pn=`cd $p && make package-name` if [ "x`basename $p`" == "xpkg" ] ; then log_it "Very Special: $t ($pn)" ( cd $p make clean all install ${PORTS_OPTS} ) > _.$b 2>&1 < /dev/null continue fi if pkg info $pn > /dev/null 2>&1 ; then log_it "Already installed: $t ($pn)" continue fi if [ "x${PKG_DIR}" != "x" -a -f ${PKG_DIR}/$pn.txz ] ; then if [ "x$use_pkg" = "x-p" ] ; then log_it "Install $t ($pn)" ( set +e pkg add ${PKG_DIR}/$pn.txz || true ) > _.$b 2>&1 < /dev/null continue fi fi miss=`(cd $p ; make missing ${PORTS_OPTS}) || true` if [ "x${miss}" != "x" ] ; then log_it "MISSING for $p:" $miss continue fi log_it "build $pn ($p)" ( set +e cd $p make clean ${PORTS_OPTS} if make install ${PORTS_OPTS} ; then if [ "x${PKG_DIR}" != "x" ] ; then make package ${PORTS_OPTS} fi else log_it FAIL build $p fi make clean ) > _.$b 2>&1 < /dev/null done ) ports_prefetch() ( ( set +x ldir=$1 true > /${ldir}/_.prefetch echo "Building /tmp/_.plist" >> /${ldir}/_.prefetch ports_recurse . $PORTS_WE_WANT echo "Completed /tmp/_.plist" >> /${ldir}/_.prefetch # Now checksump/fetch them for p in `cat /tmp/_.plist` do b=`echo $p | tr / _` ( cd $p if make checksum $PORTS_OPTS ; then rm -f /${ldir}/_.prefetch.$b echo "OK $p" >> /${ldir}/_.prefetch exit 0 fi make distclean make checksum $PORTS_OPTS || true if make checksum $PORTS_OPTS > /dev/null 2>&1 ; then rm -f /${ldir}/_.prefetch.$b echo "OK $p" >> /${ldir}/_.prefetch else echo "BAD $p" >> /${ldir}/_.prefetch fi ) > /${ldir}/_.prefetch.$b 2>&1 done echo "Done" >> /${ldir}/_.prefetch ) ) ####################################################################### do_world=true do_kernel=true do_prefetch=false use_pkg="" c_arg="" set +e args=`getopt bc:hkpP:w $*` if [ $? -ne 0 ] ; then usage fi set -e set -- $args for i do case "$i" in -b) shift; do_world=false do_kernel=false ;; -c) c_arg=$2 if [ ! -f "$c_arg" ] ; then echo "Cannot read $c_arg" 1>&2 usage fi . "$2" shift shift ;; -h) usage ;; -k) shift; do_kernel=false ;; -p) shift; use_pkg="-p" ;; -P) shift; do_prefetch=true distfile_cache=$1 shift; ;; -w) shift; do_world=false ;; --) shift break; ;; esac done ####################################################################### if [ "x$1" = "xchroot_script" ] ; then set -e shift before_ports_chroot ports_build exit 0 fi if [ "x$1" = "xfinal_chroot" ] ; then final_chroot exit 0 fi if [ $# -gt 0 ] ; then echo "$0: Extraneous arguments supplied" usage fi ####################################################################### T0=`date +%s` echo $T0 $T0 > /tmp/_sb_log [ ! -d ${SBMNT} ] && mkdir -p ${SBMNT} if $do_prefetch ; then rm -rf /tmp/sysbuild/ports mkdir -p /tmp/sysbuild/ports ln -s ${distfile_cache} /tmp/sysbuild/ports/distfiles export PORTS_OPTS=CD_MOUNTPTS=/tmp/sysbuild ports_prefetch /tmp exit 0 fi log_it Unmount everything ( ( cleanup ) umount /freebsd/distfiles || true umount ${SBMNT}/freebsd/distfiles || true umount ${FREEBSD_PART} || true umount ${SBMNT}/freebsd || true umount ${SBMNT}/dev || true umount ${SBMNT} || true umount /dev/${TARGET_PART} || true ) # > /dev/null 2>&1 log_it Prepare running image mkdir -p /freebsd mount ${FREEBSD_PART} /freebsd ####################################################################### if [ ! -d /freebsd/${PORTS_PATH} ] ; then echo PORTS_PATH does not exist 1>&2 exit 1 fi if [ ! -d /freebsd/${SRC_PATH} ] ; then echo SRC_PATH does not exist 1>&2 exit 1 fi log_it TARGET_PART $TARGET_PART sleep 5 rm -rf /usr/ports ln -s /freebsd/${PORTS_PATH} /usr/ports rm -rf /usr/src ln -s /freebsd/${SRC_PATH} /usr/src if $do_world ; then if [ "x${OBJ_PATH}" != "x" ] ; then rm -rf /usr/obj mkdir -p /freebsd/${OBJ_PATH} ln -s /freebsd/${OBJ_PATH} /usr/obj else rm -rf /usr/obj mkdir -p /usr/obj fi fi ####################################################################### for i in ${PORTS_WE_WANT} do ( cd /usr/ports if [ ! -d $i ] ; then echo "Port $i not found" 1>&2 exit 2 fi ) done export PORTS_WE_WANT export PORTS_OPTS ####################################################################### log_it Prepare destination partition newfs -t -E -O2 -U /dev/${TARGET_PART} > /dev/null mount /dev/${TARGET_PART} ${SBMNT} mkdir -p ${SBMNT}/dev mount -t devfs devfs ${SBMNT}/dev if [ "x${REMOTEDISTFILES}" != "x" ] ; then rm -rf /freebsd/${PORTS_PATH}/distfiles ln -s /freebsd/distfiles /freebsd/${PORTS_PATH}/distfiles mkdir -p /freebsd/distfiles mount ${REMOTEDISTFILES} /freebsd/distfiles fi log_it copy ports config files (cd / ; find var/db/ports -print | cpio -dumpv ${SBMNT} > /dev/null 2>&1) log_it "Start prefetch of ports distfiles" ports_prefetch ${SBMNT} & if $do_world ; then ( cd /usr/src log_it "Buildworld" make ${JARG} -s buildworld ${SRCCONF} > ${SBMNT}/_.bw 2>&1 ) fi if $do_kernel ; then ( cd /usr/src log_it "Buildkernel" make ${JARG} -s buildkernel KERNCONF=$KERNCONF > ${SBMNT}/_.bk 2>&1 ) fi log_it Installworld (cd /usr/src && make ${JARG} installworld DESTDIR=${SBMNT} ${SRCCONF} ) \ > ${SBMNT}/_.iw 2>&1 log_it distribution (cd /usr/src/etc && make -m /usr/src/share/mk distribution DESTDIR=${SBMNT} ${SRCCONF} ) \ > ${SBMNT}/_.dist 2>&1 log_it Installkernel (cd /usr/src && make ${JARG} installkernel DESTDIR=${SBMNT} KERNCONF=$KERNCONF ) \ > ${SBMNT}/_.ik 2>&1 if [ "x${OBJ_PATH}" != "x" ] ; then rmdir ${SBMNT}/usr/obj ln -s /freebsd/${OBJ_PATH} ${SBMNT}/usr/obj fi log_it Wait for ports prefetch log_it "(Tail ${SBMNT}/_.prefetch for progress)" wait log_it Move filesystems if [ "x${REMOTEDISTFILES}" != "x" ] ; then umount /freebsd/distfiles fi umount ${FREEBSD_PART} || true mkdir -p ${SBMNT}/freebsd mount ${FREEBSD_PART} ${SBMNT}/freebsd if [ "x${REMOTEDISTFILES}" != "x" ] ; then mount ${REMOTEDISTFILES} ${SBMNT}/freebsd/distfiles fi rm -rf ${SBMNT}/usr/ports || true ln -s /freebsd/${PORTS_PATH} ${SBMNT}/usr/ports rm -rf ${SBMNT}/usr/src || true ln -s /freebsd/${SRC_PATH} ${SBMNT}/usr/src log_it Build and install ports # Make sure fetching will work in the chroot if [ -f /etc/resolv.conf ] ; then log_it copy resolv.conf cp /etc/resolv.conf ${SBMNT}/etc chflags schg ${SBMNT}/etc/resolv.conf fi if [ -f /etc/localtime ] ; then log_it copy localtime cp /etc/localtime ${SBMNT}/etc fi log_it ldconfig in chroot chroot ${SBMNT} sh /etc/rc.d/ldconfig start log_it before_ports ( before_ports ) log_it fixing fstab sed "/[ ]\/[ ]/s;^[^ ]*[ ];/dev/${TARGET_PART} ;" \ /etc/fstab > ${SBMNT}/etc/fstab log_it build ports cp $0 ${SBMNT}/root cp /tmp/_sb_log ${SBMNT}/tmp b=`basename $0` if [ "x$c_arg" != "x" ] ; then cp $c_arg ${SBMNT}/root chroot ${SBMNT} sh /root/$0 -c /root/`basename $c_arg` $use_pkg chroot_script else chroot ${SBMNT} sh /root/$0 $use_pkg chroot_script fi cp ${SBMNT}/tmp/_sb_log /tmp log_it create all mountpoints grep -v '^[ ]*#' ${SBMNT}/etc/fstab | while read a b c do mkdir -p ${SBMNT}/$b done if [ "x$SERCONS" != "xfalse" ] ; then log_it serial console echo " -h" > ${SBMNT}/boot.config sed -i "" -e /ttyd0/s/off/on/ ${SBMNT}/etc/ttys sed -i "" -e /ttyu0/s/off/on/ ${SBMNT}/etc/ttys sed -i "" -e '/^ttyv[0-8]/s/ on/ off/' ${SBMNT}/etc/ttys fi log_it move dist config files "(expect warnings)" ( cd ${SBMNT} mkdir root/configfiles_dist find ${CONFIGFILES} -print | cpio -dumpv root/configfiles_dist ) log_it copy live config files (cd / && find ${CONFIGFILES} -print | cpio -dumpv ${SBMNT}) log_it final_root ( final_root ) log_it final_chroot cp /tmp/_sb_log ${SBMNT}/tmp if [ "x$c_arg" != "x" ] ; then chroot ${SBMNT} sh /root/$0 -c /root/`basename $c_arg` final_chroot else chroot ${SBMNT} sh /root/$0 final_chroot fi cp ${SBMNT}/tmp/_sb_log /tmp log_it "Check these messages (if any):" grep '^Stop' ${SBMNT}/_* || true log_it DONE echo "Now you probably want to:" echo " $GPART_SUGGESTION" echo " shutdown -r now"