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