• install to $j/base
  • create $j/etc $j/var $j/home $j/tmp $j/usrlocal etc
  • null-ro mount $j/base to $j/root
  • null-rw mount $j/etc to $j/root/etc
  • null-rw mount $j/var to $j/root/var
  • etc...
  • when upgrade time, diff $j/etc against $j/base/etc to see what was edited and how
  • upgrade $j/base
  • copy $j/base to $j/etc and apply the patches for changed items
  • things like var can be updated by running the var mtree over it
  • things like home and stuff don't need to be upgraded
  • Or just use mergemaster to maintain etc/ and that should take care of upgrading var/ from the mtree files during the next boot

NIS Setup in Jails

sudo sh -ex <<"EOF"
# Prepare a new basefs
DESTDIR=/srv/jail/base/9.1-RELEASE-p2-r249029+991d5e0
rm -Rf ${DESTDIR} || chflags -R noschg ${DESTDIR} && rm -Rf ${DESTDIR}
mkdir ${DESTDIR}
make -C /usr/src -D CDN_JAIL DESTDIR=${DESTDIR} distrib-dirs installworld distribution
rmdir ${DESTDIR}/usr/local ${DESTDIR}/local || true
mkdir  ${DESTDIR}/local
ln -s ../local ${DESTDIR}/usr/local
rmdir ${DESTDIR}/usr/home ${DESTDIR}/home || true
mkdir ${DESTDIR}/home
ln -s ../home ${DESTDIR}/usr/home
mkdir -p ${DESTDIR}/srv
echo "nameserver 10.4.4.1" > "${DESTDIR}/etc/resolv.conf"
ln -s /usr/local/etc/bash-config/bash_profile "${DESTDIR}/usr/share/skel/dot.bash_profile"
ln -s /usr/local/etc/bash-config/bashrc "${DESTDIR}/usr/share/skel/dot.bashrc"
# Generate mergemaster mtree so that mergemaster will work sanely in the future
/usr/src/release/scripts/mm-mtree.sh -D "${DESTDIR}"
# Generate mergemaster update pack

# Also pre-configure certain common settings (NIS maps, etc)
EOF
sudo sh -ex <<"EOF"
# Create a new jail
source="9.1-RELEASE-p2-r249029+991d5e0"
target="/srv/jail/newfreenet"
fstab="${target}/fstab"
fsfs="${target}/fs"
base="${fsfs}/base"
root="${target}/root"

mkdir -p "${fsfs}" "${root}"
ln -svf "../../base/${source}" "${base}"
echo "${base}  ${root}  nullfs  ro  0 0" >> "${fstab}"

# /etc is a union overlay; only store the changed files, as that will make later upgrades much easier.
mkdir -p "${fsfs}/etc"
echo "${fsfs}/etc  ${root}/etc  unionfs  rw,noatime,copymode=transparent,whiteout=whenneeded  0 0" >> "${fstab}"

# All other writable filesystems are local to this jail, and should be populated as needed.
# For instance, /var will be populated by /etc/rc.d/var on boot if necessary, and /local will be populated when the first port is installed.
for fs in home local root srv tmp var
do
  mkdir -p "${fsfs}/${fs}"
  cp -pr "${base}/${fs}/" "${fsfs}/${fs}/"
  echo "${fsfs}/${fs}  ${root}/${fs}  nullfs  rw  0 0" >> "${fstab}"
done

echo "# If you use the devfs line, make sure mount.devfs is not used in jail.conf, or mount.nodevfs is" >> "${fstab}"
echo "#devfs  ${root}/dev  devfs  rw  0 0" >> "${fstab}"
echo "#fdescfs  ${root}/dev/fd  fdescfs  rw  0 0" >> "${fstab}"
echo "proc  ${root}/proc  procfs  rw  0 0" >> "${fstab}"
EOF

Sources

Modify src.conf to support building specially pruned CDN Jail worlds by excluding unnecessary functionality

/etc/src.conf

.if defined(CDN_JAIL)

# Kernel targets make no sense for CDN Jails
.if make(buildkernel) || make(installkernel) || make(kernel)
. error Kernels aren't used in CDN Jails!
.endif

# Avoid foot-shooting during installworld
.if make(installworld) && !defined(DESTDIR)
. error Define DESTDIR when using CDN_JAIL!
.endif

# Put the build artifacts in a different location, to support plural builds
MAKEOBJDIRPREFIX?=/usr/obj/CDN_JAIL

# Set to not build acpiconf(8), acpidump(8) and related programs.
WITHOUT_ACPI=yes
# Set to not build amd(8) and related programs.
WITHOUT_AMD=yes
# Set to not build apm(8), apmd(8) and related programs.
WITHOUT_APM=yes
# Set to not build programs and libraries related to ATM networking.
WITHOUT_ATM=yes
# Set to not build Bluetooth related kernel modules, programs and libraries.
WITHOUT_BLUETOOTH=yes
# Set to not build the boot blocks and loader.
WITHOUT_BOOT=yes
# Set to not build or install programs for operating floppy disk driver.
WITHOUT_FLOPPY=yes
# Set to not build freebsd-update(8).
WITHOUT_FREEBSD_UPDATE=yes
# Set to not build games.
WITHOUT_GAMES=yes
# Set to not build gpioctl(8) as part of the base system.
WITHOUT_GPIO=yes
# Set to not build programs and libraries related to IPX networking.
# When set, it also enforces the following options:
# WITHOUT_IPX_SUPPORT
# WITHOUT_NCP
WITHOUT_IPX=yes
# Set to not build programs that support a legacy PC console; e.g. kbdcontrol(8)
# and vidcontrol(8).
WITHOUT_LEGACY_CONSOLE=yes
# Set to not build lpr(1) and related programs.
WITHOUT_LPR=yes
# Set to not build programs and libraries related to NDIS emulation support.
WITHOUT_NDIS=yes
# Set to not build ntpd(8) and related programs.
WITHOUT_NTP=yes
# Set to not build pmccontrol(8) and related programs.
WITHOUT_PMC=yes
# Set to not build or install portsnap(8) and related files.
WITHOUT_PORTSNAP=yes
# Set to not build rescue(8).
WITHOUT_RESCUE=yes
# Set to not build routed(8) utility.
WITHOUT_ROUTED=yes
# Set to not build sendmail(8) and related programs.
WITHOUT_SENDMAIL=yes
# Set to not build syscons(4) support files such as keyboard maps, fonts, and
# screen output maps.
WITHOUT_SYSCONS=yes
# Set to not build sysinstall(8) and related programs.
WITHOUT_SYSINSTALL=yes
# Set to not build USB-related programs and libraries.
WITHOUT_USB=yes
# Set to not build programs used for 802.11 wireless networks; especially
# wpa_supplicant(8) and hostapd(8). When set, it also enforces the following
# options:
# WITHOUT_WIRELESS_SUPPORT
WITHOUT_WIRELESS=yes

# Additionally, disable compiler and binutils installation, but not building
.if !make(toolchain) && !make(buildworld)
# Set to not install programs used for program development, compilers,
#  debuggers, etc.
# implies WITHOUT_BINUTILS, WITHOUT_CLANG, WITHOUT_CLANG_IS_CC, WITHOUT_GCC,
#  WITHOUT_GDB
WITHOUT_TOOLCHAIN=yes
# Set to not build cpp(1)
WITHOUT_CPP=yes
# Set to not build g++(1) and related libraries. It will also prevent building
#  of gperf(1) and devd(8).
# implies WITHOUT_CLANG, WITHOUT_CLANG_IS_CC, WITHOUT_GROFF
WITHOUT_CXX=yes
.endif

.endif

poudriere builds packages into jenga.den:/srv/www/root/packages/cdnjail-cdn/ using ports tree cdn and jail cdnjail

/usr/local/etc/poudriere.conf

ZPOOL=jenga
FREEBSD_HOST=http://jenga.den.cyberleo.net # make release into /pub/FreeBSD/releases/amd64/amd64/9.1-RELEASE-CDNJAIL/
BASEFS=/poudriere
DISTFILES_CACHE=/var/ports/distfiles # shared with host
CCACHE_DIR=/poudriere/ccache
export HTTP_PROXY=http://gateway.den.cyberleo.net:46565
export FTP_PROXY=http://gateway.den.cyberleo.net:46565
ALLOW_MAKE_JOBS=yes
portmaster ports-mgmt/poudriere devel/ccache www/lighttpd

It would be a good idea to figure out how to patch the portmaster packages, so that pkg_add'ing the portmaster package from a given repo automatically configures portmaster to source from that repo: (+CONTENTS)

...
etc/portmaster.rc.cdn
@comment MD5:421674373d2e1b1ddbac1259d58555a4
...
@exec [ -e "%D/etc/portmaster.rc" ] ||  cp %D/etc/portmaster.rc.cdn %D/etc/portmaster.rc
@unexec diff -q %D/etc/portmaster.rc.cdn %D/etc/portmaster.rc && rm %D/etc/portmaster.rc

This stuff goes on the ports-tree-less target box:

Using this method, /usr/ports MUST NOT EXIST WHATSOEVER OR PORTMASTER WILL BITCH AT YOU WITH AN UNINTELLIGIBLE ERROR MESSAGE THAT YOU WILL SPEND HOURS TRYING TO DEBUG BEFORE JUST DELETING THE DIRECTORY AND FUCK.

/usr/local/etc/portmaster.rc

# Look for INDEX-9.bz2 here
MASTER_SITE_INDEX=https://pkg.cyberleo.net/packages/cdnjail-cdn/
# Look for packages here; should point to the directory containing All, Latest, et alia
PACKAGESITE=${MASTER_SITE_INDEX}
# Store the downloaded packages here
PACKAGES=/tmp
# Use packages only; never try to use ports tree
PM_PACKAGES=only
# Use INDEX for port version information
PM_INDEX=yes
# Use only INDEX; never try to use ports tree
PM_INDEX_ONLY=pm_index_only

Install portmaster and cdn-base from newly configured repo

PACKAGESITE=https://pkg.cyberleo.net/packages/cdnjail-cdn/Latest/ pkg_add -r portmaster
portmaster misc-cdn/cdn-base

Show root and leaf port origins on the current machine

portmaster --list-origins

Check that ports are up to date without updating anything

portmaster -an

Download packages before installing them

portmaster -aF

Install them; keep track of what was installed!

portmaster -a

Reinstall things depending upon upgraded packages, or else weird things can happen; you'll have to build the command line manually, based on results of installation step.

portmaster -R -r mysql-client-5.5.32 -r pcre-8.33 -r ...

If you have removed /tmp/portmaster-download before the portmaster install, this sed should emit a proper command line based upon what has been downloaded by portmaster for installation.

ls -1 /tmp/portmaster-download | sed -ne '1{h;s/^.*$/portmaster -R/;x;};//{s/\.tbz$//;H;};${g;s/\n/ -r /g;s#$# < /dev/tty#p;}'

Provided an updated.txt list that you maintain, this will reinstall everything installed that was updated; this shouldn't be necessary unless UPDATING says there was a shared library bump.

fetch -o /tmp/updated.txt https://pkg.cyberleo.net/packages/cdnjail-cdn/updated.txt && pkg_info -qo \* | sed -e 's!^.*$!grep '\''^&$'\'' /tmp/updated.txt!' | sh | xargs portmaster -F