#!/bin/sh - # Copyright (c) 2006 Jean Milanez Melo # # Patrick Tracanelli # # $FreeBSD$ #set -xv CURRENTDIR=/usr/src/tools/tools/tinybsd if [ ! -d $CURRENTDIR ] then CURRENTDIR=`pwd` else cd $CURRENTDIR fi WORKDIR=/usr/obj/tinybsdbuild KERNCONF=TINYBSD BASEFILE="tinybsd.basefiles" PORTSFILE="tinybsd.ports" PORTSDIR=/usr/ports PKGDIRS=/tmp/pkg.dirs PKGFILES=/tmp/pkg.files DEFINSTARGS="-o 0 -g 0 -m 555" TS="=====>" splitarg1 () { local IFS IFS='=' set $1 echo $1 } splitarg2 () { local IFS IFS='=' set $1 echo $2 } getargs () { ARGS="$*" for arg in $* do ARG=`splitarg1 $arg` VAL=`splitarg2 $arg` case $ARG in sectors) SECTUNIT=$VAL ;; heads) TRACKCYL=$VAL ;; spt) SECTRACK=$VAL ;; conf) CONF=$VAL ;; mfsroot) MFSROOT=$VAL ;; image) IMG=$VAL ;; batch) NO_PROMPTS="YES" ;; new) NO_READ="YES" ;; *) usage ;; esac done } usage () { echo "Woops Usage: $0 sectors= [80000] heads= [4] spt= [32] conf= (see conf/name) [default] mfsroot[=] [no] image= [tinybsd.bin] batch[=] (do not ask interactively) new[=] (do not read previous values) Examples: $0 sectors=65536 heads=8 spt=16 conf=wireless mfsroot=yes image=myimage.img batch Default values are set in the program. Environment values override defaults. Previous values override environment values but can be disabled. Command arguments override previous values. Interactive values override command arguments but can be disabled. Run diskinfo(8) -v against your CF device to get correct information about your disk. USB keys do not need any specific geometry" exit 1 } ######## # Load variables from stdin (could be a file) # Look for lines that match foo=bar # do not run the file.. that is asking for trouble ######## loadvars () { while : do OIFS=$IFS IFS="=" if read PART1 PART2 then IFS="$OIFS" case "$PART1" in \#*) ;; "") ;; *) set "${PART1}" if [ $# = "1" ] then eval "${PART1}='${PART2}'" fi ;; esac else IFS="$OIFS" return 0 fi done } ######## # get values from the user ######## confirm_action(){ local ANSWER local MESSAGE ANSWER=$1 MESSAGE=$2 if [ "$NO_PROMPTS" != "YES" ] then echo -n "$MESSAGE [$ANSWER] " > /dev/tty read result [ "$result" != "" ] && ANSWER=$result fi ANSWER=`eval "echo $ANSWER"` echo $ANSWER } ######## # These are only used the VERY first time you run the program (on this machine) ######## setdefaults () { NO_PROMPTS=${NO_PROMPTS:-NO} NO_READ=${NO_READ:-NO} SECTUNIT=${SECTUNIT:-80000}; export SECTUNIT TRACKCYL=${TRACKCYL:-4}; export TRACKCYL SECTRACK=${SECTRACK:-32}; export SECTRACK CONF=${CONF:-default}; export CONF MFSROOT=${MFSROOT:-NO}; export MFSROOT IMG=${IMG:-tinybsd.bin}; export IMG } ####### # get ourselves set up. # Partly by reading config files and partly from asking questions. ####### loadconfig () { if [ "${NO_READ}" = "YES" ] then return fi HOSTNAME=`hostname` HOSTPART=${HOSTNAME%%.*} FILENAME=".tinybsd.${HOSTPART}.${USER}" FULLFILENAME=$HOME/$FILENAME if [ -f ${FULLFILENAME} ] then loadvars <${FULLFILENAME} fi SECTUNIT=`confirm_action "$SECTUNIT" "512 byte sectors per unit?"` TRACKCYL=`confirm_action "$TRACKCYL" "Tracks per cylinder?"` SECTRACK=`confirm_action "$SECTRACK" "Sectors per track?"` while : do echo "The following configurations exist:" ls -l conf|awk '/^d/{print " ",$9}'|grep -v CVS CONF=`confirm_action "$CONF" "Configuration name?"` if [ ! -d "${CURRENTDIR}/conf/$CONF" ] then echo "${TS} Error: Could not find config (${CONF})" if [ "$NO_PROMPTS" = "YES" ] then exit 1 fi else break fi done MFSROOT=`confirm_action "$MFSROOT" "Use an MFSROOT? (YES/NO)"` IMG=`confirm_action "$IMG" "Image file to generate?"` # example of formatted value (NNN in this case) # #condition and format the number # if [ -z "${BUILDNUM}" ] # then # echo "Starting with build 001" # BUILDNUM="001" # else # BUILDNUM=`printf "%03d\n" $(($BUILDNUM))` # fi } saveconfig () { HOSTNAME=`hostname` HOSTPART=${HOSTNAME%%.*} FILENAME=".tinybsd.${HOSTPART}.${USER}" FULLFILENAME=$HOME/$FILENAME ( echo "# written by tinybsd" `date` echo "SECTUNIT=${SECTUNIT}" echo "TRACKCYL=${TRACKCYL}" echo "SECTRACK=${SECTRACK}" echo "CONF=${CONF}" echo "MFSROOT=${MFSROOT:-NO}" echo "IMG=${IMG}" ) >${FULLFILENAME} } check_alt_imgname() { if [ ${IMG} = 'tinybsd.bin' ] then echo "${TS} Alternative image name not set; defaulting to 'tinybsd.bin'" fi } rotate_buidlog() { mv -f ${HOME}/tinybsd.log ${HOME}/tinybsd.log.old } remove_workdir() { chflags -R noschg ${WORKDIR} echo "${TS} Removing "${WORKDIR} rm -rf ${WORKDIR} echo "${TS} Removing Build Kernel Directory" rm -rf /usr/obj/usr/src/sys/${KERNCONF} echo "${TS} done." } prework() { remove_workdir mkdir -p ${WORKDIR} } create_tree() { echo "${TS} Creating directory hierarchy... " mtree -deU -f /etc/mtree/BSD.root.dist -p ${WORKDIR} mtree -deU -f /etc/mtree/BSD.usr.dist -p ${WORKDIR}/usr mtree -deU -f /etc/mtree/BSD.local.dist -p ${WORKDIR}/usr/local mtree -deU -f /etc/mtree/BSD.var.dist -p ${WORKDIR}/var } copy_binaries() { cd ${CURRENTDIR}/conf/${CONF} for file in `cat ${BASEFILE} | grep -v "#" | \ cut -f1 -d":" | sort | uniq` ; do echo "${TS} Copying "/${file}" to "${WORKDIR}/${file} cp -fp /${file} ${WORKDIR}/${file} ; done } install_ports() { for portname in `cat ${PORTSFILE} | grep -v '#'` ; do cd ${PORTSDIR}/${portname} pkgname=`make -V PKGNAME` pkg_info -VQ ${pkgname} install=`echo $?` if [ ${install} -eq 0 ] ; then echo "$portname is already installed..." create_missingdir copy_ports else make install clean create_missingdir copy_ports fi done } create_missingdir() { pkg_info -L ${pkgname} | egrep -v '(Information|Files|www|share|doc|man|include)' | sort | uniq >> ${PKGDIRS} for dir in `cat ${PKGDIRS}`; do if [ ! -d `dirname ${WORKDIR}/${dir}` ] ; then mkdir -p `dirname ${WORKDIR}/${dir}` fi done rm ${PKGDIRS} } copy_ports() { pkg_info -L ${pkgname} | egrep -v '(Information|Files|www|share|doc|man|include)' >> ${PKGFILES} for port in `cat ${PKGFILES}` ; do echo "${TS} Copying "${port}" to "${WORKDIR}${port} cp -fp ${port} ${WORKDIR}${port} ; done } make_kernel() { echo "${TS} Building customized tiny beastie kernel... " cp -p ${CURRENTDIR}/conf/${CONF}/${KERNCONF} /usr/src/sys/i386/conf cd /usr/src make buildkernel KERNCONF=${KERNCONF} || exit 1 gzip -9 /usr/obj/usr/src/sys/${KERNCONF}/kernel install ${DEFINSTARGS} /usr/obj/usr/src/sys/${KERNCONF}/kernel.gz ${WORKDIR}/boot/kernel/ install ${DEFINSTARGS} \ /usr/obj/usr/src/sys/${KERNCONF}/modules/usr/src/sys/modules/acpi/acpi/acpi.ko \ ${WORKDIR}/boot/kernel install -o 0 -g 0 -m 444 /sys/i386/conf/GENERIC.hints ${WORKDIR}/boot/device.hints } copy_libraries() { TDEPFILE="`mktemp -t deps`" TDEPFILES="`mktemp -t depsymlnk`" cd ${CURRENTDIR}/conf/${CONF} for file in `cat ${BASEFILE} ${PKGFILES} | grep -v "#" | cut -f1 -d":"`; do ldd -f "%p\n" /${file} >> ${TDEPFILE} ; # don't worry on progs been "not dynamic" done rm ${PKGFILES} for libdeplib in `cat ${TDEPFILE} | sort | uniq`; do ldd -f "%p\n" /${libdeplib} >> ${TDEPFILE} ; done for pamdep in `ls -1 /usr/lib/pam*`; do echo $pamdep >> ${TDEPFILE} ; ldd -f "%p\n" /${pamdep} >> ${TDEPFILE} ; done for lib in `cat ${TDEPFILE} | sort | uniq`; do echo "${TS} Copying "${lib}" to "${WORKDIR}${lib} cp -fp ${lib} ${WORKDIR}${lib} ; done for depsymlink in `cat ${TDEPFILE}`; do echo "${TS} Checking if ${depsymlink} is a symbolic link" /bin/ls -l $depsymlink | grep "\->" | awk '{print $11":"$9}' >> ${TDEPFILES} done for i in `cat ${TDEPFILES}`; do SOURCE_FILE=`echo $i | awk -F ":" '{print $1}'` TARGET_FILE=`echo $i | awk -F ":" '{print $2}'` echo "${TS} Unlinking ${WORKDIR}${TARGET_FILE}" chroot ${WORKDIR} /bin/chflags 0 ${TARGET_FILE} chroot ${WORKDIR} /bin/rm -f ${TARGET_FILE} echo "${TS} Symlinking ${SOURCE_FILE} to ${TARGET_FILE}" chroot ${WORKDIR} /bin/ln -s ${SOURCE_FILE} ${TARGET_FILE} done echo -n "${TS} Unlinking " rm -fv ${TDEPFILE} ${TDEPFILES} } deinstall_ports() { for portname in `cat ${PORTSFILE} | grep -v '#'` ; do cd ${PORTSDIR}/${portname} if [ $? -ne ${install} ] ; then make deinstall fi done } create_etc() { cd /usr/src/etc/sendmail/ make freebsd.cf freebsd.submit.cf cd /usr/src/etc/ mkdir -p ${WORKDIR}/var/named/etc/namedb make distribution DESTDIR=${WORKDIR} } create_ssh_keys() { echo "Creating ssh keys..." ssh-keygen -t rsa1 -b 1024 -f ${WORKDIR}/etc/ssh/ssh_host_key -N '' ssh-keygen -t dsa -f ${WORKDIR}/etc/ssh/ssh_host_dsa_key -N '' ssh-keygen -t rsa -f ${WORKDIR}/etc/ssh/ssh_host_rsa_key -N '' } personal_conf() { echo "${TS} Copying your custom configuration on conf/ ..." for custom in `find ${CURRENTDIR}/conf/${CONF}/ -type d -depth 1 \! -name CVS`; do cp -Rp ${custom}/* ${WORKDIR}/${custom#${CURRENTDIR}/conf/${CONF}/}/ done if [ -f ${CURRENTDIR}/conf/${CONF}/boot.config ]; then cp ${CURRENTDIR}/conf/${CONF}/boot.config ${WORKDIR}/boot.config fi } symlinks() { #set -xv for i in `cat ${BASEFILE} ${PORTSFILE} | grep -v "#" | grep ":"`; do SOURCE_FILE=`echo $i | awk -F ":" {'print $1'}` TARGET_FILE=`echo $i | awk -F ":" {'print $2'}` chroot ${WORKDIR} /bin/ln -vs /${SOURCE_FILE} ${TARGET_FILE} done #set +xv } create_image() { VNODEFILE=`mktemp -t tinybsd` IMGMNT=`mktemp -d -t tinybsd` dd if=/dev/zero of=${VNODEFILE} count=${SECTUNIT} MD=`mdconfig -a -t vnode -f ${VNODEFILE} -x ${SECTRACK} -y ${TRACKCYL}` diskinfo -v /dev/${MD} fdisk -I /dev/${MD} fdisk /dev/${MD} cp -p /boot/boot0 ${WORKDIR}/boot/boot0 bsdlabel -w -B /dev/${MD} newfs -O2 -U /dev/${MD}a mount /dev/${MD}a ${IMGMNT} if [ ${MFSROOT} = 'yes' ] then echo "${TS} Creating MFS root..." # Update is not done yet #mkdir -p ${WORKDIR}/usr/local/bin/ #cp -p ${CURRENTDIR}/update/update ${WORKDIR}/usr/local/bin/ rm ${WORKDIR}/etc/fstab cd ${WORKDIR} && find . -print | sed '/kernel/ d' | cpio -dump ${IMGMNT} || true umount ${IMGMNT} dd if=/dev/${MD} of=${CURRENTDIR}/mfsroot.img gzip -9 < ${CURRENTDIR}/mfsroot.img > ${CURRENTDIR}/mfsroot.gz rm ${CURRENTDIR}/mfsroot.img mount /dev/${MD}a ${IMGMNT} rm -rf ${IMGMNT}/* cp -rp ${WORKDIR}/boot ${IMGMNT} rm ${IMGMNT}/boot/device.hints ( \ echo 'set vfs.root.mountfrom="ufs:/dev/md0a"' ; \ echo 'set bootfile="/boot/kernel/kernel"' ; \ sed -e '/^#/ d' -e 's/^/set /' < ${WORKDIR}/boot/device.hints ; \ echo 'load /boot/kernel/kernel' ; \ echo 'echo Loading mfsroot' ; \ echo 'load -t mfs_root /mfsroot' ;\ echo 'boot' ; \ ) > ${IMGMNT}/boot/loader.rc mv ${CURRENTDIR}/mfsroot.gz ${IMGMNT} else ( cd ${WORKDIR} && find . -print | cpio -dump ${IMGMNT} ) || true fi df ${IMGMNT} sleep 1 umount ${IMGMNT} dd if=/dev/${MD} of=${CURRENTDIR}/${IMG} bs=64k rm -vf ${VNODEFILE} rm -rvf ${IMGMNT} mdconfig -d -u ${MD} echo "" echo "${TS} Done!" echo "${TS} Your configuration options were saved in ${FULLFILENAME}" echo "${TS} You can see your build log in ${HOME}/tinybsd.log" echo "${TS} Your final image is in ${CURRENTDIR}/${IMG}" echo "${TS} Now use dd(1) to write it." } ########################## # run things ########################################## ## The actual program ########################################## getargs $* setdefaults # Load as many of the configuration options as we can loadconfig saveconfig # Rotate build log rotate_buidlog # Now start logging. ( # Do the build prework check_alt_imgname create_tree copy_binaries install_ports make_kernel copy_libraries symlinks deinstall_ports create_etc create_ssh_keys personal_conf create_image #set +xv ) 2>&1 |tee -a ${HOME}/tinybsd.log