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