xref: /haiku/build/scripts/build_haiku_image (revision 04a0e9c7b68cbe3a43d38e2bca8e860fd80936fb)
1#!/bin/sh
2set -o errexit
3
4# The first argument is the shell script that initializes the variables:
5# sourceDir
6# outputDir
7# tmpDir
8# addBuildCompatibilityLibDir
9# systemPackages - lists of the hpkg packages copied/updated
10# repositories - all repository files
11# downloadDir
12# The following are only for image types:
13# installDir
14# isImage
15# imagePath
16# imageSize
17# imageLabel
18# resolvePackageDependencies
19# updateAllPackages
20# updateOnly
21# dontClearImage
22# isVMwareImage
23#
24# addattr
25# copyattr
26# getPackageDependencies
27# package
28# rc
29# rmAttrs
30# unzip
31# The following are only for image types:
32# bfsShell
33# fsShellCommand
34# makebootable
35# resattr
36# vmdkimage
37# The following is only for cd types:
38# generate_attribute_stores
39# isCD
40#
41if [ $# -gt 0 ]; then
42	. $1
43	shift
44fi
45
46if [ ! $isCD ]; then
47	# If the haiku image path is a symlink resolve it now (makebootable needs the
48	# path of the actual device path under Linux).
49	normalizedImagePath=''
50	if readlink -f "$imagePath" > /dev/null 2>&1 ; then
51		normalizedImagePath=$(readlink -f "$imagePath")
52	elif realpath "$imagePath" > /dev/null 2>&1 ; then
53		normalizedImagePath=$(realpath "$imagePath")
54	elif greadlink -f "$imagePath" > /dev/null 2>&1 ; then
55		normalizedImagePath=$(greadlink -f "$imagePath")
56	fi
57	if [ -n "$normalizedImagePath" ]; then
58		imagePath="$normalizedImagePath"
59	fi
60fi
61
62# this adds the build library dir to LD_LIBRARY_PATH
63eval "$addBuildCompatibilityLibDir"
64
65# map the shell commands
66if [ $isCD ]; then
67	outputDir=$tmpDir/cdsource
68
69	sPrefix=
70	tPrefix="$outputDir/"
71	cd=cd
72	scd=:
73	cp="$copyattr -d"
74	copyAttrs="$copyattr"
75	ln=ln
76	mkdir=mkdir
77	rm=rm
78elif [ $isImage ]; then
79	# If FIFOs are used for the communication with the FS shell, prepare them.
80	if $fsShellCommand --uses-fifos; then
81		fifoBasePath=/tmp/build_haiku_image-$$-fifo
82		toFSShellFifo=${fifoBasePath}-to-shell
83		fromFSShellFifo=${fifoBasePath}-from-shell
84
85		rm -f $toFSShellFifo $fromFSShellFifo
86		mkfifo $toFSShellFifo $fromFSShellFifo
87
88		# Open the FIFOs such that they are ready for the fsShellCommand. This
89		# also makes sure that they remain open until this script exits. When we
90		# exit while the FS shell is still running and waiting for commands,
91		# closing of our file descriptors will break the FIFOs and the FS shell
92		# will exit, too.
93		# Note: A bit of trickery is needed since opening one end blocks until
94		# someone opens the other end.
95		sleep 3<$fromFSShellFifo 1 &
96		exec 6>$fromFSShellFifo 3<$fromFSShellFifo
97		sleep 5<$toFSShellFifo 1 &
98		exec 4>$toFSShellFifo 5<$toFSShellFifo
99
100		# Remove the FIFO files again -- we have the open FDs, so they can
101		# still be used and this makes sure they won't hang around any further.
102		rm -f $toFSShellFifo $fromFSShellFifo
103
104		# Remap the fsShellCommand and bfsShell such that they don't inherit the
105		# wrong FDs. For both fsShellCommand and bfsShell FD 3 is the input from
106		# the respectively other program, FD 4 is the output to it.
107		actualFSShellCommand="$fsShellCommand"
108		actualBFSShell="$bfsShell"
109
110		fsShellCommandWrapper()
111		{
112			$actualFSShellCommand 5>&- 6>&- "$@"
113		}
114
115		bfsShellWrapper()
116		{
117			$actualBFSShell 3>&5 4<&6 "$@"
118		}
119
120		fsShellCommand=fsShellCommandWrapper
121		bfsShell=bfsShellWrapper
122	fi
123
124	# set up the other commands
125	sPrefix=:
126	tPrefix=/myfs/
127	cd="$fsShellCommand cd"
128	scd="$fsShellCommand cd"
129	cp="$fsShellCommand cp -f"
130	copyAttrs="$fsShellCommand cp -a"
131	ln="$fsShellCommand ln"
132	mkdir="$fsShellCommand mkdir"
133	rm="$fsShellCommand rm"
134	mkindex="$fsShellCommand mkindex"
135else
136	sPrefix=
137	# TODO: This should come from the environment.
138	tPrefix="$installDir/"
139	cd=cd
140	scd=:
141	cp="$copyattr -d"
142	copyAttrs="$copyattr"
143	ln=ln
144	mkdir=mkdir
145	rm=rm
146	mkindex=mkindex
147fi
148
149
150is_in_list()
151{
152	local element
153	for element in $2; do
154		if [ "$1" = "$element" ]; then
155			return 0
156		fi
157	done
158	return 1
159}
160
161
162extractFile()
163{
164	# extractFile <archive> <directory> <extractedSubDir>
165	archiveFile=$1
166	targetExtractedDir=$2
167	extractedSubDir=$3
168
169	extractDir=$tmpDir/extract
170	$rmAttrs -rf "$extractDir"
171	mkdir -p "$extractDir"
172
173	case "$archiveFile" in
174		*.zip)
175			echo "Extracting $archiveFile ..."
176			$unzip -q -d "$extractDir" "$archiveFile"
177			;;
178		*.tgz|*.tar.gz)
179			echo "Extracting $archiveFile ..."
180			tar -C "$extractDir" -xf "$archiveFile"
181			;;
182		*.hpkg)
183			echo "Extracting $archiveFile ..."
184			if [ -n "$extractedSubDir" ]; then
185				$package extract -C "$extractDir" "$archiveFile" \
186					"$extractedSubDir"
187			else
188				$package extract -C "$extractDir" "$archiveFile"
189			fi
190			;;
191		*)
192			echo "Unhandled archive extension in build_haiku_image" \
193				"extractFile()"
194			exit 1
195			;;
196	esac
197
198	if [ -f $extractDir/.OptionalPackageDescription ]; then
199		cat $extractDir/.OptionalPackageDescription >> $copyrightsFile
200		echo >> $copyrightsFile
201		rm $extractDir/.OptionalPackageDescription
202	fi
203
204	$cp -r "${sPrefix}$extractDir/$extractedSubDir/." \
205		"${tPrefix}$targetExtractedDir"
206
207	$rmAttrs -rf "$extractDir"
208}
209
210
211downloadFile()
212{
213	url=$1
214	path=$2
215
216	if [ ! -f "$path" ]; then
217		wget -O "$path" "$url"
218	fi
219}
220
221
222packageFileName()
223{
224	$package info -f "%fileName%" "$1"
225}
226
227
228mkdir -p $tmpDir
229copyrightsFile=$tmpDir/copyrights
230$rmAttrs -f $copyrightsFile
231
232if [ $isCD ]; then
233	# setup output dir
234	$rmAttrs -rf "$outputDir"
235	mkdir -p "$outputDir"
236fi
237
238# create the image and mount it
239if [ $isImage ]; then
240	echo
241
242	imageOffsetFlags=
243	if [ $isVMwareImage ]; then
244		imageOffsetFlags="--start-offset 65536"
245	fi
246
247	if [ ! $updateOnly ]; then
248		echo "Creating image ..."
249
250		imageFlags="-i${imageSize}M"
251		if [ ! "$dontClearImage" ]; then
252			imageFlags="$imageFlags -c"
253		fi
254
255		if [ $isVMwareImage ]; then
256			$vmdkimage -h 64k $imageFlags "$imagePath"
257		else
258			$createImage $imageFlags "$imagePath"
259		fi
260
261		$bfsShell --initialize $imageOffsetFlags "$imagePath" \
262			"$imageLabel" "block_size 2048"
263		$makebootable $imageOffsetFlags "$imagePath"
264	fi
265
266	$bfsShell -n $imageOffsetFlags "$imagePath" > /dev/null &
267	sleep 1
268
269	# Close FDs 5 and 6. Those represent the pipe ends that are used by the
270	# FS shell. Closing them in the shell process makes sure an unexpected death
271	# of the FS shell causes writing to/reading from the other ends to fail
272	# immediately.
273	exec 5>&- 6>&-
274
275	# bail out, if mounting fails
276	$cd .
277fi
278
279
280# Clean out the old packages directory, if updating all packages.
281if [ -n "$updateAllPackages" ]; then
282	echo "Removing old packages ..."
283	$rm -rf "${tPrefix}system/packages"
284	$mkdir -p "${tPrefix}system/packages"
285fi
286
287
288echo "Populating image ..."
289while [ $# -gt 0 ]; do
290	. $1
291	shift
292done
293
294
295# resolve package dependencies
296if [ -n "$resolvePackageDependencies" ]; then
297	echo "Resolving package dependencies ..."
298
299	packageUrls=`$getPackageDependencies $repositories -- $systemPackages`
300	for packageUrl in $packageUrls; do
301		packageFileName=`basename $packageUrl`
302		packageFilePath="$downloadDir/$packageFileName"
303		downloadFile $packageUrl "$packageFilePath"
304		$cp "${sPrefix}$packageFilePath" "${tPrefix}system/packages"
305		systemPackages="$systemPackages $packageFilePath"
306	done
307fi
308
309
310# install default settings for packages
311for packageFile in $systemPackages; do
312	if $package list -p $packageFile | egrep '^settings/' > /dev/null; then
313		extractFile $packageFile system/settings settings
314	fi
315done
316
317
318# add the concatenated copyrights as an attribute to AboutSystem
319# TODO: That might not be necessary, when all third-party software everything
320# is packaged. Though we might not package everything.
321
322# if [ ! $updateOnly ]; then
323# 	if [ -f $copyrightsFile ]; then
324# 		copyrightAttrs=$tmpDir/copyrightAttrs
325# 		$rmAttrs -f $copyrightAttrs
326# 		touch $copyrightAttrs
327# 		$addattr -f $copyrightsFile COPYRIGHTS $copyrightAttrs
328# 		$copyAttrs ${sPrefix}$copyrightAttrs ${tPrefix}system/apps/AboutSystem
329# 	fi
330# fi
331
332if [ $isCD ]; then
333	# generate the attribute stores
334	echo "Generating attribute stores ..."
335	$generate_attribute_stores "$tPrefix"
336
337	echo "Copying boot image ..."
338	$cp "$cdBootFloppy" "$outputDir"
339
340	if [ $(which mkisofs) ]; then
341		# build the iso image using mkisofs
342		echo "Building CD image (mkisofs)..."
343		mkisofs -uid 0 -gid 0 -b `basename $cdBootFloppy` -R -V "$cdLabel" -o "$cdImagePath" "$tPrefix"
344	elif [ $(which genisoimage) ]; then
345		# build the iso image using genisoimage
346		echo "Building CD image (genisoimage)..."
347		echo "WARNING: genisoimage fallback has known problems with long filenames!"
348		echo "         Please install mkisofs before making production releases!"
349		genisoimage -r -iso-level 4 -b `basename $cdBootFloppy` -V "$cdLabel" -o "$cdImagePath" "$tPrefix"
350	else
351		echo "you need mkisofs (preferred) or genisoimage to create a CD image."
352		exit 1
353	fi
354
355	# cleanup output dir
356	$rmAttrs -rf "$outputDir"
357fi
358
359# unmount
360if [ $isImage ]; then
361	echo "Unmounting ..."
362	$fsShellCommand sync
363	$fsShellCommand quit
364fi
365