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} \ 56 installworld installkernel distribution || \ 57 err "\n\nCannot install the base system to ${DESTDIR}." 58 59 # Bootstrap etcupdate(8) database. 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 65 echo '# Custom /etc/fstab for FreeBSD VM images' \ 66 > ${DESTDIR}/etc/fstab 67 if [ "${VMFS}" != zfs ]; then 68 echo "/dev/${ROOTLABEL}/rootfs / ${VMFS} rw 1 1" \ 69 >> ${DESTDIR}/etc/fstab 70 fi 71 if [ -z "${NOSWAP}" ]; then 72 echo '/dev/gpt/swapfs none swap sw 0 0' \ 73 >> ${DESTDIR}/etc/fstab 74 fi 75 76 local hostname 77 hostname="$(echo $(uname -o) | tr '[:upper:]' '[:lower:]')" 78 echo "hostname=\"${hostname}\"" >> ${DESTDIR}/etc/rc.conf 79 if [ "${VMFS}" = zfs ]; then 80 echo "zfs_enable=\"YES\"" >> ${DESTDIR}/etc/rc.conf 81 echo "zpool_reguid=\"zroot\"" >> ${DESTDIR}/etc/rc.conf 82 echo "zpool_upgrade=\"zroot\"" >> ${DESTDIR}/etc/rc.conf 83 fi 84 85 if ! [ -z "${QEMUSTATIC}" ]; then 86 export EMULATOR=/qemu 87 cp ${QEMUSTATIC} ${DESTDIR}/${EMULATOR} 88 fi 89 90 mkdir -p ${DESTDIR}/dev 91 mount -t devfs devfs ${DESTDIR}/dev 92 chroot ${DESTDIR} ${EMULATOR} /usr/bin/newaliases 93 chroot ${DESTDIR} ${EMULATOR} /bin/sh /etc/rc.d/ldconfig forcestart 94 umount_loop ${DESTDIR}/dev 95 96 cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf 97 98 if [ "${VMFS}" = zfs ]; then 99 echo "kern.geom.label.disk_ident.enable=0" >> ${DESTDIR}/boot/loader.conf 100 echo "zfs_load=YES" >> ${DESTDIR}/boot/loader.conf 101 fi 102 103 return 0 104} 105 106vm_extra_install_base() { 107 # Prototype. When overridden, runs extra post-installworld commands 108 # as needed, based on the target virtual machine image or cloud 109 # provider image target. 110 111 return 0 112} 113 114vm_extra_enable_services() { 115 if [ ! -z "${VM_RC_LIST}" ]; then 116 for _rcvar in ${VM_RC_LIST}; do 117 echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf 118 done 119 fi 120 121 if [ -z "${VMCONFIG}" -o -c "${VMCONFIG}" ]; then 122 echo 'ifconfig_DEFAULT="DHCP inet6 accept_rtadv"' >> \ 123 ${DESTDIR}/etc/rc.conf 124 # Expand the filesystem to fill the disk. 125 echo 'growfs_enable="YES"' >> ${DESTDIR}/etc/rc.conf 126 touch ${DESTDIR}/firstboot 127 fi 128 129 return 0 130} 131 132vm_extra_install_packages() { 133 if [ -z "${VM_EXTRA_PACKAGES}" ]; then 134 return 0 135 fi 136 mkdir -p ${DESTDIR}/dev 137 mount -t devfs devfs ${DESTDIR}/dev 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 umount_loop ${DESTDIR}/dev 145 146 return 0 147} 148 149vm_extra_install_ports() { 150 # Prototype. When overridden, installs additional ports within the 151 # virtual machine environment. 152 153 return 0 154} 155 156vm_extra_pre_umount() { 157 # Prototype. When overridden, performs additional tasks within the 158 # virtual machine environment prior to unmounting the filesystem. 159 # Note: When overriding this function, removing resolv.conf in the 160 # disk image must be included. 161 162 if ! [ -z "${QEMUSTATIC}" ]; then 163 rm -f ${DESTDIR}/${EMULATOR} 164 fi 165 rm -f ${DESTDIR}/etc/resolv.conf 166 return 0 167} 168 169vm_extra_pkg_rmcache() { 170 if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then 171 chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \ 172 /usr/local/sbin/pkg clean -y -a 173 fi 174 175 return 0 176} 177 178buildfs() { 179 local md tmppool 180 181 case "${VMFS}" in 182 ufs) 183 makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \ 184 ${VMBASE} ${DESTDIR} 185 ;; 186 zfs) 187 makefs -t zfs ${MAKEFSARGS} \ 188 -o poolname=zroot -o bootfs=zroot/ROOT/default -o rootpath=/ \ 189 -o fs=zroot\;mountpoint=none \ 190 -o fs=zroot/ROOT\;mountpoint=none \ 191 -o fs=zroot/ROOT/default\;mountpoint=/ \ 192 -o fs=zroot/home\;mountpoint=/home \ 193 -o fs=zroot/tmp\;mountpoint=/tmp\;exec=on\;setuid=off \ 194 -o fs=zroot/usr\;mountpoint=/usr\;canmount=off \ 195 -o fs=zroot/usr/ports\;setuid=off \ 196 -o fs=zroot/usr/src \ 197 -o fs=zroot/usr/obj \ 198 -o fs=zroot/var\;mountpoint=/var\;canmount=off \ 199 -o fs=zroot/var/audit\;setuid=off\;exec=off \ 200 -o fs=zroot/var/log\;setuid=off\;exec=off \ 201 -o fs=zroot/var/mail\;atime=on \ 202 -o fs=zroot/var/tmp\;setuid=off \ 203 ${VMBASE} ${DESTDIR} 204 ;; 205 *) 206 echo "Unexpected VMFS value '${VMFS}'" 207 exit 1 208 ;; 209 esac 210} 211 212umount_loop() { 213 DIR=$1 214 i=0 215 sync 216 while ! umount ${DIR}; do 217 i=$(( $i + 1 )) 218 if [ $i -ge 10 ]; then 219 # This should never happen. But, it has happened. 220 echo "Cannot umount(8) ${DIR}" 221 echo "Something has gone horribly wrong." 222 return 1 223 fi 224 sleep 1 225 done 226 227 return 0 228} 229 230vm_create_disk() { 231 local BOOTFILES BOOTPARTSOFFSET FSPARTTYPE X86GPTBOOTFILE 232 233 if [ -z "${NOSWAP}" ]; then 234 SWAPOPT="-p freebsd-swap/swapfs::${SWAPSIZE}" 235 fi 236 237 if [ -n "${VM_BOOTPARTSOFFSET}" ]; then 238 BOOTPARTSOFFSET=":${VM_BOOTPARTSOFFSET}" 239 fi 240 241 case "${VMFS}" in 242 ufs) 243 FSPARTTYPE=freebsd-ufs 244 X86GPTBOOTFILE=i386/gptboot/gptboot 245 ;; 246 zfs) 247 FSPARTTYPE=freebsd-zfs 248 X86GPTBOOTFILE=i386/gptzfsboot/gptzfsboot 249 ;; 250 *) 251 echo "Unexpected VMFS value '${VMFS}'" 252 return 1 253 ;; 254 esac 255 256 echo "Creating image... Please wait." 257 echo 258 259 BOOTFILES="$(env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ 260 WITH_UNIFIED_OBJDIR=yes \ 261 make -C ${WORLDDIR}/stand -V .OBJDIR)" 262 BOOTFILES="$(realpath ${BOOTFILES})" 263 MAKEFSARGS="-s ${VMSIZE}" 264 265 case "${TARGET}:${TARGET_ARCH}" in 266 amd64:amd64 | i386:i386) 267 ESP=yes 268 BOOTPARTS="-b ${BOOTFILES}/i386/pmbr/pmbr \ 269 -p freebsd-boot/bootfs:=${BOOTFILES}/${X86GPTBOOTFILE}${BOOTPARTSOFFSET}" 270 ROOTFSPART="-p ${FSPARTTYPE}/rootfs:=${VMBASE}" 271 MAKEFSARGS="$MAKEFSARGS -B little" 272 ;; 273 arm64:aarch64 | riscv:riscv64*) 274 ESP=yes 275 BOOTPARTS= 276 ROOTFSPART="-p ${FSPARTTYPE}/rootfs:=${VMBASE}" 277 MAKEFSARGS="$MAKEFSARGS -B little" 278 ;; 279 powerpc:powerpc*) 280 ESP=no 281 BOOTPARTS="-p prepboot:=${BOOTFILES}/powerpc/boot1.chrp/boot1.elf -a 1" 282 ROOTFSPART="-p freebsd:=${VMBASE}" 283 if [ ${TARGET_ARCH} = powerpc64le ]; then 284 MAKEFSARGS="$MAKEFSARGS -B little" 285 else 286 MAKEFSARGS="$MAKEFSARGS -B big" 287 fi 288 ;; 289 *) 290 echo "vmimage.subr: unsupported target '${TARGET}:${TARGET_ARCH}'" >&2 291 exit 1 292 ;; 293 esac 294 295 if [ ${ESP} = "yes" ]; then 296 # Create an ESP 297 espfilename=$(mktemp /tmp/efiboot.XXXXXX) 298 make_esp_file ${espfilename} ${fat32min} ${BOOTFILES}/efi/loader_lua/loader_lua.efi 299 BOOTPARTS="${BOOTPARTS} -p efi/efiesp:=${espfilename}" 300 301 # Add this to fstab 302 mkdir -p ${DESTDIR}/boot/efi 303 echo "/dev/${ROOTLABEL}/efiesp /boot/efi msdosfs rw 2 2" \ 304 >> ${DESTDIR}/etc/fstab 305 fi 306 307 echo "Building filesystem... Please wait." 308 buildfs 309 310 echo "Building final disk image... Please wait." 311 mkimg -s ${PARTSCHEME} -f ${VMFORMAT} \ 312 ${BOOTPARTS} \ 313 ${SWAPOPT} \ 314 ${ROOTFSPART} \ 315 -o ${VMIMAGE} 316 317 echo "Disk image ${VMIMAGE} created." 318 319 if [ ${ESP} = "yes" ]; then 320 rm ${espfilename} 321 fi 322 323 return 0 324} 325 326vm_extra_create_disk() { 327 328 return 0 329} 330 331