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