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