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		;;
51*3467Srscott	-n|--nocompress) compress=no
52*3467Srscott		;;
533446Smrj        *)      echo Usage: ${0##*/}: [-R \<root\>] [--nocompress]
54*3467Srscott		exit
55*3467Srscott		;;
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`
813446Smrjif [ ! -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
873446Smrjelif $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#
1263446Smrj# The first argument can be:
1273446Smrj#
1283446Smrj# "both" - create an archive with both 32-bit and 64-bit binaries
1293446Smrj# "32-bit" - create an archive with only 32-bit binaries
1303446Smrj# "64-bit" - create an archive with only 64-bit binaries
1313446Smrj#
1320Sstevel@tonic-gatefunction create_ufs
1330Sstevel@tonic-gate{
1343446Smrj	which=$1
1353446Smrj	archive=$2
1363446Smrj	lofidev=$3
1370Sstevel@tonic-gate
1383446Smrj	# should we exclude amd64 binaries?
1393446Smrj	if [ "$which" = "32-bit" ]; then
1403446Smrj		NO_AMD64="-type d -name amd64 -prune -o"
1413446Smrj		rdfile="$rdfile32"
1423446Smrj		rdmnt="$rdmnt32"
1433446Smrj	elif [ "$which" = "64-bit" ]; then
1443446Smrj		NO_AMD64=""
1453446Smrj		rdfile="$rdfile64"
1463446Smrj		rdmnt="$rdmnt64"
1473446Smrj	else
1483446Smrj		NO_AMD64=""
1493446Smrj		rdfile="$rdfile32"
1503446Smrj		rdmnt="$rdmnt32"
1513446Smrj	fi
1523446Smrj
1532334Ssetje	newfs $lofidev < /dev/null 2> /dev/null
1542334Ssetje	mkdir "$rdmnt"
1550Sstevel@tonic-gate	mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1
1562334Ssetje	mount -o nologging $lofidev "$rdmnt"
1573446Smrj	files=
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate	# do the actual copy
1602334Ssetje	cd "/$ALT_ROOT"
1612334Ssetje
1623446Smrj	for path in `find $filelist $NO_AMD64 -type f -print 2> /dev/null`
1633446Smrj	do
1643446Smrj		if [ "$which" = "both" ]; then
1653446Smrj			files="$files $path"
1663446Smrj		else
1673446Smrj			filetype=`file $path 2>/dev/null |\
1683446Smrj			    awk '/ELF/ { print \$3 }'`
1693446Smrj			if [ -z "$filetype" ] || [ "$filetype" = "$which" ]
1703446Smrj			then
1713446Smrj				files="$files $path"
1723446Smrj			fi
1733446Smrj		fi
1743446Smrj	done
1753446Smrj	if [ $compress = yes ]; then
1763446Smrj		ls $files | while read path
1773446Smrj		do
1783446Smrj			dir="${path%/*}"
1793446Smrj			mkdir -p "$rdmnt/$dir"
1803446Smrj			/usr/bin/gzip -c "$path" > "$rdmnt/$path"
1813446Smrj		done
1823446Smrj	else
1833446Smrj		ls $files | cpio -pdum "$rdmnt" 2> /dev/null
1843446Smrj	fi
1852334Ssetje	umount "$rdmnt"
1862334Ssetje	rmdir "$rdmnt"
1872334Ssetje
1883446Smrj	#
1892334Ssetje	# Check if gzip exists in /usr/bin, so we only try to run gzip
1902334Ssetje	# on systems that have gzip. Then run gzip out of the patch to
1912334Ssetje	# pick it up from bfubin or something like that if needed.
1922334Ssetje	#
1933446Smrj	# If compress is set, the individual files in the archive are
1943446Smrj	# compressed, and the final compression will accomplish very
1953446Smrj	# little.  To save time, we skip the gzip in this case.
1963446Smrj	#
1973446Smrj	if [ $compress = no ] && [ -x /usr/bin/gzip ] ; then
1983446Smrj		gzip -c "$rdfile" > "${archive}-new"
1992334Ssetje	else
2003446Smrj		cat "$rdfile" > "${archive}-new"
2012334Ssetje	fi
2020Sstevel@tonic-gate}
2030Sstevel@tonic-gate
2043446Smrj#
2053446Smrj# The first argument can be:
2063446Smrj#
2073446Smrj# "both" - create an archive with both 32-bit and 64-bit binaries
2083446Smrj# "32-bit" - create an archive with only 32-bit binaries
2093446Smrj# "64-bit" - create an archive with only 64-bit binaries
2103446Smrj#
2110Sstevel@tonic-gatefunction create_isofs
2120Sstevel@tonic-gate{
2133446Smrj	which=$1
2143446Smrj	archive=$2
2153446Smrj
2160Sstevel@tonic-gate	# should we exclude amd64 binaries?
2173446Smrj	if [ "$which" = "32-bit" ]; then
2183446Smrj		NO_AMD64="-type d -name amd64 -prune -o"
2193446Smrj		rdmnt="$rdmnt32"
2203446Smrj		errlog="$errlog32"
2213446Smrj	elif [ "$which" = "64-bit" ]; then
2223446Smrj		NO_AMD64=""
2233446Smrj		rdmnt="$rdmnt64"
2243446Smrj		errlog="$errlog64"
2253446Smrj	else
2263446Smrj		NO_AMD64=""
2273446Smrj		rdmnt="$rdmnt32"
2283446Smrj		errlog="$errlog32"
2293446Smrj	fi
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate	# create image directory seed with graft points
2322334Ssetje	mkdir "$rdmnt"
2330Sstevel@tonic-gate	files=
2343446Smrj	isocmd="mkisofs -quiet -graft-points -dlrDJN -relaxed-filenames"
2353446Smrj
2363446Smrj	cd "/$ALT_ROOT"
2373446Smrj	for path in `find $filelist $NO_AMD64 -type f -print 2> /dev/null`
2380Sstevel@tonic-gate	do
2393446Smrj		if [ "$which" = "both" ]; then
2400Sstevel@tonic-gate			files="$files $path"
2413446Smrj		else
2423446Smrj			filetype=`file $path 2>/dev/null |\
2433446Smrj			    awk '/ELF/ { print \$3 }'`
2443446Smrj			if [ -z "$filetype" ] || [ "$filetype" = "$which" ]
2453446Smrj			then
2463446Smrj				files="$files $path"
2473446Smrj			fi
2480Sstevel@tonic-gate		fi
2490Sstevel@tonic-gate	done
2503446Smrj	if [ $compress = yes ]; then
2513446Smrj		ls $files | while read path
2523446Smrj		do
2533446Smrj			dir="${path%/*}"
2543446Smrj			mkdir -p "$rdmnt/$dir"
2553446Smrj			/usr/bin/gzip -c "$path" > "$rdmnt/$path"
2563446Smrj		done
2573446Smrj	else
2583446Smrj		ls $files | cpio -pdum "$rdmnt" 2> /dev/null
2593446Smrj	fi
2602334Ssetje	isocmd="$isocmd \"$rdmnt\""
2612334Ssetje	rm -f "$errlog"
2622334Ssetje
2633446Smrj	#
2642334Ssetje	# Check if gzip exists in /usr/bin, so we only try to run gzip
2652334Ssetje	# on systems that have gzip. Then run gzip out of the patch to
2662334Ssetje	# pick it up from bfubin or something like that if needed.
2672334Ssetje	#
2683446Smrj	# If compress is set, the individual files in the archive are
2693446Smrj	# compressed, and the final compression will accomplish very
2703446Smrj	# little.  To save time, we skip the gzip in this case.
2713446Smrj	#
2723446Smrj	if [ $compress = no ] && [ -x /usr/bin/gzip ] ; then
2732334Ssetje		ksh -c "$isocmd" 2> "$errlog" | \
2743446Smrj		    gzip > "${archive}-new"
2752334Ssetje	else
2763446Smrj		ksh -c "$isocmd" 2> "$errlog" > "${archive}-new"
2772334Ssetje	fi
2782334Ssetje
2792334Ssetje	if [ -s "$errlog" ]; then
2802334Ssetje		grep Error: "$errlog" >/dev/null 2>&1
281174Sjg		if [ $? -eq 0 ]; then
2822334Ssetje			grep Error: "$errlog"
2833446Smrj			rm -f "${archive}-new"
284174Sjg		fi
285174Sjg	fi
2862334Ssetje	rm -f "$errlog"
2870Sstevel@tonic-gate}
2880Sstevel@tonic-gate
2893446Smrjfunction create_archive
2903446Smrj{
2913446Smrj	which=$1
2923446Smrj	archive=$2
2933446Smrj	lofidev=$3
2943446Smrj
2953446Smrj	echo "updating $archive...this may take a minute"
2963446Smrj
2973446Smrj	if [ "$format" = "ufs" ]; then
2983446Smrj		create_ufs "$which" "$archive" "$lofidev"
2993446Smrj	else
3003446Smrj		create_isofs "$which" "$archive"
3013446Smrj	fi
3023446Smrj
3033446Smrj	# sanity check the archive before moving it into place
3043446Smrj	#
3053446Smrj	ARCHIVE_SIZE=`du -k "${archive}-new" | cut -f 1`
3063446Smrj	if [ $compress = yes ]
3073446Smrj	then
3083446Smrj		#
3093446Smrj		# 'file' will report "English text" for uncompressed
3103446Smrj		# boot_archives.  Checking for that doesn't seem stable,
3113446Smrj		# so we just check that the file exists.
3123446Smrj		#
3133446Smrj		ls "${archive}-new" >/dev/null 2>&1
3143446Smrj	else
3153446Smrj		#
3163446Smrj		# the file type check also establishes that the
3173446Smrj		# file exists at all
3183446Smrj		#
3193446Smrj		file "${archive}-new" | grep gzip > /dev/null
3203446Smrj	fi
3213446Smrj
3223446Smrj	if [ $? = 1 ] && [ -x /usr/bin/gzip ] || [ $ARCHIVE_SIZE -lt 5000 ]
3233446Smrj	then
3243446Smrj		#
3253446Smrj		# Two of these functions may be run in parallel.  We
3263446Smrj		# need to allow the other to clean up, so we can't
3273446Smrj		# exit immediately.  Instead, we set a flag.
3283446Smrj		#
3293446Smrj		echo "update of $archive failed"
3303446Smrj		ERROR=1
3313446Smrj	else
3323446Smrj		lockfs -f "/$ALT_ROOT" 2>/dev/null
3333446Smrj		mv "${archive}-new" "$archive"
3343446Smrj		lockfs -f "/$ALT_ROOT" 2>/dev/null
3353446Smrj	fi
3363446Smrj
3373446Smrj}
3383446Smrj
3390Sstevel@tonic-gate#
3400Sstevel@tonic-gate# get filelist
3410Sstevel@tonic-gate#
3422851Sjongkisfiles=$(ls "$ALT_ROOT/boot/solaris/filelist.ramdisk" \
3432851Sjongkis	"$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" 2>/dev/null)
3442851Sjongkisif [[ -z "$files" ]]
3452851Sjongkisthen
3462851Sjongkis	print -u2 "Can't find filelist.ramdisk"
3472851Sjongkis	exit 1
3480Sstevel@tonic-gatefi
3492851Sjongkisfilelist=$(sort -u $files)
3500Sstevel@tonic-gate
3512334Ssetjescratch=tmp
3522334Ssetje
3532334Ssetjeif [ $format = ufs ] ; then
3542334Ssetje	# calculate image size
3552334Ssetje	getsize
3562334Ssetje
3573446Smrj	# We do two mkfile's of total_size, so double the space
3583446Smrj	(( tmp_needed = total_size * 2 ))
3593446Smrj
3602334Ssetje	# check to see if there is sufficient space in tmpfs
3612334Ssetje	#
3622334Ssetje	tmp_free=`df -b /tmp | tail -1 | awk '{ printf ($2) }'`
3632334Ssetje	(( tmp_free = tmp_free / 2 ))
3642334Ssetje
3653446Smrj	if [ $tmp_needed -gt $tmp_free  ] ; then
3662334Ssetje		# assumes we have enough scratch space on $ALT_ROOT
3672334Ssetje        	scratch="$ALT_ROOT"
3682334Ssetje	fi
3692334Ssetjefi
3702334Ssetje
3712334Ssetjerddir="/$scratch/create_ramdisk.$$.tmp"
3723446Smrjrdfile32="$rddir/rd.file.32"
3733446Smrjrdfile64="$rddir/rd.file.64"
3743446Smrjrdmnt32="$rddir/rd.mount.32"
3753446Smrjrdmnt64="$rddir/rd.mount.64"
3763446Smrjerrlog32="$rddir/rd.errlog.32"
3773446Smrjerrlog64="$rddir/rd.errlog.64"
3783446Smrjlofidev32=""
3793446Smrjlofidev64=""
3802334Ssetje
3812334Ssetje# make directory for temp files safely
3822334Ssetjerm -rf "$rddir"
3832334Ssetjemkdir "$rddir"
3842334Ssetje
3852334Ssetje# Clean up upon exit.
3862334Ssetjetrap 'cleanup' EXIT
3872334Ssetje
3883446Smrjif [ $SPLIT = yes ]; then
3893446Smrj	#
3903446Smrj	# We can't run lofiadm commands in parallel, so we have to do
3913446Smrj	# them here.
3923446Smrj	#
3933446Smrj	if [ "$format" = "ufs" ]; then
3943446Smrj		mkfile ${total_size}k "$rdfile32"
3953446Smrj		lofidev32=`lofiadm -a "$rdfile32"`
3963446Smrj		mkfile ${total_size}k "$rdfile64"
3973446Smrj		lofidev64=`lofiadm -a "$rdfile64"`
3983446Smrj	fi
3993446Smrj	create_archive "32-bit" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 &
4003446Smrj	create_archive "64-bit" "$ALT_ROOT/$BOOT_ARCHIVE_64" $lofidev64
4013446Smrj	wait
4023446Smrj	if [ "$format" = "ufs" ]; then
4033446Smrj		lofiadm -d "$rdfile32"
4043446Smrj		lofiadm -d "$rdfile64"
4053446Smrj	fi
4060Sstevel@tonic-gateelse
4073446Smrj	if [ "$format" = "ufs" ]; then
4083446Smrj		mkfile ${total_size}k "$rdfile32"
4093446Smrj		lofidev32=`lofiadm -a "$rdfile32"`
4103446Smrj	fi
4113446Smrj	create_archive "both" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32
4123446Smrj	[ "$format" = "ufs" ] && lofiadm -d "$rdfile32"
4130Sstevel@tonic-gatefi
4143446Smrjif [ $ERROR = 1 ]; then
4153446Smrj	cleanup
416174Sjg	exit 1
417174Sjgfi
418174Sjg
4190Sstevel@tonic-gate#
4200Sstevel@tonic-gate# For the diskless case, hardlink archive to /boot to make it
4210Sstevel@tonic-gate# visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>.
4223446Smrj# NOTE: this script must work on both client and server.
4230Sstevel@tonic-gate#
4242334Ssetjegrep "[	 ]/[	 ]*nfs[	 ]" "$ALT_ROOT/etc/vfstab" > /dev/null
4250Sstevel@tonic-gateif [ $? = 0 ]; then
4263446Smrj	rm -f "$ALT_ROOT/boot/boot_archive" "$ALT_ROOT/boot/amd64/boot_archive"
4272334Ssetje	ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/boot_archive"
4283446Smrj	ln "$ALT_ROOT/$BOOT_ARCHIVE_64" "$ALT_ROOT/boot/amd64/boot_archive"
4290Sstevel@tonic-gatefi
4302334Ssetjerm -rf "$rddir"
431