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