summaryrefslogtreecommitdiffstats
path: root/core/modules/vbox-src/module.build
blob: f8c0395601b6f21ed3e955e8f7b7956966df1f2f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/bin/bash

vbox_build_id() {
	{
		echo "$REQUIRED_VBOX_VERSION"
		gcc --version 2>&1
		echo "${TARGET_KERNEL_LONG}"
		echo "2" # incrase this in case something relevant changes in this build script
		grep -E '^(# )?CONFIG_' "${KERNEL_HEADERS_DIR}/.config"
	} | md5sum | cut -c1-32
}

fetch_source() {
	[ -d "${MODULE_WORK_DIR}/src" ] && rm -rf "${MODULE_WORK_DIR}/src"
	[ -z "${REQUIRED_VBOX_VERSION}" ] && perror "REQUIRED_VBOX_VERSION is not set!"

	local done=
	if nfs_cache_avail; then
		local id tar
		id="$( vbox_build_id )"
		pinfo "Build id is $id"
		tar="${NFS_CACHE_DIR}/cache/${id}.tar.zstd"
		if [ -s "$tar" ]; then
			pinfo "Extracting cached vbox build"
			if < "$tar" zstd -d -T0 | tar -C "${MODULE_WORK_DIR}" -x; then
				touch "$tar" # We use last modified as last used, as atime is unreliable
				done=1
			fi
			pwarning "Extracting cached kernel failed, building..."
		fi
	fi
	if [ -z "$done" ]; then
		local BASEVER="${REQUIRED_VBOX_VERSION}"
		# In case we have something like 1.2.3a, we need 1.2.3 for the directory name below
		[[ "${BASEVER: -1}" =~ ^[0-9]$ ]] || BASEVER="${BASEVER:0:-1}"
		local BASE_URL="http://download.virtualbox.org/virtualbox"
		local DOWNLOAD_URL="${BASE_URL}/${BASEVER}/VirtualBox-${REQUIRED_VBOX_VERSION}.tar.bz2"
		download_untar "$DOWNLOAD_URL" "${MODULE_WORK_DIR}/src" || \
			perror "Could not download_untar '$DOWNLOAD_URL' to '${MODULE_WORK_DIR}/src'."
	fi

	if [ -n "$REQUIRED_EXTPACK" ]; then
		# oracle's extension pack
		DOWNLOAD_URL="${DOWNLOAD_URL%/*}/Oracle_VM_VirtualBox_Extension_Pack-${BASEVER}.vbox-extpack"
		download_untar "$DOWNLOAD_URL" "${MODULE_WORK_DIR}/extpack" || \
			perror "Could not download_untar '$DOWNLOAD_URL' to '${MODULE_WORK_DIR}/extpack'."
		# Nice, Oracle - files in the tarball are world writable, but vbox refuses to use the extpack that way
		chmod -R go-w "${MODULE_WORK_DIR}/extpack"
	fi
}

build() (
	[ -n "${KERNEL_HEADERS_DIR}" ] || perror "KERNEL_HEADERS_DIR not set, kernel module present?"
	local BASEVER="${REQUIRED_VBOX_VERSION}"
	# In case we have something like 1.2.3a, we need 1.2.3 for the directory name below
	[[ "${BASEVER: -1}" =~ ^[0-9]$ ]] || BASEVER="${BASEVER:0:-1}"
	local VBOX_BUILD_DIR="${MODULE_WORK_DIR}/src/VirtualBox-${BASEVER}/build"
	# Cached?
	local bf="${MODULE_WORK_DIR}/src/.mltk-build-flag"
	if [ -e "$bf"  ]; then
		# Cached, setup vars
		source "${VBOX_BUILD_DIR}/env.sh" || perror "Failed to source '${VBOX_BUILD_DIR}/env.sh'."
		local VBOX_RELEASE_BUILD_DIR="${VBOX_BUILD_DIR}/linux.${BUILD_PLATFORM_ARCH}/release"
	else
		cd "${MODULE_WORK_DIR}/src/VirtualBox-${BASEVER}" || \
			perror "Could not cd to '${MODULE_WORK_DIR}/src/VirtualBox-${BASEVER}'."
		mkdir -p "$VBOX_BUILD_DIR" || perror "Failed to mkdir '$VBOX_BUILD_DIR'."
		./configure \
			--disable-docs				\
			--disable-java				\
			--disable-python			\
			--disable-libvpx			\
			--enable-vnc            \
			--disable-udptunnel     \
			--with-linux="${KERNEL_HEADERS_DIR}"	\
			--out-base-dir="${VBOX_BUILD_DIR}"	\
				|| perror "'configure' failed."
		# Newer version SUCK because they ignore --with-linux and require KERN_DIR to be set,
		# and forthermode require it to end in "<version>/build", so we need to create a symlink *facepalm*
		mkdir -p "kernel/${TARGET_KERNEL_LONG}"
		ln -nfs "${KERNEL_HEADERS_DIR}" "kernel/${TARGET_KERNEL_LONG}/build" \
			|| perror "Kernel symlink fail ('${KERNEL_HEADERS_DIR}' <- 'kernel/${TARGET_KERNEL_LONG}/build')"
		export KERN_DIR="$( readlink -f "kernel" )/${TARGET_KERNEL_LONG}/build"
		# Limit job count - can easily OOM
		num="$( awk '$1 == "MemTotal:" { print int(0.25 + $2 / (1024*1024)) }' /proc/meminfo )"
		(( num > CPU_CORES )) && num="$CPU_CORES"
		# the configure script should have created a file called 'env.sh'
		source "${VBOX_BUILD_DIR}/env.sh" || perror "Failed to source '${VBOX_BUILD_DIR}/env.sh'."
		# copy the LocalConfig.kmk to the build dir to be more LSB-compliant
		cp "${MODULE_DIR}/LocalConfig.kmk" "${VBOX_BUILD_DIR}" || \
			perror "Failed to cp LocalConfig.kmk to build dir"
		cp "${MODULE_DIR}/LocalConfig.kmk" "${VBOX_BUILD_DIR}/../" || \
			perror "Failed to cp LocalConfig.kmk to build/../ dir"
		kmk -j "$num" all || perror "Failed to execute 'kmk'."

		# check the generated build directory, use BUILD_PLATFORM_ARCH defined in env.sh
		local VBOX_RELEASE_BUILD_DIR="${VBOX_BUILD_DIR}/linux.${BUILD_PLATFORM_ARCH}/release"
		[ -d "${VBOX_RELEASE_BUILD_DIR}" ] || \
			perror "No release build dir found under '${VBOX_RELEASE_BUILD_DIR}'. Build failed?"

		## Kernel modules
		# build kernel modules from the release dir
		cde "${VBOX_RELEASE_BUILD_DIR}/bin/src"
		make \
			KERN_DIR="${KERNEL_HEADERS_DIR}" \
			KERN_VER="${TARGET_KERNEL_LONG}" \
				|| perror "Build kernel modules failed."

		# Cache
		touch "$bf"
		if nfs_cache_avail; then
			local id tar
			id="$( vbox_build_id )"
			tar="${NFS_CACHE_DIR}/cache/${id}.tar.zstd"
			pinfo "Copying built vbox to NFS cache with id $id"
			mkdir -p "$( dirname "$tar" )"
			tar -C "${MODULE_WORK_DIR}" -c -k src | zstd -T0 -2 -z > "$tar" \
				|| pwarning "Could not write vbox to NFS cache"
		fi
	fi

	# the resulting linux.<arch>/release/bin folder contains the whole build,
	# copy it over to usr/lib/virtualbox
	mkdir -p "${MODULE_BUILD_DIR}/usr/lib/virtualbox" || \
		perror "Failed to mkdir '${MODULE_BUILD_DIR}/usr/lib/virtualbox'."
	cp -r "${VBOX_RELEASE_BUILD_DIR}/bin/"* "${MODULE_BUILD_DIR}/usr/lib/virtualbox" || \
		perror "Failed to cp -r '${VBOX_RELEASE_BUILD_DIR}/bin' to '${MODULE_BUILD_DIR}/usr/lib/virtualbox'."

	# set suid bits
	for BIN in VBoxHeadless VBoxNetAdpCtl VBoxNetDHCP VBoxNetNAT VBoxSDL VirtualBoxVM; do
		if ! [ -e "${MODULE_BUILD_DIR}/usr/lib/virtualbox/$BIN" ]; then
			pwarning "No such file: '${MODULE_BUILD_DIR}/usr/lib/virtualbox/$BIN', cannot add suid bit."
			continue
		fi
		chmod u+s "${MODULE_BUILD_DIR}/usr/lib/virtualbox/${BIN}" || perror "Failed to set suid bit on '${BIN}'."
	done

	# Copy kernel modules
	cde "${VBOX_RELEASE_BUILD_DIR}/bin/src"
	mkdir -p "${MODULE_BUILD_DIR}/lib/modules/vbox" || \
		perror "Failed to mkdir '${MODULE_BUILD_DIR}/lib/modules/vbox'."
	for MOD in $(find ./* -maxdepth 0 -type d); do
		[ -e "$MOD.ko" ] || perror "Module '$MOD' was not built!"
		cp "$MOD.ko" "${MODULE_BUILD_DIR}/lib/modules/vbox/" || \
			perror "Failed to cp $MOD.ko to '${MODULE_BUILD_DIR}/lib/modules/vbox/'."
	done

	if [ -n "$REQUIRED_EXTPACK" ]; then
		# finally copy the extension pack files, everthing is needed as the subfolders
		# target the guest architectures and not that of the host!
		local VBOX_EXTPACK_DIR="${MODULE_BUILD_DIR}/usr/lib/virtualbox/ExtensionPacks/Oracle_VM_VirtualBox_Extension_Pack"
		cp -ar "${MODULE_WORK_DIR}/extpack" "${VBOX_EXTPACK_DIR}" || \
			perror "Failed to cp '${MODULE_WORK_DIR}/extpack' to '${VBOX_EXTPACK_DIR}'."
		chown -R root:root "${VBOX_EXTPACK_DIR}" || \
			perror "Failed to chown '${VBOX_EXTPACK_DIR}' to root:root."
	fi

	# od binary
	local OD_BIN="$(which od 2>/dev/null)"
	if [ -n "$OD_BIN" ] && [ -f "$OD_BIN" ]; then
		tarcopy "$OD_BIN" "$MODULE_BUILD_DIR"
	fi
	true
)

post_copy() {
	groupadd --system vboxusers
	add_to_group demo vboxusers
}