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
233446Smrj# 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=
303446Smrjcompress=yes
313446SmrjSPLIT=unknown
323446SmrjERROR=0
330Sstevel@tonic-gate
340Sstevel@tonic-gateBOOT_ARCHIVE=platform/i86pc/boot_archive
353446SmrjBOOT_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#
423446Smrjwhile [ "$1" != "" ]
430Sstevel@tonic-gatedo
443446Smrj        case $1 in
453446Smrj        -R)	shift
463446Smrj		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		;;
513467Srscott	-n|--nocompress) compress=no
523467Srscott		;;
533446Smrj        *)      echo Usage: ${0##*/}: [-R \<root\>] [--nocompress]
543467Srscott		exit
553467Srscott		;;
560Sstevel@tonic-gate        esac
573446Smrj	shift
580Sstevel@tonic-gatedone
590Sstevel@tonic-gate
600Sstevel@tonic-gateif [ -x /usr/bin/mkisofs -o -x /tmp/bfubin/mkisofs ] ; then
610Sstevel@tonic-gate	format=isofs
620Sstevel@tonic-gatefi
630Sstevel@tonic-gate
64621Svikram#
65621Svikram# mkisofs on s8 doesn't support functionality used by GRUB boot.
66621Svikram# Use ufs format for boot archive instead.
67621Svikram#
68621Svikramrelease=`uname -r`
69621Svikramif [ "$release" = "5.8" ]; then
703446Smrj	format=ufs
71621Svikramfi
72621Svikram
730Sstevel@tonic-gateshift `expr $OPTIND - 1`
740Sstevel@tonic-gate
750Sstevel@tonic-gateif [ $# -eq 1 ]; then
762334Ssetje	ALT_ROOT="$1"
772334Ssetje	echo "Creating ram disk for $ALT_ROOT"
780Sstevel@tonic-gatefi
790Sstevel@tonic-gate
803446Smrjrundir=`dirname $0`
81*3555Srscottif [ ! -x "$rundir"/symdef ]; then
823446Smrj	# Shouldn't happen
833446Smrj	echo "Warning: $rundir/symdef not present."
843446Smrj	echo "Creating single archive at $ALT_ROOT/platform/i86pc/boot_archive"
853446Smrj	SPLIT=no
863446Smrj	compress=no
87*3555Srscottelif "$rundir"/symdef "$ALT_ROOT"/platform/i86pc/kernel/unix \
883446Smrj    dboot_image 2>/dev/null; then
893446Smrj	SPLIT=yes
903446Smrjelse
913446Smrj	SPLIT=no
923446Smrj	compress=no
933446Smrjfi
943446Smrj
953446Smrj[ -x /usr/bin/gzip ] || compress=no
963446Smrj
972334Ssetjefunction cleanup
982334Ssetje{
993446Smrj	umount -f "$rdmnt32" 2>/dev/null
1003446Smrj	umount -f "$rdmnt64" 2>/dev/null
1013446Smrj	lofiadm -d "$rdfile32" 2>/dev/null
1023446Smrj	lofiadm -d "$rdfile64" 2>/dev/null
1032334Ssetje	rm -fr "$rddir" 2> /dev/null
1040Sstevel@tonic-gate}
1050Sstevel@tonic-gate
1062334Ssetjefunction getsize
1072334Ssetje{
1082511Sjongkis	# Estimate image size and add %10 overhead for ufs stuff.
1092511Sjongkis	# Note, we can't use du here in case we're on a filesystem, e.g. zfs,
1102511Sjongkis	# in which the disk usage is less than the sum of the file sizes.
1112511Sjongkis	# The nawk code
1122511Sjongkis	#
1132511Sjongkis	#	{t += ($7 % 1024) ? (int($7 / 1024) + 1) * 1024 : $7}
1142511Sjongkis	#
1152511Sjongkis	# below rounds up the size of a file/directory, in bytes, to the
1162511Sjongkis	# next multiple of 1024.  This mimics the behavior of ufs especially
1172511Sjongkis	# with directories.  This results in a total size that's slightly
1182511Sjongkis	# bigger than if du was called on a ufs directory.
1192851Sjongkis	total_size=$(cd "/$ALT_ROOT"
1203446Smrj		find $filelist -ls 2>/dev/null | nawk '
1212851Sjongkis			{t += ($7 % 1024) ? (int($7 / 1024) + 1) * 1024 : $7}
1222851Sjongkis			END {print int(t * 1.10 / 1024)}')
1230Sstevel@tonic-gate}
1240Sstevel@tonic-gate
1253446Smrj#
126*3555Srscott# Copies all desired files to a target directory.
127*3555Srscott#
128*3555Srscott# This function depends on several variables that must be set before calling:
129*3555Srscott# $ALT_ROOT - the target directory
130*3555Srscott# $filelist - the list of files and directories to search
131*3555Srscott# $NO_AMD64 - the find(1) expression to exclude files, if desired
132*3555Srscott# $which - One of "both", "32-bit", or "64-bit"
133*3555Srscott# $compress - whether or not the files in the archives should be compressed
134*3555Srscott# $rdmnt - the target directory
135*3555Srscott#
136*3555Srscottfunction find_and_copy
137*3555Srscott{
138*3555Srscott	cd "/$ALT_ROOT"
139*3555Srscott
140*3555Srscott	#
141*3555Srscott	# If compress is set, the files are gzip'd and put in the correct
142*3555Srscott	# location in the loop.  Nothing is printed, so the pipe and cpio
143*3555Srscott	# at the end is a nop.
144*3555Srscott	#
145*3555Srscott	# If compress is not set, the file names are printed, which causes
146*3555Srscott	# the cpio at the end to do the copy.
147*3555Srscott	#
148*3555Srscott	find $filelist $NO_AMD64 -type f -print 2>/dev/null | while read path
149*3555Srscott	do
150*3555Srscott		if [ "$which" = "both" ]; then
151*3555Srscott			if [ $compress = yes ]; then
152*3555Srscott				dir="${path%/*}"
153*3555Srscott				mkdir -p "$rdmnt/$dir"
154*3555Srscott				/usr/bin/gzip -c "$path" > "$rdmnt/$path"
155*3555Srscott			else
156*3555Srscott				print "$path"
157*3555Srscott			fi
158*3555Srscott		else
159*3555Srscott			filetype=`file $path 2>/dev/null |\
160*3555Srscott			    awk '/ELF/ { print \$3 }'`
161*3555Srscott			if [ -z "$filetype" ] || [ "$filetype" = "$which" ]
162*3555Srscott			then
163*3555Srscott				if [ $compress = yes ]; then
164*3555Srscott					dir="${path%/*}"
165*3555Srscott					mkdir -p "$rdmnt/$dir"
166*3555Srscott					/usr/bin/gzip -c "$path" > \
167*3555Srscott					    "$rdmnt/$path"
168*3555Srscott				else
169*3555Srscott					print "$path"
170*3555Srscott				fi
171*3555Srscott			fi
172*3555Srscott		fi
173*3555Srscott	done | cpio -pdum "$rdmnt" 2>/dev/null
174*3555Srscott}
175*3555Srscott
176*3555Srscott#
1773446Smrj# The first argument can be:
1783446Smrj#
1793446Smrj# "both" - create an archive with both 32-bit and 64-bit binaries
1803446Smrj# "32-bit" - create an archive with only 32-bit binaries
1813446Smrj# "64-bit" - create an archive with only 64-bit binaries
1823446Smrj#
1830Sstevel@tonic-gatefunction create_ufs
1840Sstevel@tonic-gate{
1853446Smrj	which=$1
1863446Smrj	archive=$2
1873446Smrj	lofidev=$3
1880Sstevel@tonic-gate
1893446Smrj	# should we exclude amd64 binaries?
1903446Smrj	if [ "$which" = "32-bit" ]; then
1913446Smrj		NO_AMD64="-type d -name amd64 -prune -o"
1923446Smrj		rdfile="$rdfile32"
1933446Smrj		rdmnt="$rdmnt32"
1943446Smrj	elif [ "$which" = "64-bit" ]; then
1953446Smrj		NO_AMD64=""
1963446Smrj		rdfile="$rdfile64"
1973446Smrj		rdmnt="$rdmnt64"
1983446Smrj	else
1993446Smrj		NO_AMD64=""
2003446Smrj		rdfile="$rdfile32"
2013446Smrj		rdmnt="$rdmnt32"
2023446Smrj	fi
2033446Smrj
2042334Ssetje	newfs $lofidev < /dev/null 2> /dev/null
2052334Ssetje	mkdir "$rdmnt"
2060Sstevel@tonic-gate	mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1
2072334Ssetje	mount -o nologging $lofidev "$rdmnt"
2083446Smrj	files=
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate	# do the actual copy
211*3555Srscott	find_and_copy
2122334Ssetje	umount "$rdmnt"
2132334Ssetje	rmdir "$rdmnt"
2142334Ssetje
2153446Smrj	#
2162334Ssetje	# Check if gzip exists in /usr/bin, so we only try to run gzip
2172334Ssetje	# on systems that have gzip. Then run gzip out of the patch to
2182334Ssetje	# pick it up from bfubin or something like that if needed.
2192334Ssetje	#
2203446Smrj	# If compress is set, the individual files in the archive are
2213446Smrj	# compressed, and the final compression will accomplish very
2223446Smrj	# little.  To save time, we skip the gzip in this case.
2233446Smrj	#
2243446Smrj	if [ $compress = no ] && [ -x /usr/bin/gzip ] ; then
2253446Smrj		gzip -c "$rdfile" > "${archive}-new"
2262334Ssetje	else
2273446Smrj		cat "$rdfile" > "${archive}-new"
2282334Ssetje	fi
2290Sstevel@tonic-gate}
2300Sstevel@tonic-gate
2313446Smrj#
2323446Smrj# The first argument can be:
2333446Smrj#
2343446Smrj# "both" - create an archive with both 32-bit and 64-bit binaries
2353446Smrj# "32-bit" - create an archive with only 32-bit binaries
2363446Smrj# "64-bit" - create an archive with only 64-bit binaries
2373446Smrj#
2380Sstevel@tonic-gatefunction create_isofs
2390Sstevel@tonic-gate{
2403446Smrj	which=$1
2413446Smrj	archive=$2
2423446Smrj
2430Sstevel@tonic-gate	# should we exclude amd64 binaries?
2443446Smrj	if [ "$which" = "32-bit" ]; then
2453446Smrj		NO_AMD64="-type d -name amd64 -prune -o"
2463446Smrj		rdmnt="$rdmnt32"
2473446Smrj		errlog="$errlog32"
2483446Smrj	elif [ "$which" = "64-bit" ]; then
2493446Smrj		NO_AMD64=""
2503446Smrj		rdmnt="$rdmnt64"
2513446Smrj		errlog="$errlog64"
2523446Smrj	else
2533446Smrj		NO_AMD64=""
2543446Smrj		rdmnt="$rdmnt32"
2553446Smrj		errlog="$errlog32"
2563446Smrj	fi
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate	# create image directory seed with graft points
2592334Ssetje	mkdir "$rdmnt"
2600Sstevel@tonic-gate	files=
2613446Smrj	isocmd="mkisofs -quiet -graft-points -dlrDJN -relaxed-filenames"
2623446Smrj
263*3555Srscott	find_and_copy
2642334Ssetje	isocmd="$isocmd \"$rdmnt\""
2652334Ssetje	rm -f "$errlog"
2662334Ssetje
2673446Smrj	#
2682334Ssetje	# Check if gzip exists in /usr/bin, so we only try to run gzip
2692334Ssetje	# on systems that have gzip. Then run gzip out of the patch to
2702334Ssetje	# pick it up from bfubin or something like that if needed.
2712334Ssetje	#
2723446Smrj	# If compress is set, the individual files in the archive are
2733446Smrj	# compressed, and the final compression will accomplish very
2743446Smrj	# little.  To save time, we skip the gzip in this case.
2753446Smrj	#
2763446Smrj	if [ $compress = no ] && [ -x /usr/bin/gzip ] ; then
2772334Ssetje		ksh -c "$isocmd" 2> "$errlog" | \
2783446Smrj		    gzip > "${archive}-new"
2792334Ssetje	else
2803446Smrj		ksh -c "$isocmd" 2> "$errlog" > "${archive}-new"
2812334Ssetje	fi
2822334Ssetje
2832334Ssetje	if [ -s "$errlog" ]; then
2842334Ssetje		grep Error: "$errlog" >/dev/null 2>&1
285174Sjg		if [ $? -eq 0 ]; then
2862334Ssetje			grep Error: "$errlog"
2873446Smrj			rm -f "${archive}-new"
288174Sjg		fi
289174Sjg	fi
2902334Ssetje	rm -f "$errlog"
2910Sstevel@tonic-gate}
2920Sstevel@tonic-gate
2933446Smrjfunction create_archive
2943446Smrj{
2953446Smrj	which=$1
2963446Smrj	archive=$2
2973446Smrj	lofidev=$3
2983446Smrj
2993446Smrj	echo "updating $archive...this may take a minute"
3003446Smrj
3013446Smrj	if [ "$format" = "ufs" ]; then
3023446Smrj		create_ufs "$which" "$archive" "$lofidev"
3033446Smrj	else
3043446Smrj		create_isofs "$which" "$archive"
3053446Smrj	fi
3063446Smrj
3073446Smrj	# sanity check the archive before moving it into place
3083446Smrj	#
309*3555Srscott	ARCHIVE_SIZE=`ls -l "${archive}-new" | nawk '{ print $5 }'`
3103446Smrj	if [ $compress = yes ]
3113446Smrj	then
3123446Smrj		#
3133446Smrj		# 'file' will report "English text" for uncompressed
3143446Smrj		# boot_archives.  Checking for that doesn't seem stable,
3153446Smrj		# so we just check that the file exists.
3163446Smrj		#
3173446Smrj		ls "${archive}-new" >/dev/null 2>&1
3183446Smrj	else
3193446Smrj		#
3203446Smrj		# the file type check also establishes that the
3213446Smrj		# file exists at all
3223446Smrj		#
3233446Smrj		file "${archive}-new" | grep gzip > /dev/null
3243446Smrj	fi
3253446Smrj
3263446Smrj	if [ $? = 1 ] && [ -x /usr/bin/gzip ] || [ $ARCHIVE_SIZE -lt 5000 ]
3273446Smrj	then
3283446Smrj		#
3293446Smrj		# Two of these functions may be run in parallel.  We
3303446Smrj		# need to allow the other to clean up, so we can't
3313446Smrj		# exit immediately.  Instead, we set a flag.
3323446Smrj		#
3333446Smrj		echo "update of $archive failed"
3343446Smrj		ERROR=1
3353446Smrj	else
3363446Smrj		lockfs -f "/$ALT_ROOT" 2>/dev/null
3373446Smrj		mv "${archive}-new" "$archive"
3383446Smrj		lockfs -f "/$ALT_ROOT" 2>/dev/null
3393446Smrj	fi
3403446Smrj
3413446Smrj}
3423446Smrj
3430Sstevel@tonic-gate#
3440Sstevel@tonic-gate# get filelist
3450Sstevel@tonic-gate#
346*3555Srscottif [ ! -f "$ALT_ROOT/boot/solaris/filelist.ramdisk" ] &&
347*3555Srscott    [ ! -f "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" ]
3482851Sjongkisthen
3492851Sjongkis	print -u2 "Can't find filelist.ramdisk"
3502851Sjongkis	exit 1
3510Sstevel@tonic-gatefi
352*3555Srscottfilelist=$(cat "$ALT_ROOT/boot/solaris/filelist.ramdisk" \
353*3555Srscott    "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" 2>/dev/null | sort -u)
3540Sstevel@tonic-gate
3552334Ssetjescratch=tmp
3562334Ssetje
3572334Ssetjeif [ $format = ufs ] ; then
3582334Ssetje	# calculate image size
3592334Ssetje	getsize
3602334Ssetje
3613446Smrj	# We do two mkfile's of total_size, so double the space
3623446Smrj	(( tmp_needed = total_size * 2 ))
3633446Smrj
3642334Ssetje	# check to see if there is sufficient space in tmpfs
3652334Ssetje	#
3662334Ssetje	tmp_free=`df -b /tmp | tail -1 | awk '{ printf ($2) }'`
3672334Ssetje	(( tmp_free = tmp_free / 2 ))
3682334Ssetje
3693446Smrj	if [ $tmp_needed -gt $tmp_free  ] ; then
3702334Ssetje		# assumes we have enough scratch space on $ALT_ROOT
3712334Ssetje        	scratch="$ALT_ROOT"
3722334Ssetje	fi
3732334Ssetjefi
3742334Ssetje
3752334Ssetjerddir="/$scratch/create_ramdisk.$$.tmp"
3763446Smrjrdfile32="$rddir/rd.file.32"
3773446Smrjrdfile64="$rddir/rd.file.64"
3783446Smrjrdmnt32="$rddir/rd.mount.32"
3793446Smrjrdmnt64="$rddir/rd.mount.64"
3803446Smrjerrlog32="$rddir/rd.errlog.32"
3813446Smrjerrlog64="$rddir/rd.errlog.64"
3823446Smrjlofidev32=""
3833446Smrjlofidev64=""
3842334Ssetje
3852334Ssetje# make directory for temp files safely
3862334Ssetjerm -rf "$rddir"
3872334Ssetjemkdir "$rddir"
3882334Ssetje
3892334Ssetje# Clean up upon exit.
3902334Ssetjetrap 'cleanup' EXIT
3912334Ssetje
3923446Smrjif [ $SPLIT = yes ]; then
3933446Smrj	#
3943446Smrj	# We can't run lofiadm commands in parallel, so we have to do
3953446Smrj	# them here.
3963446Smrj	#
3973446Smrj	if [ "$format" = "ufs" ]; then
3983446Smrj		mkfile ${total_size}k "$rdfile32"
3993446Smrj		lofidev32=`lofiadm -a "$rdfile32"`
4003446Smrj		mkfile ${total_size}k "$rdfile64"
4013446Smrj		lofidev64=`lofiadm -a "$rdfile64"`
4023446Smrj	fi
4033446Smrj	create_archive "32-bit" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 &
4043446Smrj	create_archive "64-bit" "$ALT_ROOT/$BOOT_ARCHIVE_64" $lofidev64
4053446Smrj	wait
4063446Smrj	if [ "$format" = "ufs" ]; then
4073446Smrj		lofiadm -d "$rdfile32"
4083446Smrj		lofiadm -d "$rdfile64"
4093446Smrj	fi
4100Sstevel@tonic-gateelse
4113446Smrj	if [ "$format" = "ufs" ]; then
4123446Smrj		mkfile ${total_size}k "$rdfile32"
4133446Smrj		lofidev32=`lofiadm -a "$rdfile32"`
4143446Smrj	fi
4153446Smrj	create_archive "both" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32
4163446Smrj	[ "$format" = "ufs" ] && lofiadm -d "$rdfile32"
4170Sstevel@tonic-gatefi
4183446Smrjif [ $ERROR = 1 ]; then
4193446Smrj	cleanup
420174Sjg	exit 1
421174Sjgfi
422174Sjg
4230Sstevel@tonic-gate#
4240Sstevel@tonic-gate# For the diskless case, hardlink archive to /boot to make it
4250Sstevel@tonic-gate# visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>.
4263446Smrj# NOTE: this script must work on both client and server.
4270Sstevel@tonic-gate#
4282334Ssetjegrep "[	 ]/[	 ]*nfs[	 ]" "$ALT_ROOT/etc/vfstab" > /dev/null
4290Sstevel@tonic-gateif [ $? = 0 ]; then
4303446Smrj	rm -f "$ALT_ROOT/boot/boot_archive" "$ALT_ROOT/boot/amd64/boot_archive"
4312334Ssetje	ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/boot_archive"
4323446Smrj	ln "$ALT_ROOT/$BOOT_ARCHIVE_64" "$ALT_ROOT/boot/amd64/boot_archive"
4330Sstevel@tonic-gatefi
4342334Ssetjerm -rf "$rddir"
435