1#!/bin/sh 2# 3# $FreeBSD$ 4# 5# 6# Common functions for virtual machine image build scripts. 7# 8 9export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 10trap "cleanup" INT QUIT TRAP ABRT TERM 11 12write_partition_layout() { 13 if [ -z "${NOSWAP}" ]; then 14 SWAPOPT="-p freebsd-swap/swapfs::${SWAPSIZE}" 15 fi 16 17 BOOTFILES="$(env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ 18 WITH_UNIFIED_OBJDIR=yes \ 19 make -C ${WORLDDIR}/stand -V .OBJDIR)" 20 BOOTFILES="$(realpath ${BOOTFILES})" 21 22 case "${TARGET}:${TARGET_ARCH}" in 23 amd64:amd64 | i386:i386) 24 mkimg -s gpt -f ${VMFORMAT} \ 25 -b ${BOOTFILES}/i386/pmbr/pmbr \ 26 -p freebsd-boot/bootfs:=${BOOTFILES}/i386/gptboot/gptboot \ 27 ${SWAPOPT} \ 28 -p freebsd-ufs/rootfs:=${VMBASE} \ 29 -o ${VMIMAGE} 30 ;; 31 arm64:aarch64) 32 mkimg -s mbr -f ${VMFORMAT} \ 33 -p efi:=${BOOTFILES}/efi/boot1/boot1.efifat \ 34 -p freebsd:=${VMBASE} \ 35 -o ${VMIMAGE} 36 ;; 37 powerpc:powerpc*) 38 mkimg -s apm -f ${VMFORMAT} \ 39 -p apple-boot/bootfs:=${BOOTFILES}/powerpc/boot1.chrp/boot1.hfs \ 40 ${SWAPOPT} \ 41 -p freebsd-ufs/rootfs:=${VMBASE} \ 42 -o ${VMIMAGE} 43 ;; 44 *) 45 # ENOTSUPP 46 return 1 47 ;; 48 esac 49 50 return 0 51} 52 53err() { 54 printf "${@}\n" 55 cleanup 56 return 1 57} 58 59cleanup() { 60 if [ -c "${DESTDIR}/dev/null" ]; then 61 umount_loop ${DESTDIR}/dev 2>/dev/null 62 fi 63 umount_loop ${DESTDIR} 64 if [ ! -z "${mddev}" ]; then 65 mdconfig -d -u ${mddev} 66 fi 67 68 return 0 69} 70 71vm_create_base() { 72 # Creates the UFS root filesystem for the virtual machine disk, 73 # written to the formatted disk image with mkimg(1). 74 75 mkdir -p ${DESTDIR} 76 truncate -s ${VMSIZE} ${VMBASE} 77 mddev=$(mdconfig -f ${VMBASE}) 78 newfs -L rootfs /dev/${mddev} 79 mount /dev/${mddev} ${DESTDIR} 80 81 return 0 82} 83 84vm_copy_base() { 85 # Creates a new UFS root filesystem and copies the contents of the 86 # current root filesystem into it. This produces a "clean" disk 87 # image without any remnants of files which were created temporarily 88 # during image-creation and have since been deleted (e.g., downloaded 89 # package archives). 90 91 mkdir -p ${DESTDIR}/old 92 mdold=$(mdconfig -f ${VMBASE}) 93 mount /dev/${mdold} ${DESTDIR}/old 94 95 truncate -s ${VMSIZE} ${VMBASE}.tmp 96 mkdir -p ${DESTDIR}/new 97 mdnew=$(mdconfig -f ${VMBASE}.tmp) 98 newfs -L rootfs /dev/${mdnew} 99 mount /dev/${mdnew} ${DESTDIR}/new 100 101 tar -cf- -C ${DESTDIR}/old . | tar -xUf- -C ${DESTDIR}/new 102 103 umount_loop /dev/${mdold} 104 rmdir ${DESTDIR}/old 105 mdconfig -d -u ${mdold} 106 107 umount_loop /dev/${mdnew} 108 rmdir ${DESTDIR}/new 109 tunefs -n enable /dev/${mdnew} 110 mdconfig -d -u ${mdnew} 111 mv ${VMBASE}.tmp ${VMBASE} 112} 113 114vm_install_base() { 115 # Installs the FreeBSD userland/kernel to the virtual machine disk. 116 117 cd ${WORLDDIR} && \ 118 make DESTDIR=${DESTDIR} \ 119 installworld installkernel distribution || \ 120 err "\n\nCannot install the base system to ${DESTDIR}." 121 122 # Bootstrap etcupdate(8) and mergemaster(8) databases. 123 mkdir -p ${DESTDIR}/var/db/etcupdate 124 etcupdate extract -B \ 125 -M "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \ 126 -s ${WORLDDIR} -d ${DESTDIR}/var/db/etcupdate 127 sh ${WORLDDIR}/release/scripts/mm-mtree.sh -m ${WORLDDIR} \ 128 -F "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \ 129 -D ${DESTDIR} 130 131 echo '# Custom /etc/fstab for FreeBSD VM images' \ 132 > ${DESTDIR}/etc/fstab 133 echo "/dev/${ROOTLABEL}/rootfs / ufs rw 1 1" \ 134 >> ${DESTDIR}/etc/fstab 135 if [ -z "${NOSWAP}" ]; then 136 echo '/dev/gpt/swapfs none swap sw 0 0' \ 137 >> ${DESTDIR}/etc/fstab 138 fi 139 140 local hostname 141 hostname="$(echo $(uname -o) | tr '[:upper:]' '[:lower:]')" 142 echo "hostname=\"${hostname}\"" >> ${DESTDIR}/etc/rc.conf 143 144 mkdir -p ${DESTDIR}/dev 145 mount -t devfs devfs ${DESTDIR}/dev 146 chroot ${DESTDIR} /usr/bin/newaliases 147 chroot ${DESTDIR} /etc/rc.d/ldconfig forcestart 148 umount_loop ${DESTDIR}/dev 149 150 cp /etc/resolv.conf ${DESTDIR}/etc/resolv.conf 151 152 return 0 153} 154 155vm_extra_install_base() { 156 # Prototype. When overridden, runs extra post-installworld commands 157 # as needed, based on the target virtual machine image or cloud 158 # provider image target. 159 160 return 0 161} 162 163vm_extra_enable_services() { 164 if [ ! -z "${VM_RC_LIST}" ]; then 165 for _rcvar in ${VM_RC_LIST}; do 166 echo ${_rcvar}_enable="YES" >> ${DESTDIR}/etc/rc.conf 167 done 168 fi 169 170 if [ -z "${VMCONFIG}" -o -c "${VMCONFIG}" ]; then 171 echo 'ifconfig_DEFAULT="DHCP inet6 accept_rtadv"' >> \ 172 ${DESTDIR}/etc/rc.conf 173 fi 174 175 return 0 176} 177 178vm_extra_install_packages() { 179 if [ -z "${VM_EXTRA_PACKAGES}" ]; then 180 return 0 181 fi 182 mkdir -p ${DESTDIR}/dev 183 mount -t devfs devfs ${DESTDIR}/dev 184 chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ 185 /usr/sbin/pkg bootstrap -y 186 chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ 187 /usr/sbin/pkg install -y ${VM_EXTRA_PACKAGES} 188 umount_loop ${DESTDIR}/dev 189 190 return 0 191} 192 193vm_extra_install_ports() { 194 # Prototype. When overridden, installs additional ports within the 195 # virtual machine environment. 196 197 return 0 198} 199 200vm_extra_pre_umount() { 201 # Prototype. When overridden, performs additional tasks within the 202 # virtual machine environment prior to unmounting the filesystem. 203 # Note: When overriding this function, removing resolv.conf in the 204 # disk image must be included. 205 206 rm -f ${DESTDIR}/etc/resolv.conf 207 return 0 208} 209 210vm_extra_pkg_rmcache() { 211 if [ -e ${DESTDIR}/usr/local/sbin/pkg ]; then 212 chroot ${DESTDIR} env ASSUME_ALWAYS_YES=yes \ 213 /usr/local/sbin/pkg clean -y -a 214 fi 215 216 return 0 217} 218 219umount_loop() { 220 DIR=$1 221 i=0 222 sync 223 while ! umount ${DIR}; do 224 i=$(( $i + 1 )) 225 if [ $i -ge 10 ]; then 226 # This should never happen. But, it has happened. 227 echo "Cannot umount(8) ${DIR}" 228 echo "Something has gone horribly wrong." 229 return 1 230 fi 231 sleep 1 232 done 233 234 return 0 235} 236 237vm_create_disk() { 238 echo "Creating image... Please wait." 239 echo 240 241 write_partition_layout || return 1 242 243 return 0 244} 245 246vm_extra_create_disk() { 247 248 return 0 249} 250 251