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