#!/bin/sh
# $FiG: config/freebsd/builder01/root/bin/create-and-populate-new-BE.sh,v 1.17 2020-06-10 07:54:53 trond Exp $
# $BSDnet: config/freebsd/enterprise/root/bin/create-and-populate-new-BE.sh,v 1.6 2020-06-10 08:40:15 trond Exp $
#set -x

# Specify which kernel to install.
#KERNCONF=GENERIC
KERNCONF=`sysctl -n kern.ident`

# Specify where to place the typescripts.
TYPESCRIPT_DIR=/mnt/root/tmp
#TYPESCRIPT_DIR=/usr/src

# Specify where to temporary mount the new BEs, typically /mnt.
DESTDIR=/mnt

# Determine a suitable svn executable.
SVN_CANDIDATES="/usr/local/bin/svn /usr/bin/svn /usr/bin/svnlite"

for cand in ${SVN_CANDIDATES}; do
  if [ -x ${cand} ]; then
    SVN=${cand}
    break
  fi
done

if [ -z "${SVN}" ]; then
  echo "${0}: neither of ${SVN_CANDIDATES} are useable" >/dev/stderr
  exit 69
fi

# Ensure / is of type ZFS.
if [ -z "`/bin/df -Tt zfs /`" ]; then
  echo $0: root filesystem must be of type ZFS >/dev/stderr
  exit 69
fi

# Ensure /usr/src is mounted, be it NFS or local fs.
if [ ! -f /usr/src/Makefile ]; then
  /sbin/mount /usr/src

  if [ ! -f /usr/src/Makefile ]; then
    echo $0: unable to mount /usr/src >/dev/stderr
    exit 69
  fi
fi

# Ensure /usr/obj is mounted, be it NFS or local fs.
if [ ! -d /usr/obj/usr ]; then
  /sbin/mount /usr/obj

  if [ ! -d /usr/obj/usr ]; then
    echo $0: unable to mount /usr/obj >/dev/stderr
    exit 69
  fi
fi

# What's the name of the current BE?
CURRENT_BE=`/bin/df / | /usr/bin/tail -1 | /usr/bin/awk '{print $1}'`
if [ -z "${CURRENT_BE}" ]; then
  echo "$0: zero length CURRENT_BE" >/dev/stderr
  exit 69
fi

# What's the current date given local time?
CURRENT_DATE=`/bin/date +%Y%m%d`
if [ -z "${CURRENT_DATE}" ]; then
  echo "$0: zero length CURRENT_DATE" >/dev/stderr
  exit 69
fi

# What's the global revision number?
#SVN_REVISION=`/usr/bin/grep 'Revision' /usr/src/svn-info.txt | /usr/bin/cut -d ' ' -f 2`
SVN_REVISION=`${SVN} info --show-item revision /usr/src`
if [ -z "${SVN_REVISION}" ]; then
  echo "$0: zero length SVN_REVISION" >/dev/stderr
  exit 69
fi

# Construct the name of the snapshot.
NEW_SNAPSHOT="${CURRENT_BE}@r${SVN_REVISION}"

# Get the root of the BEs.
BE_ROOT=`/usr/bin/dirname ${CURRENT_BE}`
if [ -z "${BE_ROOT}" ]; then
  echo "$0: zero length BE_ROOT" >/dev/stderr
  exit 69
fi

# Get the name of the root pool.
ROOT_POOL=`echo ${BE_ROOT} | /usr/bin/cut -d / -f 1`
if [ -z "${ROOT_POOL}" ]; then
  echo "$0: zero length ROOT_POOL" >/dev/stderr
  exit 69
fi

# Construct the name of the new BE.
NEW_BE="${BE_ROOT}/${CURRENT_DATE}-r${SVN_REVISION}"

# Run pre-flight checks. This is an interactive step.
/usr/sbin/mergemaster -Fp || exit

# Create the snapshot and the new BE.
/sbin/zfs snapshot ${NEW_SNAPSHOT} || exit
/sbin/zfs clone -o mountpoint=${DESTDIR} ${NEW_SNAPSHOT} ${NEW_BE} || exit

# Merge any changes to the configuration files. This is an interactive step.
/usr/sbin/mergemaster -D ${DESTDIR} -Fi || exit

# Ensure we have somewhere to place the typescripts.
if [ ! -d ${TYPESCRIPT_DIR} ]; then
  /bin/mkdir -p ${TYPESCRIPT_DIR}

  if [ ! -d ${TYPESCRIPT_DIR} ]; then
    echo $0: unable to create ${TYPESCRIPT_DIR} >/dev/stderr
    exit 69
  fi
fi

# Remove previous typescripts.
/bin/rm -f -- ${TYPESCRIPT_DIR}/make-installworld-installkernel-*.txt ${TYPESCRIPT_DIR}/make-check-old-*.txt ${TYPESCRIPT_DIR}/make-delete-old-*.txt

# Install new world and kernel into the new BE.
/usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-installworld-installkernel-${CURRENT_DATE}-r${SVN_REVISION}.txt /usr/bin/make -C /usr/src -j `/sbin/sysctl -n hw.ncpu` DESTDIR=${DESTDIR} KERNCONF=${KERNCONF} installworld installkernel || exit

# Check to see if there's something old and outdated.
/usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-check-old-${CURRENT_DATE}-r${SVN_REVISION}.txt /usr/bin/make -C /usr/src DESTDIR=${DESTDIR} check-old || exit

# Remove any old files.
/usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-delete-old-${CURRENT_DATE}-r${SVN_REVISION}.txt /usr/bin/make -C /usr/src -D BATCH_DELETE_OLD_FILES DESTDIR=${DESTDIR} delete-old || exit

# Remove any old libraries.
/usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-delete-old-libs-${CURRENT_DATE}-r${SVN_REVISION}.txt /usr/bin/make -C /usr/src -D BATCH_DELETE_OLD_FILES DESTDIR=${DESTDIR} delete-old-libs || exit

# Check to see if there's still something old and outdated.
/usr/bin/script -at 0 ${TYPESCRIPT_DIR}/make-check-old-${CURRENT_DATE}-r${SVN_REVISION}.txt /usr/bin/make -C /usr/src DESTDIR=${DESTDIR} check-old || exit

# Unmount the NFS mounted filesystems if needed.
if [ "`/bin/df -T /usr/src | /usr/bin/tail -1 | /usr/bin/awk '{print $2}'`" = "nfs" ]; then
  /sbin/umount /usr/src || exit
fi
if [ "`/bin/df -T /usr/obj | /usr/bin/tail -1 | /usr/bin/awk '{print $2}'`" = "nfs" ]; then
  /sbin/umount /usr/obj || exit
fi

# Unconditionally remove any traces of any (false) NFS mounts.
/bin/rm -f -- ${DESTDIR}/var/db/mounttab

# Enable this if you have bemigrate.sh stored as /etc/rc.d/bemigrate
# and also have set bemigrate_enable="YES" in /etc/rc.conf.
# Place the /firstboot marker in the new BE.
/usr/bin/touch ${DESTDIR}/firstboot

# Inherit the mountpoint and set the bootfs zpool property.
/sbin/zfs inherit mountpoint ${NEW_BE} || exit
/sbin/zpool set bootfs=${NEW_BE} ${ROOT_POOL} || exit

# Ready to reboot into the new BE.
echo $0: ready to boot into ${NEW_BE}

# EOF
