1#!/bin/sh 2# 3# 4# 5# Common functions for virtual machine image build scripts. 6# 7 8scriptdir=$(dirname $(realpath $0)) 9. ${scriptdir}/../../tools/boot/install-boot.sh 10 11export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 12trap "cleanup" INT QUIT TRAP ABRT TERM 13 14# Platform-specific large-scale setup 15# Most platforms use GPT, so put that as default, then special cases 16PARTSCHEME=gpt 17ROOTLABEL="gpt" 18case "${TARGET}:${TARGET_ARCH}" in 19 powerpc:powerpc*) 20 PARTSCHEME=mbr 21 ROOTLABEL="ufs" 22 NOSWAP=yes # Can't label swap partition with MBR, so no swap 23 ;; 24esac 25 26err() { 27 printf "${@}\n" 28 cleanup 29 return 1 30} 31 32cleanup() { 33 if [ -c "${DESTDIR}/dev/null" ]; then 34 umount_loop ${DESTDIR}/dev 2>/dev/null 35 fi 36 37 return 0 38} 39 40vm_create_base() { 41 42 mkdir -p ${DESTDIR} 43 44 return 0 45} 46 47vm_copy_base() { 48 # Defunct 49} 50 51vm_install_base() { 52 # Installs the FreeBSD userland/kernel to the virtual machine disk. 53 54 cd ${WORLDDIR} && \ 55 make DESTDIR=${DESTDIR} ${INSTALLOPTS} \ 56 installworld installkernel distribution || \ 57 err "\n\nCannot install the base system to ${DESTDIR}." 58 59 # Bootstrap etcupdate(8) and mergemaster(8) databases. 60 mkdir -p ${DESTDIR}/var/db/etcupdate 61 etcupdate extract -B \ 62 -M "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \ 63 -s ${WORLDDIR} -d ${DESTDIR}/var/db/etcupdate 64 sh ${WORLDDIR}/release/scripts/mm-mtree.sh -m ${WORLDDIR} \ 65 -F "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \ 66 -D ${DESTDIR} 67 68 echo '# Custom /etc/fstab for FreeBSD VM images' \ 69 > ${DESTDIR}/etc/fstab 70 if [ "${VMFS}" != zfs ]; then 71 echo "/dev/${ROOTLABEL}/rootfs / ${VMFS} rw 1 1" \ 72 >> ${DESTDIR}/etc/fstab 73 fi 74 if [ -z "${NOSWAP}" ]; then 75 echo '/dev/gpt/swapfs none swap sw 0 0' \ 76 >> ${DESTDIR}/etc/fstab 77 fi 78 79 local hostname 80 hostname="$(echo $(uname -o) | tr '[:upper:]' '[:lower:]')" 81 echo "hostname=\"${hostname}\"" >> ${DESTDIR}/etc/rc.conf 82 if [ "${VMFS}" = zfs ]; then 83 echo "zfs_enable=\"YES\"" >> ${DESTDIR}/etc/rc.conf 84 echo "zpool_reguid=\"zroot\"" >> ${DESTDIR}/etc/rc.conf 85 echo "zpool_upgrade=\"zroot\"" >> ${DESTDIR}/etc/rc.conf 86 echo "kern.geom.label.disk_ident.enable=0" >> ${DESTDIR}/boot/loader.conf 87 echo "zfs_load=YES" >> ${DESTDIR}/boot/loader.conf 88 fi 89 90 return 0 91} 92 93vm_emulation_setup() { 94 if ! [ -z "${QEMUSTATIC}" ]; then 95 export EMULATOR=/qemu 96 cp ${QEMUSTATIC} ${DESTDIR}/${EMULATOR} 97 fi 98 99 mkdir -p ${DESTDIR}/dev 100 mount -t devfs devfs ${DESTDIR}/dev 101 chroot ${DESTDIR} ${EMULATOR} /usr/bin/newaliases 102 chroot ${DESTDIR} ${EMULATOR} /bin/sh /etc/rc.d/ldconfig forcestart 103 cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf 104 105 return 0 106} 107 108vm_extra_install_base() { 109 # Prototype. When overridden, runs extra post-installworld commands 110 # as needed, based on the target virtual machine image or cloud 111 # provider image target. 112 113 return 0 114} 115 116vm_extra_enable_services() { 117 if [ ! -z "${VM_RC_LIST}" ]; then 118 for _rcvar in ${VM_RC_LIST}; do 119 echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf 120 done 121 fi 122 123 if [ -z "${VMCONFIG}" -o -c "${VMCONFIG}" ]; then 124 echo 'ifconfig_DEFAULT="DHCP inet6 accept_rtadv"' >> \ 125 ${DESTDIR}/etc/rc.conf 126 # Expand the filesystem to fill the disk. 127 echo 'growfs_enable="YES"' >> ${DESTDIR}/etc/rc.conf 128 touch ${DESTDIR}/firstboot 129 fi 130 131 return 0 132} 133 134vm_extra_install_packages() { 135 if [ -z "${VM_EXTRA_PACKAGES}" ]; then 136 return 0 137 fi 138 chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \ 139 /usr/sbin/pkg bootstrap -y 140 for p in ${VM_EXTRA_PACKAGES}; do 141 chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \ 142 /usr/sbin/pkg install -y ${p} 143 done 144 145 return 0 146} 147 148vm_extra_install_ports() { 149 # Prototype. When overridden, installs additional ports within the 150 # virtual machine environment. 151 152 return 0 153} 154 155vm_extra_pre_umount() { 156 # Prototype. When overridden, performs additional tasks within the 157 # virtual machine environment prior to unmounting the filesystem. 158 159 return 0 160} 161 162vm_emulation_cleanup() { 163 if ! [ -z "${QEMUSTATIC}" ]; then 164 rm -f ${DESTDIR}/${EMULATOR} 165 fi 166 rm -f ${DESTDIR}/etc/resolv.conf 167 umount_loop ${DESTDIR}/dev 168 return 0 169} 170 171vm_extra_pkg_rmcache() { 172 if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then 173 chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \ 174 /usr/local/sbin/pkg clean -y -a 175 fi 176 177 return 0 178} 179 180buildfs() { 181 local md tmppool 182 183 case "${VMFS}" in 184 ufs) 185 makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \ 186 ${VMBASE} ${DESTDIR} 187 ;; 188 zfs) 189 makefs -t zfs ${MAKEFSARGS} \ 190 -o poolname=zroot -o bootfs=zroot/ROOT/default -o rootpath=/ \ 191 -o fs=zroot\;mountpoint=none \ 192 -o fs=zroot/ROOT\;mountpoint=none \ 193 -o fs=zroot/ROOT/default\;mountpoint=/ \ 194 -o fs=zroot/home\;mountpoint=/home \ 195 -o fs=zroot/tmp\;mountpoint=/tmp\;exec=on\;setuid=off \ 196 -o fs=zroot/usr\;mountpoint=/usr\;canmount=off \ 197 -o fs=zroot/usr/ports\;setuid=off \ 198 -o fs=zroot/usr/src \ 199 -o fs=zroot/usr/obj \ 200 -o fs=zroot/var\;mountpoint=/var\;canmount=off \ 201 -o fs=zroot/var/audit\;setuid=off\;exec=off \ 202 -o fs=zroot/var/crash\;setuid=off\;exec=off \ 203 -o fs=zroot/var/log\;setuid=off\;exec=off \ 204 -o fs=zroot/var/mail\;atime=on \ 205 -o fs=zroot/var/tmp\;setuid=off \ 206 ${VMBASE} ${DESTDIR} 207 ;; 208 *) 209 echo "Unexpected VMFS value '${VMFS}'" 210 exit 1 211 ;; 212 esac 213} 214 215umount_loop() { 216 DIR=$1 217 i=0 218 sync 219 while ! umount ${DIR}; do 220 i=$(( $i + 1 )) 221 if [ $i -ge 10 ]; then 222 # This should never happen. But, it has happened. 223 echo "Cannot umount(8) ${DIR}" 224 echo "Something has gone horribly wrong." 225 return 1 226 fi 227 sleep 1 228 done 229 230 return 0 231} 232 233vm_create_disk() { 234 local BOOTFILES BOOTPARTSOFFSET FSPARTTYPE X86GPTBOOTFILE 235 236 if [ -z "${NOSWAP}" ]; then 237 SWAPOPT="-p freebsd-swap/swapfs::${SWAPSIZE}" 238 fi 239 240 if [ -n "${VM_BOOTPARTSOFFSET}" ]; then 241 BOOTPARTSOFFSET=":${VM_BOOTPARTSOFFSET}" 242 fi 243 244 if [ -n "${CONFIG_DRIVE}" ]; then 245 CONFIG_DRIVE="-p freebsd/config-drive::${CONFIG_DRIVE_SIZE}" 246 fi 247 248 case "${VMFS}" in 249 ufs) 250 FSPARTTYPE=freebsd-ufs 251 X86GPTBOOTFILE=i386/gptboot/gptboot 252 ;; 253 zfs) 254 FSPARTTYPE=freebsd-zfs 255 X86GPTBOOTFILE=i386/gptzfsboot/gptzfsboot 256 ;; 257 *) 258 echo "Unexpected VMFS value '${VMFS}'" 259 return 1 260 ;; 261 esac 262 263 echo "Creating image... Please wait." 264 echo 265 266 BOOTFILES="$(env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ 267 WITH_UNIFIED_OBJDIR=yes \ 268 make -C ${WORLDDIR}/stand -V .OBJDIR)" 269 BOOTFILES="$(realpath ${BOOTFILES})" 270 MAKEFSARGS="-s ${VMSIZE}" 271 272 case "${TARGET}:${TARGET_ARCH}" in 273 amd64:amd64 | i386:i386) 274 ESP=yes 275 BOOTPARTS="-b ${BOOTFILES}/i386/pmbr/pmbr \ 276 -p freebsd-boot/bootfs:=${BOOTFILES}/${X86GPTBOOTFILE}${BOOTPARTSOFFSET}" 277 ROOTFSPART="-p ${FSPARTTYPE}/rootfs:=${VMBASE}" 278 MAKEFSARGS="$MAKEFSARGS -B little" 279 ;; 280 arm64:aarch64 | riscv:riscv64*) 281 ESP=yes 282 BOOTPARTS= 283 ROOTFSPART="-p ${FSPARTTYPE}/rootfs:=${VMBASE}" 284 MAKEFSARGS="$MAKEFSARGS -B little" 285 ;; 286 powerpc:powerpc*) 287 ESP=no 288 BOOTPARTS="-p prepboot:=${BOOTFILES}/powerpc/boot1.chrp/boot1.elf -a 1" 289 ROOTFSPART="-p freebsd:=${VMBASE}" 290 if [ ${TARGET_ARCH} = powerpc64le ]; then 291 MAKEFSARGS="$MAKEFSARGS -B little" 292 else 293 MAKEFSARGS="$MAKEFSARGS -B big" 294 fi 295 ;; 296 *) 297 echo "vmimage.subr: unsupported target '${TARGET}:${TARGET_ARCH}'" >&2 298 exit 1 299 ;; 300 esac 301 302 if [ ${ESP} = "yes" ]; then 303 # Create an ESP 304 espfilename=$(mktemp /tmp/efiboot.XXXXXX) 305 make_esp_file ${espfilename} ${fat32min} ${BOOTFILES}/efi/loader_lua/loader_lua.efi 306 BOOTPARTS="${BOOTPARTS} -p efi/efiesp:=${espfilename}" 307 308 # Add this to fstab 309 mkdir -p ${DESTDIR}/boot/efi 310 echo "/dev/${ROOTLABEL}/efiesp /boot/efi msdosfs rw 2 2" \ 311 >> ${DESTDIR}/etc/fstab 312 fi 313 314 echo "Building filesystem... Please wait." 315 buildfs 316 317 echo "Building final disk image... Please wait." 318 mkimg -s ${PARTSCHEME} -f ${VMFORMAT} \ 319 ${BOOTPARTS} \ 320 ${SWAPOPT} \ 321 ${CONFIG_DRIVE} \ 322 ${ROOTFSPART} \ 323 -o ${VMIMAGE} 324 325 echo "Disk image ${VMIMAGE} created." 326 327 if [ ${ESP} = "yes" ]; then 328 rm ${espfilename} 329 fi 330 331 return 0 332} 333 334vm_extra_create_disk() { 335 336 return 0 337} 338 339