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 80 mkindex="mkindex -d $tPrefix" 81elif [ $isImage ]; then 82 # If FIFOs are used for the communication with the FS shell, prepare them. 83 if $fsShellCommand --uses-fifos; then 84 fifoBasePath=/tmp/build_haiku_image-$$-fifo 85 toFSShellFifo=${fifoBasePath}-to-shell 86 fromFSShellFifo=${fifoBasePath}-from-shell 87 88 rm -f $toFSShellFifo $fromFSShellFifo 89 mkfifo $toFSShellFifo $fromFSShellFifo 90 91 # Open the FIFOs such that they are ready for the fsShellCommand. This 92 # also makes sure that they remain open until this script exits. When we 93 # exit while the FS shell is still running and waiting for commands, 94 # closing of our file descriptors will break the FIFOs and the FS shell 95 # will exit, too. 96 # Note: A bit of trickery is needed since opening one end blocks until 97 # someone opens the other end. 98 sleep 3<$fromFSShellFifo 1 & 99 exec 6>$fromFSShellFifo 3<$fromFSShellFifo 100 sleep 5<$toFSShellFifo 1 & 101 exec 4>$toFSShellFifo 5<$toFSShellFifo 102 103 # Remove the FIFO files again -- we have the open FDs, so they can 104 # still be used and this makes sure they won't hang around any further. 105 rm -f $toFSShellFifo $fromFSShellFifo 106 107 # Remap the fsShellCommand and bfsShell such that they don't inherit the 108 # wrong FDs. For both fsShellCommand and bfsShell FD 3 is the input from 109 # the respectively other program, FD 4 is the output to it. 110 actualFSShellCommand="$fsShellCommand" 111 actualBFSShell="$bfsShell" 112 113 fsShellCommandWrapper() 114 { 115 $actualFSShellCommand 5>&- 6>&- "$@" 116 } 117 118 bfsShellWrapper() 119 { 120 $actualBFSShell 3>&5 4<&6 "$@" 121 } 122 123 fsShellCommand=fsShellCommandWrapper 124 bfsShell=bfsShellWrapper 125 fi 126 127 # set up the other commands 128 sPrefix=: 129 tPrefix=/myfs/ 130 cd="$fsShellCommand cd" 131 scd="$fsShellCommand cd" 132 cp="$fsShellCommand cp -f" 133 copyAttrs="$fsShellCommand cp -a" 134 ln="$fsShellCommand ln" 135 mkdir="$fsShellCommand mkdir" 136 rm="$fsShellCommand rm" 137 mkindex="$fsShellCommand mkindex" 138else 139 sPrefix= 140 # TODO: This should come from the environment. 141 tPrefix="$installDir/" 142 cd=cd 143 scd=: 144 cp="$copyattr -d" 145 copyAttrs="$copyattr" 146 ln=ln 147 mkdir=mkdir 148 rm=rm 149 mkindex="mkindex -d $tPrefix" 150fi 151 152 153is_in_list() 154{ 155 local element 156 for element in $2; do 157 if [ "$1" = "$element" ]; then 158 return 0 159 fi 160 done 161 return 1 162} 163 164 165extractFile() 166{ 167 # extractFile <archive> <directory> <extractedSubDir> 168 archiveFile=$1 169 targetExtractedDir=$2 170 extractedSubDir=$3 171 172 extractDir=$tmpDir/extract 173 $rmAttrs -rf "$extractDir" 174 mkdir -p "$extractDir" 175 176 case "$archiveFile" in 177 *.zip) 178 echo "Extracting $archiveFile ..." 179 $unzip -q -d "$extractDir" "$archiveFile" 180 ;; 181 *.tgz|*.tar.gz) 182 echo "Extracting $archiveFile ..." 183 tar -C "$extractDir" -xf "$archiveFile" 184 ;; 185 *.hpkg) 186 echo "Extracting $archiveFile ..." 187 if [ -n "$extractedSubDir" ]; then 188 $package extract -C "$extractDir" "$archiveFile" \ 189 "$extractedSubDir" 190 else 191 $package extract -C "$extractDir" "$archiveFile" 192 fi 193 ;; 194 *) 195 echo "Unhandled archive extension in build_haiku_image" \ 196 "extractFile()" 197 exit 1 198 ;; 199 esac 200 201 if [ -f $extractDir/.OptionalPackageDescription ]; then 202 cat $extractDir/.OptionalPackageDescription >> $copyrightsFile 203 echo >> $copyrightsFile 204 rm $extractDir/.OptionalPackageDescription 205 fi 206 207 $cp -r "${sPrefix}$extractDir/$extractedSubDir/." \ 208 "${tPrefix}$targetExtractedDir" 209 210 $rmAttrs -rf "$extractDir" 211} 212 213 214downloadFile() 215{ 216 url=$1 217 path=$2 218 219 if [ ! -f "$path" ]; then 220 if [ "$noDownloads" = "1" ]; then 221 echo "ERROR: Would need to download $url, but HAIKU_NO_DOWNLOADS " 222 "is set!" 223 exit 1 224 fi 225 wget -O "$path" "$url" 226 fi 227} 228 229 230packageFileName() 231{ 232 $package info -f "%fileName%" "$1" 233} 234 235 236mkdir -p $tmpDir 237copyrightsFile=$tmpDir/copyrights 238$rmAttrs -f $copyrightsFile 239 240if [ $isCD ]; then 241 # setup output dir 242 $rmAttrs -rf "$outputDir" 243 mkdir -p "$outputDir" 244fi 245 246# create the image and mount it 247if [ $isImage ]; then 248 echo 249 250 imageOffsetFlags= 251 if [ $isVMwareImage ]; then 252 imageOffsetFlags="--start-offset 65536" 253 fi 254 255 if [ ! $updateOnly ]; then 256 echo "Creating image ..." 257 258 imageFlags="-i${imageSize}M" 259 if [ ! "$dontClearImage" ]; then 260 imageFlags="$imageFlags -c" 261 fi 262 263 if [ $isVMwareImage ]; then 264 $vmdkimage -h 64k $imageFlags "$imagePath" 265 else 266 $createImage $imageFlags "$imagePath" 267 fi 268 269 $bfsShell --initialize $imageOffsetFlags "$imagePath" \ 270 "$imageLabel" "block_size 2048" 271 $makebootable $imageOffsetFlags "$imagePath" 272 fi 273 274 $bfsShell -n $imageOffsetFlags "$imagePath" > /dev/null & 275 sleep 1 276 277 # Close FDs 5 and 6. Those represent the pipe ends that are used by the 278 # FS shell. Closing them in the shell process makes sure an unexpected death 279 # of the FS shell causes writing to/reading from the other ends to fail 280 # immediately. 281 exec 5>&- 6>&- 282 283 # bail out, if mounting fails 284 $cd . 285fi 286 287 288# Clean out the old packages directory, if updating all packages. 289if [ -n "$updateAllPackages" ]; then 290 echo "Removing old packages ..." 291 $rm -rf "${tPrefix}system/packages" 292 $mkdir -p "${tPrefix}system/packages" 293fi 294 295if [ ! $updateOnly ] && [ ! $isCD ]; then 296echo "Creating filesystem indices..." 297 $mkindex -t string Audio:Album 298 $mkindex -t string Audio:Artist 299 $mkindex -t string Media:Genre 300 $mkindex -t string Media:Title 301 $mkindex -t string MAIL:account 302 $mkindex -t string MAIL:cc 303 $mkindex -t string MAIL:chain 304 $mkindex -t string MAIL:from 305 $mkindex -t string MAIL:name 306 $mkindex -t string MAIL:pending_chain 307 $mkindex -t string MAIL:priority 308 $mkindex -t string MAIL:reply 309 $mkindex -t string MAIL:status 310 $mkindex -t string MAIL:subject 311 $mkindex -t string MAIL:thread 312 $mkindex -t string MAIL:to 313 $mkindex -t string META:address 314 $mkindex -t string META:city 315 $mkindex -t string META:company 316 $mkindex -t string META:county 317 $mkindex -t string META:email 318 $mkindex -t string META:fax 319 $mkindex -t string META:group 320 $mkindex -t string META:hphone 321 $mkindex -t string META:name 322 $mkindex -t string META:nickname 323 $mkindex -t string META:state 324 $mkindex -t string META:url 325 $mkindex -t string META:wphone 326 $mkindex -t string META:zip 327 328 $mkindex -t int32 Media:Rating 329 $mkindex -t int32 Media:Year 330 $mkindex -t int32 MAIL:account_id 331 $mkindex -t int32 MAIL:read 332 $mkindex -t int32 MAIL:when 333 $mkindex -t int32 MAIL:draft 334 $mkindex -t int32 MAIL:flags 335fi 336 337echo "Populating image ..." 338while [ $# -gt 0 ]; do 339 . $1 340 shift 341done 342 343 344# resolve package dependencies 345if [ -n "$resolvePackageDependencies" ]; then 346 echo "Resolving package dependencies ..." 347 348 packageUrls=`$getPackageDependencies $repositories -- $systemPackages` 349 for packageUrl in $packageUrls; do 350 packageFileName=`basename $packageUrl` 351 if [ "$otherPackages" != "${otherPackages#*$packageFileName}" ]; then 352 echo "ERROR: $packageFileName is a dependency of a package installed in /system/packages," \ 353 "but it is in another (i.e. unactivated) package directory!" 354 exit 1 355 fi 356 packageFilePath="$downloadDir/$packageFileName" 357 downloadFile $packageUrl "$packageFilePath" 358 $cp "${sPrefix}$packageFilePath" "${tPrefix}system/packages" 359 systemPackages="$systemPackages $packageFilePath" 360 done 361 362 # validate dependencies of optional packages 363 packageUrls=`$getPackageDependencies $repositories -- $systemPackages $otherPackages` 364 packageFileNames="" 365 for packageUrl in $packageUrls; do 366 packageFileNames="$packageFileNames `basename $packageUrl`" 367 done 368 if [ ! -z "$packageFileNames" ]; then 369 echo "ERROR: Some of the unactivated (i.e. optional) packages have the following unmet dependencies:" 370 echo $packageFileNames 371 exit 1 372 fi 373fi 374 375# install default settings for packages 376for packageFile in $systemPackages; do 377 if $package list -p $packageFile | grep -E '^settings/' > /dev/null; then 378 extractFile $packageFile system/settings settings 379 fi 380done 381 382 383if [ $isCD ]; then 384 # generate the attribute stores 385 echo "Generating attribute stores ..." 386 $generate_attribute_stores "$tPrefix" 387 388 echo "Copying boot image ..." 389 $cp "$cdBootFloppy" "$outputDir" 390 391 if [ $(which xorriso) ]; then 392 # build the iso image using xorriso 393 echo "Building CD image..." 394 xorriso -as mkisofs -r -b `basename $cdBootFloppy` \ 395 -V "$cdLabel" -o "$cdImagePath" "$tPrefix" 396 else 397 echo "you need xorriso to create a CD image." 398 exit 1 399 fi 400 401 # cleanup output dir 402 $rmAttrs -rf "$outputDir" 403fi 404 405# unmount 406if [ $isImage ]; then 407 echo "Unmounting ..." 408 $fsShellCommand sync 409 $fsShellCommand quit 410fi 411