1#!/bin/ksh -p 2# 3# CDDL HEADER START 4# 5# The contents of this file are subject to the terms of the 6# Common Development and Distribution License (the "License"). 7# You may not use this file except in compliance with the License. 8# 9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10# or http://www.opensolaris.org/os/licensing. 11# See the License for the specific language governing permissions 12# and limitations under the License. 13# 14# When distributing Covered Code, include this CDDL HEADER in each 15# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16# If applicable, add the following below this CDDL HEADER, with the 17# fields enclosed by brackets "[]" replaced with your own identifying 18# information: Portions Copyright [yyyy] [name of copyright owner] 19# 20# CDDL HEADER END 21# 22 23# Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24# Use is subject to license terms. 25 26# ident "%Z%%M% %I% %E% SMI" 27 28format=ufs 29ALT_ROOT= 30ALTROOT_ARG= 31compress=yes 32SPLIT=unknown 33ERROR=0 34dirsize32=0 35dirsize64=0 36 37PLAT=`uname -m` 38if [ $PLAT = i86pc ] ; then 39 ARCH64=amd64 40else 41 ARCH64=sparcv9 42fi 43BOOT_ARCHIVE=platform/$PLAT/boot_archive 44BOOT_ARCHIVE_64=platform/$PLAT/$ARCH64/boot_archive 45 46# 47# set path, but inherit /tmp/bfubin if owned by 48# same uid executing this process, which must be root. 49# 50if [ "`echo $PATH | cut -f 1 -d :`" = /tmp/bfubin ] && \ 51 [ -O /tmp/bfubin ] ; then 52 export PATH=/tmp/bfubin 53 export GZIP_CMD=/tmp/bfubin/gzip 54else 55 export PATH=/usr/sbin:/usr/bin:/sbin 56 export GZIP_CMD=/usr/bin/gzip 57fi 58 59EXTRACT_FILELIST="/boot/solaris/bin/extract_boot_filelist" 60 61# 62# Parse options 63# 64while [ "$1" != "" ] 65do 66 case $1 in 67 -R) shift 68 ALT_ROOT="$1" 69 if [ "$ALT_ROOT" != "/" ]; then 70 echo "Creating boot_archive for $ALT_ROOT" 71 ALTROOT_ARG="-R $ALT_ROOT" 72 EXTRACT_FILELIST="${ALT_ROOT}${EXTRACT_FILELIST}" 73 fi 74 ;; 75 -n|--nocompress) compress=no 76 ;; 77 *) echo Usage: ${0##*/}: [-R \<root\>] [--nocompress] 78 exit 79 ;; 80 esac 81 shift 82done 83 84if [ -x /usr/bin/mkisofs -o -x /tmp/bfubin/mkisofs ] ; then 85 format=isofs 86fi 87 88# 89# mkisofs on s8 doesn't support functionality used by GRUB boot. 90# Use ufs format for boot archive instead. 91# 92release=`uname -r` 93if [ "$release" = "5.8" ]; then 94 format=ufs 95fi 96 97shift `expr $OPTIND - 1` 98 99if [ $# -eq 1 ]; then 100 ALT_ROOT="$1" 101 echo "Creating boot_archive for $ALT_ROOT" 102fi 103 104if [ $PLAT = i86pc ] ; then 105 rundir=`dirname $0` 106 if [ ! -x "$rundir"/symdef ]; then 107 # Shouldn't happen 108 echo "Warning: $rundir/symdef not present." 109 echo "Creating single archive at $ALT_ROOT/$BOOT_ARCHIVE" 110 SPLIT=no 111 compress=no 112 elif "$rundir"/symdef "$ALT_ROOT"/platform/i86pc/kernel/unix \ 113 dboot_image 2>/dev/null; then 114 SPLIT=yes 115 else 116 SPLIT=no 117 compress=no 118 fi 119else # must be sparc 120 SPLIT=no # there's only 64-bit (sparcv9), so don't split 121 compress=no 122fi 123 124[ -x $GZIP_CMD ] || compress=no 125 126function cleanup 127{ 128 umount -f "$rdmnt32" 2>/dev/null 129 umount -f "$rdmnt64" 2>/dev/null 130 lofiadm -d "$rdfile32" 2>/dev/null 131 lofiadm -d "$rdfile64" 2>/dev/null 132 [ -n "$rddir" ] && rm -fr "$rddir" 2> /dev/null 133 [ -n "$new_rddir" ] && rm -fr "$new_rddir" 2>/dev/null 134} 135 136function getsize 137{ 138 # Estimate image size and add 10% overhead for ufs stuff. 139 # Note, we can't use du here in case we're on a filesystem, e.g. zfs, 140 # in which the disk usage is less than the sum of the file sizes. 141 # The nawk code 142 # 143 # {t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5} 144 # 145 # below rounds up the size of a file/directory, in bytes, to the 146 # next multiple of 1024. This mimics the behavior of ufs especially 147 # with directories. This results in a total size that's slightly 148 # bigger than if du was called on a ufs directory. 149 size32=$(cat "$list32" | xargs -I {} ls -lLd "{}" 2> /dev/null | 150 nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5} 151 END {print int(t * 1.10 / 1024)}') 152 (( size32 += dirsize32 )) 153 size64=$(cat "$list64" | xargs -I {} ls -lLd "{}" 2> /dev/null | 154 nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5} 155 END {print int(t * 1.10 / 1024)}') 156 (( size64 += dirsize64 )) 157 (( total_size = size32 + size64 )) 158 159 if [ $compress = yes ] ; then 160 total_size=`echo $total_size | nawk '{print int($1 / 2)}'` 161 fi 162} 163 164# 165# Copies all desired files to a target directory. One argument should be 166# passed: the file containing the list of files to copy. This function also 167# depends on several variables that must be set before calling: 168# 169# $ALT_ROOT - the target directory 170# $compress - whether or not the files in the archives should be compressed 171# $rdmnt - the target directory 172# 173function copy_files 174{ 175 list="$1" 176 177 # 178 # If compress is set, the files are gzip'd and put in the correct 179 # location in the loop. Nothing is printed, so the pipe and cpio 180 # at the end is a nop. 181 # 182 # If compress is not set, the file names are printed, which causes 183 # the cpio at the end to do the copy. 184 # 185 while read path 186 do 187 if [ $compress = yes ]; then 188 dir="${path%/*}" 189 [ -d "$rdmnt/$dir" ] || mkdir -p "$rdmnt/$dir" 190 $GZIP_CMD -c "$path" > "$rdmnt/$path" 191 else 192 print "$path" 193 fi 194 done <"$list" | cpio -pdum "$rdmnt" 2>/dev/null 195 196 if [ `uname -p` = sparc ] ; then 197 # copy links 198 find $filelist -type l -print 2>/dev/null |\ 199 cpio -pdum "$rdmnt" 2>/dev/null 200 if [ $compress = yes ] ; then 201 # always copy unix uncompressed 202 find $filelist -name unix -type f -print 2>/dev/null |\ 203 cpio -pdum "$rdmnt" 2>/dev/null 204 fi 205 fi 206 207} 208 209# 210# The first argument can be: 211# 212# "both" - create an archive with both 32-bit and 64-bit binaries 213# "32-bit" - create an archive with only 32-bit binaries 214# "64-bit" - create an archive with only 64-bit binaries 215# 216function create_ufs 217{ 218 which=$1 219 archive=$2 220 lofidev=$3 221 222 # should we exclude amd64 binaries? 223 if [ "$which" = "32-bit" ]; then 224 rdfile="$rdfile32" 225 rdmnt="$rdmnt32" 226 list="$list32" 227 elif [ "$which" = "64-bit" ]; then 228 rdfile="$rdfile64" 229 rdmnt="$rdmnt64" 230 list="$list64" 231 else 232 rdfile="$rdfile32" 233 rdmnt="$rdmnt32" 234 list="$list32" 235 fi 236 237 newfs $lofidev < /dev/null 2> /dev/null 238 mkdir "$rdmnt" 239 mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1 240 mount -o nologging $lofidev "$rdmnt" 241 files= 242 243 # do the actual copy 244 copy_files "$list" 245 umount "$rdmnt" 246 rmdir "$rdmnt" 247 248 if [ `uname -p` = sparc ] ; then 249 rlofidev=`echo "$lofidev" | sed -e "s/dev\/lofi/dev\/rlofi/"` 250 bb="$ALT_ROOT/usr/platform/`uname -i`/lib/fs/ufs/bootblk" 251 installboot "$bb" $rlofidev 252 fi 253 254 # 255 # Check if gzip exists in /usr/bin, so we only try to run gzip 256 # on systems that have gzip. Then run gzip out of the patch to 257 # pick it up from bfubin or something like that if needed. 258 # 259 # If compress is set, the individual files in the archive are 260 # compressed, and the final compression will accomplish very 261 # little. To save time, we skip the gzip in this case. 262 # 263 if [ `uname -p` = i386 ] && [ $compress = no ] && \ 264 [ -x $GZIP_CMD ] ; then 265 gzip -c "$rdfile" > "${archive}-new" 266 else 267 cat "$rdfile" > "${archive}-new" 268 fi 269} 270 271# 272# The first argument can be: 273# 274# "both" - create an archive with both 32-bit and 64-bit binaries 275# "32-bit" - create an archive with only 32-bit binaries 276# "64-bit" - create an archive with only 64-bit binaries 277# 278function create_isofs 279{ 280 which=$1 281 archive=$2 282 283 # should we exclude amd64 binaries? 284 if [ "$which" = "32-bit" ]; then 285 rdmnt="$rdmnt32" 286 errlog="$errlog32" 287 list="$list32" 288 elif [ "$which" = "64-bit" ]; then 289 rdmnt="$rdmnt64" 290 errlog="$errlog64" 291 list="$list64" 292 else 293 rdmnt="$rdmnt32" 294 errlog="$errlog32" 295 list="$list32" 296 fi 297 298 # create image directory seed with graft points 299 mkdir "$rdmnt" 300 files= 301 isocmd="mkisofs -quiet -graft-points -dlrDJN -relaxed-filenames" 302 303 if [ `uname -p` = sparc ] ; then 304 bb="$ALT_ROOT/usr/platform/`uname -i`/lib/fs/hsfs/bootblk" 305 isocmd="$isocmd -G \"$bb\"" 306 fi 307 308 copy_files "$list" 309 isocmd="$isocmd \"$rdmnt\"" 310 rm -f "$errlog" 311 312 # 313 # Check if gzip exists in /usr/bin, so we only try to run gzip 314 # on systems that have gzip. Then run gzip out of the patch to 315 # pick it up from bfubin or something like that if needed. 316 # 317 # If compress is set, the individual files in the archive are 318 # compressed, and the final compression will accomplish very 319 # little. To save time, we skip the gzip in this case. 320 # 321 if [ `uname -p` = i386 ] &&[ $compress = no ] && [ -x $GZIP_CMD ] 322 then 323 ksh -c "$isocmd" 2> "$errlog" | \ 324 gzip > "${archive}-new" 325 else 326 ksh -c "$isocmd" 2> "$errlog" > "${archive}-new" 327 fi 328 329 dd_ret=0 330 if [ `uname -p` = sparc ] ; then 331 bb="$ALT_ROOT/usr/platform/`uname -i`/lib/fs/hsfs/bootblk" 332 dd if="$bb" of="${archive}-new" bs=1b oseek=1 count=15 \ 333 conv=notrunc conv=sync >> "$errlog" 2>&1 334 dd_ret=$? 335 fi 336 337 if [ -s "$errlog" ] || [ $dd_ret -ne 0 ] ; then 338 grep Error: "$errlog" >/dev/null 2>&1 339 if [ $? -eq 0 ] || [ $dd_ret -ne 0 ] ; then 340 cat "$errlog" 341 rm -f "${archive}-new" 342 fi 343 fi 344 rm -f "$errlog" 345} 346 347function create_archive 348{ 349 which=$1 350 archive=$2 351 lofidev=$3 352 353 echo "updating $archive" 354 355 if [ "$format" = "ufs" ]; then 356 create_ufs "$which" "$archive" "$lofidev" 357 else 358 create_isofs "$which" "$archive" 359 fi 360 361 # sanity check the archive before moving it into place 362 # 363 ARCHIVE_SIZE=`ls -l "${archive}-new" | nawk '{ print $5 }'` 364 if [ $compress = yes ] || [ `uname -p` = sparc ] ; then 365 # 366 # 'file' will report "English text" for uncompressed 367 # boot_archives. Checking for that doesn't seem stable, 368 # so we just check that the file exists. 369 # 370 ls "${archive}-new" >/dev/null 2>&1 371 else 372 # 373 # the file type check also establishes that the 374 # file exists at all 375 # 376 LC_MESSAGES=C file "${archive}-new" | grep gzip > /dev/null 377 fi 378 379 if [ $? = 1 ] && [ -x $GZIP_CMD ] || [ $ARCHIVE_SIZE -lt 5000 ] 380 then 381 # 382 # Two of these functions may be run in parallel. We 383 # need to allow the other to clean up, so we can't 384 # exit immediately. Instead, we set a flag. 385 # 386 echo "update of $archive failed" 387 ERROR=1 388 else 389 lockfs -f "/$ALT_ROOT" 2>/dev/null 390 mv "${archive}-new" "$archive" 391 lockfs -f "/$ALT_ROOT" 2>/dev/null 392 fi 393 394} 395 396function fatal_error 397{ 398 print -u2 $* 399 exit 1 400} 401 402# 403# get filelist 404# 405if [ ! -f "$ALT_ROOT/boot/solaris/filelist.ramdisk" ] && 406 [ ! -f "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" ] 407then 408 print -u2 "Can't find filelist.ramdisk" 409 exit 1 410fi 411filelist=$($EXTRACT_FILELIST $ALTROOT_ARG /boot/solaris/filelist.ramdisk \ 412 /etc/boot/solaris/filelist.ramdisk 2>/dev/null | sort -u) 413 414# 415# We use /tmp/ for scratch space now. This may be changed later if there 416# is insufficient space in /tmp/. 417# 418rddir="/tmp/create_ramdisk.$$.tmp" 419new_rddir= 420rm -rf "$rddir" 421mkdir "$rddir" || fatal_error "Could not create temporary directory $rddir" 422 423# Clean up upon exit. 424trap 'cleanup' EXIT 425 426list32="$rddir/filelist.32" 427list64="$rddir/filelist.64" 428 429touch $list32 $list64 430 431# 432# This loop creates the 32-bit and 64-bit lists of files. The 32-bit list 433# is written to stdout, which is redirected at the end of the loop. The 434# 64-bit list is appended with each write. 435# 436cd "/$ALT_ROOT" 437find $filelist -print 2>/dev/null | while read path 438do 439 if [ $SPLIT = no ]; then 440 print "$path" 441 elif [ -d "$path" ]; then 442 if [ $format = ufs ]; then 443 size=`ls -lLd "$path" | nawk ' 444 {print ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}'` 445 if [ `basename "$path"` != "amd64" ]; then 446 (( dirsize32 += size )) 447 fi 448 (( dirsize64 += size )) 449 fi 450 else 451 case `LC_MESSAGES=C /usr/bin/file -m /dev/null "$path" 2>/dev/null` in 452 *ELF\ 64-bit*) 453 print "$path" >> "$list64" 454 ;; 455 *ELF\ 32-bit*) 456 print "$path" 457 ;; 458 *) 459 # put in both lists 460 print "$path" 461 print "$path" >> "$list64" 462 esac 463 fi 464done >"$list32" 465 466if [ $format = ufs ] ; then 467 # calculate image size 468 getsize 469 470 # check to see if there is sufficient space in tmpfs 471 # 472 tmp_free=`df -b /tmp | tail -1 | awk '{ printf ($2) }'` 473 (( tmp_free = tmp_free / 2 )) 474 475 if [ $total_size -gt $tmp_free ] ; then 476 # assumes we have enough scratch space on $ALT_ROOT 477 new_rddir="/$ALT_ROOT/create_ramdisk.$$.tmp" 478 rm -rf "$new_rddir" 479 mkdir "$new_rddir" || fatal_error \ 480 "Could not create temporary directory $new_rddir" 481 482 # Save the file lists 483 mv "$list32" "$new_rddir"/ 484 mv "$list64" "$new_rddir"/ 485 list32="/$new_rddir/filelist.32" 486 list64="/$new_rddir/filelist.64" 487 488 # Remove the old $rddir and set the new value of rddir 489 rm -rf "$rddir" 490 rddir="$new_rddir" 491 new_rddir= 492 fi 493fi 494 495rdfile32="$rddir/rd.file.32" 496rdfile64="$rddir/rd.file.64" 497rdmnt32="$rddir/rd.mount.32" 498rdmnt64="$rddir/rd.mount.64" 499errlog32="$rddir/rd.errlog.32" 500errlog64="$rddir/rd.errlog.64" 501lofidev32="" 502lofidev64="" 503 504if [ $SPLIT = yes ]; then 505 # 506 # We can't run lofiadm commands in parallel, so we have to do 507 # them here. 508 # 509 if [ "$format" = "ufs" ]; then 510 mkfile ${size32}k "$rdfile32" 511 lofidev32=`lofiadm -a "$rdfile32"` 512 mkfile ${size64}k "$rdfile64" 513 lofidev64=`lofiadm -a "$rdfile64"` 514 fi 515 create_archive "32-bit" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 & 516 create_archive "64-bit" "$ALT_ROOT/$BOOT_ARCHIVE_64" $lofidev64 517 wait 518 if [ "$format" = "ufs" ]; then 519 lofiadm -d "$rdfile32" 520 lofiadm -d "$rdfile64" 521 fi 522else 523 if [ "$format" = "ufs" ]; then 524 mkfile ${total_size}k "$rdfile32" 525 lofidev32=`lofiadm -a "$rdfile32"` 526 fi 527 create_archive "both" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 528 [ "$format" = "ufs" ] && lofiadm -d "$rdfile32" 529fi 530if [ $ERROR = 1 ]; then 531 cleanup 532 exit 1 533fi 534 535# 536# For the diskless case, hardlink archive to /boot to make it 537# visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>. 538# NOTE: this script must work on both client and server. 539# 540grep "[ ]/[ ]*nfs[ ]" "$ALT_ROOT/etc/vfstab" > /dev/null 541if [ $? = 0 ]; then 542 rm -f "$ALT_ROOT/boot/boot_archive" "$ALT_ROOT/boot/amd64/boot_archive" 543 ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/boot_archive" 544 ln "$ALT_ROOT/$BOOT_ARCHIVE_64" "$ALT_ROOT/boot/amd64/boot_archive" 545fi 546[ -n "$rddir" ] && rm -rf "$rddir" 547