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