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