#!/bin/sh

# Updated 2017 March 8, Nathan Dorfman <na@rtfm.net>
# Based on the mkoctimage script from Warner Losh.

# This script will build a FreeBSD image for the Ubiquiti EdgeRouter Lite.
# More information is available at http://rtfm.net/FreeBSD/ERL/

# After checking the following settings, run this script from the root of the
# FreeBSD source tree you wish to build. You may also need to set the
# MAKEOBJDIRPREFIX environment variable. See the FreeBSD Handbook for more
# details about the FreeBSD build process.

# Write the resulting image to a USB drive using:
#   xzcat "filename.image.gz" | dd of="/dev/devicename" bs=1024k
# Boot it from the U-Boot prompt using:
#   fatload usb 0 $loadaddr kernel/kernel ; bootoctlinux $loadaddr coremask=0x3

image_name=freebsd-ubiquiti-edgerouter-lite

temp_root=$(mktemp -d)          # 2GB+ of scratch space for temp root and UFS
make_args='-DNO_CLEAN -j20'     # any args to buildworld/buildkernel
kern_conf=ERL                   # kernel config to use, or create if not there
skip_build=false                # true/false, don't run buildworld/buildkernel
clean_up=true                   # true/false, delete temp root/UFS on success
min_free_inodes=16384           # minimum # of free inodes left in new root fs

#
# The end.
#

set -e

if [ ! -d sys/mips/conf ]; then
    echo $0: must be run from a FreeBSD source tree root > /dev/stderr
    exit 1
fi

kconffile=sys/mips/conf/$kern_conf
kcompdir=sys/mips/compile/$kern_conf
if [ ! -e ${kconffile} ]; then
    if [ -e ${kcompdir} ]; then
        echo $0: $kconffile does not exist but $kcompdir does. Check and\
            delete by hand, then run $0 again. > /dev/stderr
        exit 1
    fi

    echo
    echo $0: $kconffile not found, creating a new one based on OCTEON1
    echo

    (cd sys/mips/conf && sed -E -f/dev/stdin OCTEON1 << EOF > ${kern_conf}\
        && config ${kern_conf}) || exit 7
s|^# OCTEON1.*|# ERL - EdgeRouter Lite kernel config, generated by mkerlimage, http://rtfm.net/FreeBSD/ERL|
s/^ident[[:space:]].*/ident		ERL/
s/^(options[[:space:]]+ROOTDEVNAME=).*/\1\\\\"ufs:da0s2a\\\\"	# Default root filesystem./
s/^#(options[[:space:]]+OCTEON_VENDOR_UBIQUITI[[:space:]]*)/\1/
s/^options[[:space:]]+([KDG]DB|DEADLKRES|MALLOC_DEBUG_.*)([[:space:]]*#.*)?/#&/
s/^options[[:space:]]+(INVARIANTS?|WITNESS)(_[A-Z0-9_]+)?([[:space:]]*#.*)? /#&/
s/^#(options[[:space:]]+OCTEON_MODEL=).*/\1OCTEON_CN50XX_PASS1/
s/^options[[:space:]]+NO_SWAPPING([[:space:]]*#.*)?$/&\\
options		TMPFS			# Temporary file system\\
device		pf\\
device		pflog/
EOF
fi

rootdir=$temp_root/$image_name

if cmp / $rootdir 2> /dev/null; then
    echo $0: something went horribly wrong, check script settings > /dev/stderr
    exit 255
fi

export TARGET=mips
export TARGET_ARCH=mips64

if ${skip_build}; then
    echo $0: skipping buildworld and buildkernel steps
else
    make buildworld ${make_args} || exit 2
    make buildkernel ${make_args} KERNCONF=${kern_conf} || exit 3
fi

mkdir -p ${rootdir} 
make installworld DESTDIR=${rootdir} || exit 4
make distribution DESTDIR=${rootdir} || exit 5
make installkernel KERNCONF=${kern_conf} DESTDIR=${rootdir} || exit 6

cat <<EOF > ${rootdir}/etc/fstab
# Device                Mountpoint      FStype  Options         Dump    Pass#
/dev/da0s2a             /               ufs     rw              1       1
/dev/da0s1              /boot           msdosfs rw              0       0
tmpfs                   /tmp            tmpfs   rw,mode=1777,size=192m  0 0
EOF

cat <<EOF > ${rootdir}/etc/rc.conf
hostname=erl
ifconfig_octe0="DHCP"
#ifconfig_octe1="inet 10.11.12.13/24"
#ifconfig_octe2="inet 10.9.8.7/24"
#gateway_enable="YES"
#sshd_enable="YES"
#ntpd_enable="YES"
#ntpd_sync_on_start="YES"
EOF

cat <<EOF >> ${rootdir}/etc/motd
Image built with mkerlimage, http://rtfm.net/FreeBSD/ERL

EOF

# 930MiB is just shy of 1GB in bytes
IMG_SIZE=$((930 * 1024 * 1024))
DOS_SECTORS=$(( (930-760) * 1024 * 2))

cp /dev/null ${rootdir}.image
dd if=/dev/zero of=${rootdir}.image oseek=${IMG_SIZE} bs=1 count=0
md=$(mdconfig -f ${rootdir}.image)
gpart create -s mbr ${md}
gpart add -t !6 -s ${DOS_SECTORS} ${md}
gpart add -t freebsd ${md}
gpart create -s BSD ${md}s2
gpart add -b 16 -t freebsd-ufs ${md}s2

newfs_msdos -F 16 /dev/${md}s1
mount -t msdosfs /dev/${md}s1 /mnt
mv ${rootdir}/boot/* /mnt
umount /mnt

makefs -f ${min_free_inodes} -B big -s 760m ${rootdir}.ufs ${rootdir}
dd if=${rootdir}.ufs of=/dev/${md}s2a bs=1m || true

mdconfig -d -u ${md}
xz -9f ${rootdir}.image
echo ${rootdir}.image.xz successfully created!

if $clean_up; then
    chflags -R noschg ${rootdir}
    rm -rf ${rootdir}.ufs ${rootdir}
fi
