10Sstevel@tonic-gate#!/bin/ksh -p 20Sstevel@tonic-gate# 30Sstevel@tonic-gate# CDDL HEADER START 40Sstevel@tonic-gate# 50Sstevel@tonic-gate# The contents of this file are subject to the terms of the 62334Ssetje# Common Development and Distribution License (the "License"). 72334Ssetje# You may not use this file except in compliance with the License. 80Sstevel@tonic-gate# 90Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate# See the License for the specific language governing permissions 120Sstevel@tonic-gate# and limitations under the License. 130Sstevel@tonic-gate# 140Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate# 200Sstevel@tonic-gate# CDDL HEADER END 210Sstevel@tonic-gate# 220Sstevel@tonic-gate 23*3446Smrj# Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate# Use is subject to license terms. 250Sstevel@tonic-gate 262334Ssetje# ident "%Z%%M% %I% %E% SMI" 27174Sjg 280Sstevel@tonic-gateformat=ufs 290Sstevel@tonic-gateALT_ROOT= 30*3446Smrjcompress=yes 31*3446SmrjSPLIT=unknown 32*3446SmrjERROR=0 330Sstevel@tonic-gate 340Sstevel@tonic-gateBOOT_ARCHIVE=platform/i86pc/boot_archive 35*3446SmrjBOOT_ARCHIVE_64=platform/i86pc/amd64/boot_archive 360Sstevel@tonic-gate 372334Ssetjeexport PATH=$PATH:/usr/sbin:/usr/bin:/sbin 380Sstevel@tonic-gate 390Sstevel@tonic-gate# 400Sstevel@tonic-gate# Parse options 410Sstevel@tonic-gate# 42*3446Smrjwhile [ "$1" != "" ] 430Sstevel@tonic-gatedo 44*3446Smrj case $1 in 45*3446Smrj -R) shift 46*3446Smrj ALT_ROOT="$1" 470Sstevel@tonic-gate if [ "$ALT_ROOT" != "/" ]; then 482334Ssetje echo "Creating ram disk for $ALT_ROOT" 490Sstevel@tonic-gate fi 500Sstevel@tonic-gate ;; 51*3446Smrj -n|--nocompress) compress=no ;; 52*3446Smrj *) echo Usage: ${0##*/}: [-R \<root\>] [--nocompress] 530Sstevel@tonic-gate exit ;; 540Sstevel@tonic-gate esac 55*3446Smrj shift 560Sstevel@tonic-gatedone 570Sstevel@tonic-gate 580Sstevel@tonic-gateif [ -x /usr/bin/mkisofs -o -x /tmp/bfubin/mkisofs ] ; then 590Sstevel@tonic-gate format=isofs 600Sstevel@tonic-gatefi 610Sstevel@tonic-gate 62621Svikram# 63621Svikram# mkisofs on s8 doesn't support functionality used by GRUB boot. 64621Svikram# Use ufs format for boot archive instead. 65621Svikram# 66621Svikramrelease=`uname -r` 67621Svikramif [ "$release" = "5.8" ]; then 68*3446Smrj format=ufs 69621Svikramfi 70621Svikram 710Sstevel@tonic-gateshift `expr $OPTIND - 1` 720Sstevel@tonic-gate 730Sstevel@tonic-gateif [ $# -eq 1 ]; then 742334Ssetje ALT_ROOT="$1" 752334Ssetje echo "Creating ram disk for $ALT_ROOT" 760Sstevel@tonic-gatefi 770Sstevel@tonic-gate 78*3446Smrjrundir=`dirname $0` 79*3446Smrjif [ ! -x $rundir/symdef ]; then 80*3446Smrj # Shouldn't happen 81*3446Smrj echo "Warning: $rundir/symdef not present." 82*3446Smrj echo "Creating single archive at $ALT_ROOT/platform/i86pc/boot_archive" 83*3446Smrj SPLIT=no 84*3446Smrj compress=no 85*3446Smrjelif $rundir/symdef "$ALT_ROOT"/platform/i86pc/kernel/unix \ 86*3446Smrj dboot_image 2>/dev/null; then 87*3446Smrj SPLIT=yes 88*3446Smrjelse 89*3446Smrj SPLIT=no 90*3446Smrj compress=no 91*3446Smrjfi 92*3446Smrj 93*3446Smrj[ -x /usr/bin/gzip ] || compress=no 94*3446Smrj 952334Ssetjefunction cleanup 962334Ssetje{ 97*3446Smrj umount -f "$rdmnt32" 2>/dev/null 98*3446Smrj umount -f "$rdmnt64" 2>/dev/null 99*3446Smrj lofiadm -d "$rdfile32" 2>/dev/null 100*3446Smrj lofiadm -d "$rdfile64" 2>/dev/null 1012334Ssetje rm -fr "$rddir" 2> /dev/null 1020Sstevel@tonic-gate} 1030Sstevel@tonic-gate 1042334Ssetjefunction getsize 1052334Ssetje{ 1062511Sjongkis # Estimate image size and add %10 overhead for ufs stuff. 1072511Sjongkis # Note, we can't use du here in case we're on a filesystem, e.g. zfs, 1082511Sjongkis # in which the disk usage is less than the sum of the file sizes. 1092511Sjongkis # The nawk code 1102511Sjongkis # 1112511Sjongkis # {t += ($7 % 1024) ? (int($7 / 1024) + 1) * 1024 : $7} 1122511Sjongkis # 1132511Sjongkis # below rounds up the size of a file/directory, in bytes, to the 1142511Sjongkis # next multiple of 1024. This mimics the behavior of ufs especially 1152511Sjongkis # with directories. This results in a total size that's slightly 1162511Sjongkis # bigger than if du was called on a ufs directory. 1172851Sjongkis total_size=$(cd "/$ALT_ROOT" 118*3446Smrj find $filelist -ls 2>/dev/null | nawk ' 1192851Sjongkis {t += ($7 % 1024) ? (int($7 / 1024) + 1) * 1024 : $7} 1202851Sjongkis END {print int(t * 1.10 / 1024)}') 1210Sstevel@tonic-gate} 1220Sstevel@tonic-gate 123*3446Smrj# 124*3446Smrj# The first argument can be: 125*3446Smrj# 126*3446Smrj# "both" - create an archive with both 32-bit and 64-bit binaries 127*3446Smrj# "32-bit" - create an archive with only 32-bit binaries 128*3446Smrj# "64-bit" - create an archive with only 64-bit binaries 129*3446Smrj# 1300Sstevel@tonic-gatefunction create_ufs 1310Sstevel@tonic-gate{ 132*3446Smrj which=$1 133*3446Smrj archive=$2 134*3446Smrj lofidev=$3 1350Sstevel@tonic-gate 136*3446Smrj # should we exclude amd64 binaries? 137*3446Smrj if [ "$which" = "32-bit" ]; then 138*3446Smrj NO_AMD64="-type d -name amd64 -prune -o" 139*3446Smrj rdfile="$rdfile32" 140*3446Smrj rdmnt="$rdmnt32" 141*3446Smrj elif [ "$which" = "64-bit" ]; then 142*3446Smrj NO_AMD64="" 143*3446Smrj rdfile="$rdfile64" 144*3446Smrj rdmnt="$rdmnt64" 145*3446Smrj else 146*3446Smrj NO_AMD64="" 147*3446Smrj rdfile="$rdfile32" 148*3446Smrj rdmnt="$rdmnt32" 149*3446Smrj fi 150*3446Smrj 1512334Ssetje newfs $lofidev < /dev/null 2> /dev/null 1522334Ssetje mkdir "$rdmnt" 1530Sstevel@tonic-gate mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1 1542334Ssetje mount -o nologging $lofidev "$rdmnt" 155*3446Smrj files= 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate # do the actual copy 1582334Ssetje cd "/$ALT_ROOT" 1592334Ssetje 160*3446Smrj for path in `find $filelist $NO_AMD64 -type f -print 2> /dev/null` 161*3446Smrj do 162*3446Smrj if [ "$which" = "both" ]; then 163*3446Smrj files="$files $path" 164*3446Smrj else 165*3446Smrj filetype=`file $path 2>/dev/null |\ 166*3446Smrj awk '/ELF/ { print \$3 }'` 167*3446Smrj if [ -z "$filetype" ] || [ "$filetype" = "$which" ] 168*3446Smrj then 169*3446Smrj files="$files $path" 170*3446Smrj fi 171*3446Smrj fi 172*3446Smrj done 173*3446Smrj if [ $compress = yes ]; then 174*3446Smrj ls $files | while read path 175*3446Smrj do 176*3446Smrj dir="${path%/*}" 177*3446Smrj mkdir -p "$rdmnt/$dir" 178*3446Smrj /usr/bin/gzip -c "$path" > "$rdmnt/$path" 179*3446Smrj done 180*3446Smrj else 181*3446Smrj ls $files | cpio -pdum "$rdmnt" 2> /dev/null 182*3446Smrj fi 1832334Ssetje umount "$rdmnt" 1842334Ssetje rmdir "$rdmnt" 1852334Ssetje 186*3446Smrj # 1872334Ssetje # Check if gzip exists in /usr/bin, so we only try to run gzip 1882334Ssetje # on systems that have gzip. Then run gzip out of the patch to 1892334Ssetje # pick it up from bfubin or something like that if needed. 1902334Ssetje # 191*3446Smrj # If compress is set, the individual files in the archive are 192*3446Smrj # compressed, and the final compression will accomplish very 193*3446Smrj # little. To save time, we skip the gzip in this case. 194*3446Smrj # 195*3446Smrj if [ $compress = no ] && [ -x /usr/bin/gzip ] ; then 196*3446Smrj gzip -c "$rdfile" > "${archive}-new" 1972334Ssetje else 198*3446Smrj cat "$rdfile" > "${archive}-new" 1992334Ssetje fi 2000Sstevel@tonic-gate} 2010Sstevel@tonic-gate 202*3446Smrj# 203*3446Smrj# The first argument can be: 204*3446Smrj# 205*3446Smrj# "both" - create an archive with both 32-bit and 64-bit binaries 206*3446Smrj# "32-bit" - create an archive with only 32-bit binaries 207*3446Smrj# "64-bit" - create an archive with only 64-bit binaries 208*3446Smrj# 2090Sstevel@tonic-gatefunction create_isofs 2100Sstevel@tonic-gate{ 211*3446Smrj which=$1 212*3446Smrj archive=$2 213*3446Smrj 2140Sstevel@tonic-gate # should we exclude amd64 binaries? 215*3446Smrj if [ "$which" = "32-bit" ]; then 216*3446Smrj NO_AMD64="-type d -name amd64 -prune -o" 217*3446Smrj rdmnt="$rdmnt32" 218*3446Smrj errlog="$errlog32" 219*3446Smrj elif [ "$which" = "64-bit" ]; then 220*3446Smrj NO_AMD64="" 221*3446Smrj rdmnt="$rdmnt64" 222*3446Smrj errlog="$errlog64" 223*3446Smrj else 224*3446Smrj NO_AMD64="" 225*3446Smrj rdmnt="$rdmnt32" 226*3446Smrj errlog="$errlog32" 227*3446Smrj fi 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate # create image directory seed with graft points 2302334Ssetje mkdir "$rdmnt" 2310Sstevel@tonic-gate files= 232*3446Smrj isocmd="mkisofs -quiet -graft-points -dlrDJN -relaxed-filenames" 233*3446Smrj 234*3446Smrj cd "/$ALT_ROOT" 235*3446Smrj for path in `find $filelist $NO_AMD64 -type f -print 2> /dev/null` 2360Sstevel@tonic-gate do 237*3446Smrj if [ "$which" = "both" ]; then 2380Sstevel@tonic-gate files="$files $path" 239*3446Smrj else 240*3446Smrj filetype=`file $path 2>/dev/null |\ 241*3446Smrj awk '/ELF/ { print \$3 }'` 242*3446Smrj if [ -z "$filetype" ] || [ "$filetype" = "$which" ] 243*3446Smrj then 244*3446Smrj files="$files $path" 245*3446Smrj fi 2460Sstevel@tonic-gate fi 2470Sstevel@tonic-gate done 248*3446Smrj if [ $compress = yes ]; then 249*3446Smrj ls $files | while read path 250*3446Smrj do 251*3446Smrj dir="${path%/*}" 252*3446Smrj mkdir -p "$rdmnt/$dir" 253*3446Smrj /usr/bin/gzip -c "$path" > "$rdmnt/$path" 254*3446Smrj done 255*3446Smrj else 256*3446Smrj ls $files | cpio -pdum "$rdmnt" 2> /dev/null 257*3446Smrj fi 2582334Ssetje isocmd="$isocmd \"$rdmnt\"" 2592334Ssetje rm -f "$errlog" 2602334Ssetje 261*3446Smrj # 2622334Ssetje # Check if gzip exists in /usr/bin, so we only try to run gzip 2632334Ssetje # on systems that have gzip. Then run gzip out of the patch to 2642334Ssetje # pick it up from bfubin or something like that if needed. 2652334Ssetje # 266*3446Smrj # If compress is set, the individual files in the archive are 267*3446Smrj # compressed, and the final compression will accomplish very 268*3446Smrj # little. To save time, we skip the gzip in this case. 269*3446Smrj # 270*3446Smrj if [ $compress = no ] && [ -x /usr/bin/gzip ] ; then 2712334Ssetje ksh -c "$isocmd" 2> "$errlog" | \ 272*3446Smrj gzip > "${archive}-new" 2732334Ssetje else 274*3446Smrj ksh -c "$isocmd" 2> "$errlog" > "${archive}-new" 2752334Ssetje fi 2762334Ssetje 2772334Ssetje if [ -s "$errlog" ]; then 2782334Ssetje grep Error: "$errlog" >/dev/null 2>&1 279174Sjg if [ $? -eq 0 ]; then 2802334Ssetje grep Error: "$errlog" 281*3446Smrj rm -f "${archive}-new" 282174Sjg fi 283174Sjg fi 2842334Ssetje rm -f "$errlog" 2850Sstevel@tonic-gate} 2860Sstevel@tonic-gate 287*3446Smrjfunction create_archive 288*3446Smrj{ 289*3446Smrj which=$1 290*3446Smrj archive=$2 291*3446Smrj lofidev=$3 292*3446Smrj 293*3446Smrj echo "updating $archive...this may take a minute" 294*3446Smrj 295*3446Smrj if [ "$format" = "ufs" ]; then 296*3446Smrj create_ufs "$which" "$archive" "$lofidev" 297*3446Smrj else 298*3446Smrj create_isofs "$which" "$archive" 299*3446Smrj fi 300*3446Smrj 301*3446Smrj # sanity check the archive before moving it into place 302*3446Smrj # 303*3446Smrj ARCHIVE_SIZE=`du -k "${archive}-new" | cut -f 1` 304*3446Smrj if [ $compress = yes ] 305*3446Smrj then 306*3446Smrj # 307*3446Smrj # 'file' will report "English text" for uncompressed 308*3446Smrj # boot_archives. Checking for that doesn't seem stable, 309*3446Smrj # so we just check that the file exists. 310*3446Smrj # 311*3446Smrj ls "${archive}-new" >/dev/null 2>&1 312*3446Smrj else 313*3446Smrj # 314*3446Smrj # the file type check also establishes that the 315*3446Smrj # file exists at all 316*3446Smrj # 317*3446Smrj file "${archive}-new" | grep gzip > /dev/null 318*3446Smrj fi 319*3446Smrj 320*3446Smrj if [ $? = 1 ] && [ -x /usr/bin/gzip ] || [ $ARCHIVE_SIZE -lt 5000 ] 321*3446Smrj then 322*3446Smrj # 323*3446Smrj # Two of these functions may be run in parallel. We 324*3446Smrj # need to allow the other to clean up, so we can't 325*3446Smrj # exit immediately. Instead, we set a flag. 326*3446Smrj # 327*3446Smrj echo "update of $archive failed" 328*3446Smrj ERROR=1 329*3446Smrj else 330*3446Smrj lockfs -f "/$ALT_ROOT" 2>/dev/null 331*3446Smrj mv "${archive}-new" "$archive" 332*3446Smrj lockfs -f "/$ALT_ROOT" 2>/dev/null 333*3446Smrj fi 334*3446Smrj 335*3446Smrj} 336*3446Smrj 3370Sstevel@tonic-gate# 3380Sstevel@tonic-gate# get filelist 3390Sstevel@tonic-gate# 3402851Sjongkisfiles=$(ls "$ALT_ROOT/boot/solaris/filelist.ramdisk" \ 3412851Sjongkis "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" 2>/dev/null) 3422851Sjongkisif [[ -z "$files" ]] 3432851Sjongkisthen 3442851Sjongkis print -u2 "Can't find filelist.ramdisk" 3452851Sjongkis exit 1 3460Sstevel@tonic-gatefi 3472851Sjongkisfilelist=$(sort -u $files) 3480Sstevel@tonic-gate 3492334Ssetjescratch=tmp 3502334Ssetje 3512334Ssetjeif [ $format = ufs ] ; then 3522334Ssetje # calculate image size 3532334Ssetje getsize 3542334Ssetje 355*3446Smrj # We do two mkfile's of total_size, so double the space 356*3446Smrj (( tmp_needed = total_size * 2 )) 357*3446Smrj 3582334Ssetje # check to see if there is sufficient space in tmpfs 3592334Ssetje # 3602334Ssetje tmp_free=`df -b /tmp | tail -1 | awk '{ printf ($2) }'` 3612334Ssetje (( tmp_free = tmp_free / 2 )) 3622334Ssetje 363*3446Smrj if [ $tmp_needed -gt $tmp_free ] ; then 3642334Ssetje # assumes we have enough scratch space on $ALT_ROOT 3652334Ssetje scratch="$ALT_ROOT" 3662334Ssetje fi 3672334Ssetjefi 3682334Ssetje 3692334Ssetjerddir="/$scratch/create_ramdisk.$$.tmp" 370*3446Smrjrdfile32="$rddir/rd.file.32" 371*3446Smrjrdfile64="$rddir/rd.file.64" 372*3446Smrjrdmnt32="$rddir/rd.mount.32" 373*3446Smrjrdmnt64="$rddir/rd.mount.64" 374*3446Smrjerrlog32="$rddir/rd.errlog.32" 375*3446Smrjerrlog64="$rddir/rd.errlog.64" 376*3446Smrjlofidev32="" 377*3446Smrjlofidev64="" 3782334Ssetje 3792334Ssetje# make directory for temp files safely 3802334Ssetjerm -rf "$rddir" 3812334Ssetjemkdir "$rddir" 3822334Ssetje 3832334Ssetje# Clean up upon exit. 3842334Ssetjetrap 'cleanup' EXIT 3852334Ssetje 386*3446Smrjif [ $SPLIT = yes ]; then 387*3446Smrj # 388*3446Smrj # We can't run lofiadm commands in parallel, so we have to do 389*3446Smrj # them here. 390*3446Smrj # 391*3446Smrj if [ "$format" = "ufs" ]; then 392*3446Smrj mkfile ${total_size}k "$rdfile32" 393*3446Smrj lofidev32=`lofiadm -a "$rdfile32"` 394*3446Smrj mkfile ${total_size}k "$rdfile64" 395*3446Smrj lofidev64=`lofiadm -a "$rdfile64"` 396*3446Smrj fi 397*3446Smrj create_archive "32-bit" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 & 398*3446Smrj create_archive "64-bit" "$ALT_ROOT/$BOOT_ARCHIVE_64" $lofidev64 399*3446Smrj wait 400*3446Smrj if [ "$format" = "ufs" ]; then 401*3446Smrj lofiadm -d "$rdfile32" 402*3446Smrj lofiadm -d "$rdfile64" 403*3446Smrj fi 4040Sstevel@tonic-gateelse 405*3446Smrj if [ "$format" = "ufs" ]; then 406*3446Smrj mkfile ${total_size}k "$rdfile32" 407*3446Smrj lofidev32=`lofiadm -a "$rdfile32"` 408*3446Smrj fi 409*3446Smrj create_archive "both" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 410*3446Smrj [ "$format" = "ufs" ] && lofiadm -d "$rdfile32" 4110Sstevel@tonic-gatefi 412*3446Smrjif [ $ERROR = 1 ]; then 413*3446Smrj cleanup 414174Sjg exit 1 415174Sjgfi 416174Sjg 4170Sstevel@tonic-gate# 4180Sstevel@tonic-gate# For the diskless case, hardlink archive to /boot to make it 4190Sstevel@tonic-gate# visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>. 420*3446Smrj# NOTE: this script must work on both client and server. 4210Sstevel@tonic-gate# 4222334Ssetjegrep "[ ]/[ ]*nfs[ ]" "$ALT_ROOT/etc/vfstab" > /dev/null 4230Sstevel@tonic-gateif [ $? = 0 ]; then 424*3446Smrj rm -f "$ALT_ROOT/boot/boot_archive" "$ALT_ROOT/boot/amd64/boot_archive" 4252334Ssetje ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/boot_archive" 426*3446Smrj ln "$ALT_ROOT/$BOOT_ARCHIVE_64" "$ALT_ROOT/boot/amd64/boot_archive" 4270Sstevel@tonic-gatefi 4282334Ssetjerm -rf "$rddir" 429