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