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