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