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