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