xref: /titanic_52/usr/src/tools/scripts/Install.sh (revision 3c112a2b34403220c06c3e2fcac403358cfba168)
1#!/bin/ksh
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 2010 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26# Author:  Jeff Bonwick
27#
28#	Please report any bugs to bonwick@eng.
29#
30# How Install works:
31#
32#	Install performs the following steps:
33#
34#	1. Get the list of modules, configuration files, and links
35#	   that are desired.
36#
37#	2. Create the requested subset of /kernel in Install's temp space
38#	   (/tmp/Install.username by default.)
39#
40#	3. Create a tar file (/tmp/Install.username/Install.tar) based on (3).
41#
42#	4. If -n was specified, exit.  If a target was specified using -T,
43#	   rcp the tarfile to the target and exit.  If a target was specified
44#	   using -t, rsh to the target machine and untar the tarfile in the
45#	   target directory.
46#
47# If any of these steps fail, Install will give you an error message and,
48# in most cases, suggest corrective measures.  Then, you can recover the
49# install with "Install -R". (This is not required; it's just faster than
50# starting from scratch.)
51#
52# One final comment:  Unfortunately, tar and I disagree on what
53# constitutes a fatal error.  (tar -x will exit 0 even if it can't write
54# anything in the current directory.)  Thus, I am reduced to grepping stderr
55# for (what I consider) fatal and nonfatal error messages.  If you run into
56# a situation where this doesn't behave the way you think it should (either
57# an "Install failed" message after a successful install, or an "Install
58# complete" message after it bombs), please let me know.
59
60#
61# The CDPATH variable causes ksh's `cd' builtin to emit messages to stdout
62# under certain circumstances, which can really screw things up; unset it.
63#
64unset CDPATH
65
66INSTALL=`basename $0`
67DOT=`pwd`
68
69TRAILER="Install.$LOGNAME"
70INSTALL_STATE=${INSTALL_STATE-$HOME/.Install.state}
71export INSTALL_STATE
72INSTALL_DIR=${INSTALL_DIR-/tmp/$TRAILER}
73if [ "`basename $INSTALL_DIR`" != "$TRAILER" ]; then
74	INSTALL_DIR="$INSTALL_DIR/$TRAILER"
75fi
76export INSTALL_DIR
77INSTALL_LIB=${INSTALL_LIB-$HOME/LibInstall}
78export INSTALL_LIB
79INSTALL_RC=${INSTALL_RC-$HOME/.Installrc}
80export INSTALL_RC
81INSTALL_CP=${INSTALL_CP-"cp -p"}
82export INSTALL_CP
83INSTALL_RCP=${INSTALL_RCP-"rcp -p"}
84export INSTALL_RCP
85
86STATE=0
87
88DEFAULT_OPTIONS="-naq"
89GLOM=no
90GLOMNAME=kernel
91IMPL="default"
92WANT32="yes"
93WANT64="yes"
94
95modlist=/tmp/modlist$$
96# dummy directory for make state files.
97modstatedir=/tmp/modstate$$
98
99trap 'fail "User Interrupt" "You can resume by typing \"$INSTALL -R\""' 1 2 3 15
100
101function usage {
102	echo ""
103	echo $1
104	echo '
105Usage: Install	[ -w workspace ]
106		[ -s srcdir (default: usr/src/uts) ]
107		[ -k karch (e.g. sun4u; required if not deducible from pwd) ]
108		[ -t target (extract tar file on target, e.g. user@machine:/) ]
109		[ -T target (copy tar file to target, e.g. user@machine:/tmp) ]
110		[ -n (no target, just create tar file in /tmp (default)) ]
111		[ -u (install unix only) ]
112		[ -m (install modules only) ]
113		[ -a (install everything, i.e. unix + modules (default)) ]
114		[ -v (verbose output) ]
115		[ -V (REALLY verbose output) ]
116		[ -q (quiet (default)) ]
117		[ -c (clean up (remove temp files) when done (default) ]
118		[ -p (preserve temp files -- useful for debugging) ]
119		[ -L (library create: put tarfile in $INSTALL_LIB/env.karch) ]
120		[ -l lib (library extract: use $INSTALL_LIB/lib as source) ]
121		[ -D libdir (default: $HOME/LibInstall) ]
122		[ -d tempdir (Install work area (default: /tmp)) ]
123		[ -G glomname (put all files under platform/karch/glomname) ]
124		[ -i impl (e.g. sunfire; recommended with -G) ]
125		[ -x (update /etc/name_to_major et al) ]
126		[ -X (do not update /etc/name_to_major et al (default)) ]
127		[ -P (update /etc/path_to_inst -- generally not advisable) ]
128		[ -h (help -- prints this message) ]
129		[ -R (recover a previous Install) ]
130		[ -o objdir (object directory - either obj or debug (the default)) ]
131		[ -K (do not copy kmdb) ]
132		[ -3 32-bit modules only ]
133		[ -6 64-bit modules only ]
134		[ list of modules to install ]
135
136For full details:
137
138	man -M /ws/on297-gate/public/docs Install
139'
140	exit 1
141}
142
143#
144# Save the current state of Install
145#
146
147function save_state {
148	rm -f $INSTALL_STATE
149	(echo "# State of previous Install
150TARGET=$TARGET
151ENV_PATH=$ENV_PATH
152ENV_NAME=$ENV_NAME
153KARCH=$KARCH
154UTS=$UTS
155INSTALL_DIR=$INSTALL_DIR
156INSTALL_LIB=$INSTALL_LIB
157IMODE=$IMODE
158LIBCREATE=$LIBCREATE
159LIBSRC=$LIBSRC
160VERBOSE=$VERBOSE
161CLEANUP=$CLEANUP
162GLOM=$GLOM
163GLOMNAME=$GLOMNAME
164KMDB=$KMDB
165files='$files'
166STATE=$STATE" >$INSTALL_STATE) || verbose "Warning: cannot save state"
167}
168
169#
170# Restore the previous state of Install
171#
172
173function restore_state {
174	test -s $INSTALL_STATE || fail "Can't find $INSTALL_STATE"
175	eval "`cat $INSTALL_STATE`"
176}
177
178#
179# Install failed -- print error messages and exit 2
180#
181
182function fail {
183	save_state
184	#
185	# We might have gotten here via a trap.  So wait for any
186	# children (especially "make modlist") to exit before giving
187	# the error message or cleaning up.
188	#
189	wait
190	while [ $# -gt 0 ]
191	do
192		echo $1
193		shift
194	done
195	rm -rf $modstatedir
196	rm -f $modlist
197	echo "Install failed"
198	exit 2
199}
200
201#
202# Echo a string in verbose mode only
203#
204
205function verbose {
206	test "$VERBOSE" != "q" && echo $1
207}
208
209#
210# hack for tmpfs bug -- remove files gradually
211#
212
213function remove_dir {
214	test -d $1 || return
215	local_dot=`pwd`
216	cd $1
217	touch foo
218	rm -f `find . -type f -print`
219	cd $local_dot
220	rm -rf $1
221}
222
223#
224# Create a directory if it doesn't already exist.
225# mkdir will provide an error message, so don't provide an additional
226# message.
227#
228
229function tstmkdir {
230	[ -d $1 ] || mkdir -p $1 || fail
231}
232
233#
234# Patch up target directories for glommed kernel.
235# usage: fixglom listfile glomname
236#
237
238function fixglom {
239	nawk \
240	    -v glomname=$2 \
241	    -v karch=$KARCH '
242	$1 == "MOD" || $1 == "SYMLINK" {
243		sub(/^platform.*kernel/, "platform/" karch "/" glomname, $3)
244		sub(/^kernel/, "platform/" karch "/" glomname, $3)
245		sub(/^usr.kernel/, "platform/" karch "/" glomname, $3)
246		print
247	}
248	$1 == "LINK" {
249		sub(/^platform.*kernel/, "platform/" karch "/" glomname, $2)
250		sub(/^kernel/, "platform/" karch "/" glomname, $2)
251		sub(/^usr.kernel/, "platform/" karch "/" glomname, $2)
252		sub(/^platform.*kernel/, "platform/" karch "/" glomname, $4)
253		sub(/^kernel/, "platform/" karch "/" glomname, $4)
254		sub(/^usr.kernel/, "platform/" karch "/" glomname, $4)
255		print
256	}
257	$1 == "CONF" {
258		sub(/^platform.*kernel/, "platform/" karch "/" glomname, $2)
259		sub(/^kernel/, "platform/" karch "/" glomname, $2)
260		sub(/^usr.kernel/, "platform/" karch "/" glomname, $2)
261		print
262	}
263	' $1 > $1.new
264	mv $1.new $1
265}
266
267#
268# Remove entries from
269# usage: filtimpl listfile implname
270#
271
272function filtimpl {
273	nawk \
274	    -v impl=$2 '
275	$1 == "MOD" || $1 == "SYMLINK" {
276		if ($5 == "all" || $5 == impl)
277			print
278	}
279	$1 == "CONF" {
280		if ($4 == "all" || $4 == impl)
281			print
282	}
283	$1 == "LINK" {
284		if ($6 == "all" || $6 == impl)
285			print
286	}
287	' $1 > $1.new
288	mv $1.new $1
289}
290
291#
292# Filter the module list to match the user's request.
293# Usage: filtmod listfile modules
294#
295function filtmod {
296	nawk -v reqstring="$2" '
297	function modmatch(modname) {
298		if (reqstring == "All") {
299			return (1)
300		} else if (reqstring == "Modules") {
301			if (modname != "unix" && modname != "genunix")
302				return (1)
303		} else {
304			if (modname in reqmods)
305				return (1)
306		}
307		return (0)
308	}
309	BEGIN {
310		#
311		# The split call creates indexes 1, 2, 3, ...  We want
312		# the module names as indexes.
313		#
314		split(reqstring, tmpmods)
315		for (i in tmpmods)
316			reqmods[tmpmods[i]] = 1
317	}
318	$1 == "MOD" {
319		if (modmatch($2))
320			print
321	}
322	$1 == "CONF" {
323		if (modmatch($5))
324			print
325	}
326	$1 == "SYMLINK" {
327		if (modmatch($6))
328			print
329	}
330	$1 == "LINK" {
331		if (modmatch($3))
332			print
333	}
334	' $1 > $1.new
335	mv $1.new $1
336}
337
338#
339# Unpack the crypto tarball into the given tree, then massage the
340# tree so that the binaries are all in objNN or debugNN directories.
341#
342function unpack_crypto {
343	typeset tarfile=$1
344	typeset ctop=$2
345	[ -d "$ctop" ] || fail "Can't create tree for crypto modules."
346
347	[ "$VERBOSE" = "V" ] && echo "unpacking crypto tarball into $ctop..."
348	bzcat "$tarfile" | (cd "$ctop"; tar xf -)
349
350	typeset root="$ctop/proto/root_$MACH"
351	[ $OBJD = obj ] && root="$ctop/proto/root_$MACH-nd"
352	[ -d "$root" ] || fail "Can't unpack crypto tarball."
353
354	(cd "$root"; for d in platform kernel usr/kernel; do
355		[ ! -d $d ] && continue
356		find $d -type f -print
357	done) | while read file; do
358		typeset dir=$(dirname "$file")
359		typeset base=$(basename "$file")
360		typeset type=$(basename "$dir")
361		if [ "$type" = amd64 ]; then
362			newdir="$dir/${OBJD}64"
363		elif [ "$type" = sparcv9 ]; then
364			newdir="$dir/${OBJD}64"
365		else
366			newdir="$dir/${OBJD}32"
367		fi
368		mkdir -p "$root/$newdir"
369		[ "$VERBOSE" = "V" ] && echo "mv $file $newdir"
370		mv "$root/$file" "$root/$newdir"
371	done
372}
373
374#
375# usage: fixcrypto listfile ctop
376# Massage entries in listfile for crypto modules, so that they point
377# into ctop.
378#
379function fixcrypto {
380	typeset listfile=$1
381	typeset ctop=$2
382
383	typeset ccontents=/tmp/crypto-toc$$
384	find "$ctop" -type f -print > $ccontents
385	typeset root=root_$MACH
386	[ "$OBJD" = obj ] && root=root_$MACH-nd
387
388	grep -v ^MOD $listfile > $listfile.no-mod
389	grep ^MOD $listfile | while read tag module targdir size impl srcdir; do
390		#
391		# We don't just grep for ${OBJD}$size/$module because
392		# there can be generic and platform-dependent versions
393		# of a module.
394		#
395		newsrcfile=$(grep -w $root/$targdir/${OBJD}$size/$module $ccontents)
396		if [ -n "$newsrcfile" ]; then
397			# srcdir doesn't include final objNN or debugNN
398			echo $tag $module $targdir $size $impl \
399			    $(dirname $(dirname "$newsrcfile"))
400		else
401			echo $tag $module $targdir $size $impl $srcdir
402		fi
403	done > $listfile.mod
404	cat $listfile.mod $listfile.no-mod > $listfile
405
406	rm -f $listfile.mod
407	rm -f $listfile.no-mod
408	rm -f $ccontents
409}
410
411#
412# Copy a module, or create a link, as needed.
413# See $SRC/uts/Makefile.targ ($(MODLIST_DEPS) target) for the format
414# of the different input lines.
415#
416
417function copymod {
418	case $1 in
419	MOD)
420		targdir=$INSTALL_FILES/$3
421		tstmkdir $targdir
422		target=$targdir/$2
423		verbose "$INSTALL_CP $6/${OBJD}$4/$2 $target"
424		$INSTALL_CP $6/${OBJD}$4/$2 $target || \
425		    fail "can't create $target"
426		;;
427	SYMLINK)
428		targdir=$INSTALL_FILES/$3
429		tstmkdir $targdir
430		target=$targdir/$4
431		rm -f $target
432		verbose "ln -s $2 $target"
433		ln -s $2 $target || fail "can't create $target"
434		;;
435	LINK)
436		targdir=$INSTALL_FILES/$4
437		tstmkdir $targdir
438		target=$targdir/$5
439		rm -f $target
440		verbose "ln $INSTALL_FILES/$2/$3 $target"
441		ln $INSTALL_FILES/$2/$3 $target || fail "can't create $target"
442		;;
443	CONF)
444		target=$INSTALL_FILES/$2
445		tstmkdir `dirname $target`
446		conffile=`basename $2`
447		verbose "$INSTALL_CP $3/$conffile $target"
448		$INSTALL_CP $3/$conffile $target
449		;;
450	*)
451		fail "unrecognized modlist entry: $*"
452		;;
453	esac
454}
455
456#
457# Copy kernel modules to $INSTALL_DIR
458#
459
460function copy_kernel {
461
462	case $KARCH in
463		sun4*)		ISA=sparc;	MACH=sparc	;;
464		i86*)		ISA=intel;	MACH=i386	;;
465		*)		fail "${KARCH}: invalid kernel architecture";;
466	esac
467	export MACH
468
469	if [ "$GLOM" = "no" ]; then
470		verbose "Source = $UTS, ISA = $ISA, kernel = $KARCH"
471	else
472		verbose "Source = $UTS, ISA = $ISA, kernel = $KARCH, impl = $IMPL"
473	fi
474
475	test -d $KARCH || fail "${KARCH}: invalid kernel architecture"
476	test -d $ISA || fail "${ISA}: invalid instruction set architecture"
477
478	tstmkdir $INSTALL_FILES
479	rm -rf $modstatedir
480	tstmkdir $modstatedir
481	export MODSTATE=$modstatedir/state
482
483	#
484	# Figure out which "make" to use.  dmake is faster than serial
485	# make, but dmake 7.3 has a bug that causes it to lose log
486	# output, which means the modlist might be incomplete.
487	#
488	make=dmake
489	dmvers=`$make -version`
490	if [ $? -ne 0 ]; then
491		make=/usr/ccs/bin/make
492	elif [[ $dmvers = *Distributed?Make?7.3* ]]; then
493		unset make
494		searchpath="/ws/onnv-tools/SUNWspro/SOS10/bin
495			/opt/SUNWspro/SOS10/bin
496			/opt/SUNWspro/bin"
497		for dmpath in $searchpath; do
498			verbose "Trying $dmpath/dmake"
499			if [ -x $dmpath/dmake ]; then
500				dmvers=`$dmpath/dmake -version`
501				if [[ $dmvers != *Distributed?Make?7.3* ]]; then
502					make="$dmpath/dmake"
503					break;
504				fi
505			fi
506		done
507		if [ -z $make ]; then
508			make=/usr/ccs/bin/make
509			echo "Warning: dmake 7.3 doesn't work with Install;" \
510				"using $make"
511		fi
512	fi
513
514	#
515	# Get a list of all modules, configuration files, and links
516	# that we might want to install.
517	#
518	verbose "Building module list..."
519	(cd $KARCH; MAKEFLAGS=e $make -K $MODSTATE modlist.karch) | \
520	    egrep "^MOD|^CONF|^LINK|^SYMLINK" > $modlist
521	[ "$VERBOSE" = "V" ] && cat $modlist
522	if [ -n "$ON_CRYPTO_BINS" ]; then
523		cryptotar="$ON_CRYPTO_BINS"
524		if [ "$OBJD" = obj ]; then
525			isa=$(uname -p)
526			cryptotar=$(echo "$ON_CRYPTO_BINS" |
527			    sed -e s/.$isa.tar.bz2/-nd.$isa.tar.bz2/)
528		fi
529		[ -f "$cryptotar" ] || fail "crypto ($cryptotar) doesn't exist"
530		cryptotree=$(mktemp -d /tmp/crypto.XXXXXX)
531		[ -n "$cryptotree" ] || fail "can't create tree for crypto"
532		unpack_crypto "$cryptotar" "$cryptotree"
533		#
534		# fixcrypto must come before fixglom, because
535		# fixcrypto uses the unglommed path to find things in
536		# the unpacked crypto.
537		#
538		fixcrypto $modlist "$cryptotree"
539	fi
540	if [ "$GLOM" = "yes" ]; then
541		fixglom $modlist $GLOMNAME
542		filtimpl $modlist $IMPL
543	fi
544	if [[ -n "$files" && "$files" != All ]]; then
545		filtmod $modlist "$files"
546	fi
547
548	#
549	# Copy modules and create links.  For architectures with both
550	# 32- and 64-bit modules, we'll likely have duplicate
551	# configuration files, so do those after filtering out the
552	# duplicates.
553	#
554	verbose "Copying files to ${INSTALL_FILES}..."
555
556	#
557	# The IFS is reset to the newline character so we can buffer the
558	# output of grep without piping it directly to copymod, otherwise
559	# if fail() is called, then it will deadlock in fail()'s wait call
560	#
561	OIFS="$IFS"
562	IFS="
563	"
564	set -- `grep -v "^CONF" $modlist`;
565	IFS="$OIFS"
566	for onemod in "$@"; do
567		copymod $onemod
568	done
569
570	OIFS="$IFS"
571	IFS="
572	"
573	set -- `grep "^CONF" $modlist | sort | uniq`;
574	IFS="$OIFS"
575	for onemod in "$@"; do
576		copymod $onemod
577	done
578
579	#
580	# Add the glommed kernel name to the root archive
581	#
582	if [[ $GLOM == "yes" ]];
583	then
584		filelist="$INSTALL_FILES/etc/boot/solaris/filelist.ramdisk"
585		mkdir -p `dirname $filelist`
586		echo "platform/$KARCH/$GLOMNAME" >$filelist
587	fi
588
589	STATE=1 # all kernel modules copied correctly
590	save_state
591}
592
593function kmdb_copy {
594	typeset src="$1"
595	typeset destdir="$2"
596
597	if [[ ! -d $dest ]] ; then
598		[[ "$VERBOSE" != "q" ]] && echo "mkdir -p $destdir"
599
600		mkdir -p $destdir || fail "failed to create $destdir"
601	fi
602
603	[[ "$VERBOSE" != "q" ]] && echo "cp $src $destdir"
604
605	cp $src $destdir || fail "failed to copy $src to $destdir"
606}
607
608function kmdb_copy_machkmods {
609	typeset modbase="$1"
610	typeset destdir="$2"
611	typeset dir=
612	typeset kmod=
613
614	[[ ! -d $modbase ]] && return
615
616	for dir in $(find $modbase -name kmod) ; do
617		set -- $(echo $dir |tr '/' ' ')
618
619		[[ $# -lt 2 ]] && fail "invalid mach kmod dir $dir"
620
621		shift $(($# - 2))
622		kmod=$1
623
624		[[ ! -f $dir/$kmod ]] && continue
625
626		kmdb_copy $dir/$kmod $destdir
627	done
628}
629
630function kmdb_copy_karchkmods {
631	typeset modbase="$1"
632	typeset destdir="$2"
633	typeset bitdir="$3"
634	typeset dir=
635	typeset kmod=
636	typeset karch=
637
638	[[ ! -d $modbase ]] && return
639
640	for dir in $(find $modbase -name kmod) ; do
641		set -- $(echo $dir | tr '/' ' ')
642
643		[[ $# -lt 3 ]] && fail "invalid karch kmod dir $dir"
644
645		shift $(($# - 3))
646		kmod=$1
647		bdir=$2
648
649		[[ $bdir != $bitdir ]] && continue
650		[[ ! -f $dir/$1 ]] && continue
651
652		kmdb_copy $dir/$kmod $destdir
653	done
654}
655
656function kmdb_copy_kmdbmod {
657	typeset kmdbpath="$1"
658	typeset destdir="$2"
659
660	[[ ! -f $kmdbpath ]] && return 1
661
662	kmdb_copy $kmdbpath $destdir
663
664	return 0
665}
666
667function copy_kmdb {
668	typeset kmdbtgtdir=$INSTALL_FILES/platform/$KARCH/$GLOMNAME/misc
669	typeset bitdirs=
670	typeset isadir=
671	typeset b64srcdir=
672	typeset b64tgtdir=
673	typeset b32srcdir=
674	typeset b32tgtdir=
675	typeset machdir=
676	typeset platdir=
677
678	if [[ $KMDB = "no" || ! -d $SRC/cmd/mdb ]] ; then
679		# The kmdb copy was suppressed or the workspace doesn't contain
680		# the mdb subtree.  Either way, there's nothing to do.
681		STATE=2
682		save_state
683		return
684	fi
685
686	if [[ $(mach) = "i386" ]] ; then
687		isadir="intel"
688		b64srcdir="amd64"
689		b64tgtdir="amd64"
690		b32srcdir="ia32"
691		b32tgtdir="."
692	else
693		isadir="sparc"
694		b64srcdir="v9"
695		b64tgtdir="sparcv9"
696		b32srcdir="v7"
697		b32tgtdir="."
698	fi
699
700	typeset foundkmdb=no
701	typeset kmdbpath=
702	typeset destdir=
703
704	platdir=$INSTALL_FILES/platform/$KARCH/$GLOMNAME
705	if [[ $GLOM = "yes" ]] ; then
706		machdir=$platdir
707	else
708		machdir=$INSTALL_FILES/kernel
709	fi
710
711	srctrees=$SRC
712	if [[ -d $SRC/../closed && "$CLOSED_IS_PRESENT" != no ]]; then
713		srctrees="$srctrees $SRC/../closed"
714	else
715		if [ -z "$ON_CRYPTO_BINS" ]; then
716			echo "Warning: ON_CRYPTO_BINS not set; pre-signed" \
717			    "crypto not provided."
718		fi
719	fi
720	if [[ $WANT64 = "yes" ]] ; then
721		# kmdbmod for sparc and x86 are built and installed
722		# in different places
723		if [[ $(mach) = "i386" ]] ; then
724			kmdbpath=$SRC/cmd/mdb/$isadir/$b64srcdir/kmdb/kmdbmod
725			destdir=$machdir/misc/$b64tgtdir
726		else
727			kmdbpath=$SRC/cmd/mdb/$KARCH/$b64srcdir/kmdb/kmdbmod
728			destdir=$platdir/misc/$b64tgtdir
729		fi
730
731		if kmdb_copy_kmdbmod $kmdbpath $destdir ; then
732			foundkmdb="yes"
733
734			for tree in $srctrees; do
735				kmdb_copy_machkmods \
736				    $tree/cmd/mdb/$isadir/$b64srcdir \
737				    $machdir/kmdb/$b64tgtdir
738				kmdb_copy_karchkmods $tree/cmd/mdb/$KARCH \
739				    $platdir/kmdb/$b64tgtdir $b64srcdir
740			done
741		fi
742	fi
743
744	if [[ $WANT32 = "yes" ]] ; then
745		kmdbpath=$SRC/cmd/mdb/$isadir/$b32srcdir/kmdb/kmdbmod
746		destdir=$machdir/misc/$b32tgtdir
747
748		if kmdb_copy_kmdbmod $kmdbpath $destdir ; then
749			foundkmdb="yes"
750
751			for tree in $srctrees; do
752				kmdb_copy_machkmods \
753				    $tree/cmd/mdb/$isadir/$b32srcdir \
754				    $machdir/kmdb/$b32tgtdir
755				kmdb_copy_karchkmods $tree/cmd/mdb/$KARCH \
756				    $platdir/kmdb/$b32tgtdir $b32srcdir
757			done
758		fi
759	fi
760
761	# A kmdb-less workspace isn't fatal, but it is potentially problematic,
762	# as the changes made to uts may have altered something upon which kmdb
763	# depends.  We will therefore remind the user that they haven't built it
764	# yet.
765	if [[ $foundkmdb != "yes" ]] ; then
766		echo "WARNING: kmdb isn't built, and won't be included"
767	fi
768
769	STATE=2
770	save_state
771	return
772}
773
774#
775# Make tarfile
776#
777
778function make_tarfile {
779	echo "Creating tarfile $TARFILE"
780	test -d $INSTALL_FILES || fail "Can't find $INSTALL_FILES"
781	cd $INSTALL_FILES
782	rm -f $TARFILE files
783
784	# We don't want to change the permissions or ownership of pre-existing
785	# directories on the target machine, so we're going to take care to
786	# avoid including directories in the tarfile.  On extraction, tar won't
787	# modify pre-existing directories, and will create non-existent ones as
788	# the user doing the extraction.
789	find . ! -type d -print |fgrep -vx './files' >files
790	tar cf $TARFILE -I files || fail "Couldn't create tarfile $TARFILE"
791	STATE=3
792}
793
794#
795# Routines to copy files to the target machine
796#
797
798function remote_fail {
799	fail "" "$1" "" \
800		"Make sure that $TARGET_MACHINE is up." \
801"Check .rhosts in the home directory of user $TARGET_USER on $TARGET_MACHINE." \
802		"Check /etc/hosts.equiv, /etc/passwd, and /etc/shadow." \
803		"Change permissions on $TARGET_MACHINE as necessary." \
804		"Then, use \"$INSTALL -R\" to resume the install." ""
805}
806
807function remote_install {
808	if [ "$IMODE" = "n" ]; then
809		STATE=4
810		return 0
811	fi
812	test -s $TARFILE || fail "$TARFILE missing or empty"
813	verbose "Installing system on $TARGET"
814	test -d $INSTALL_DIR || fail "Can't find $INSTALL_DIR"
815	cd $INSTALL_DIR
816	rm -f errors fatal nonfatal
817	if [ "$IMODE" = "T" ]; then
818		EMESG="Can't rcp to $TARGET"
819		touch errors
820		sh -e${SHV}c "$INSTALL_RCP $TARFILE $TARGET/Install.tar"
821	else
822		EMESG="Can't rsh to $TARGET_MACHINE"
823		rsh -l $TARGET_USER $TARGET_MACHINE \
824		    "(cd $TARGET_DIR; /usr/bin/tar x${V}f -)" \
825		    <$TARFILE 2>errors
826	fi
827	test $? -ne 0 && remote_fail "$EMESG"
828	cd $INSTALL_DIR
829	egrep "set time|warning|blocksize" errors >nonfatal
830	egrep -v "set time|warning|blocksize" errors >fatal
831	if [ -s fatal ]; then
832		echo "Fatal errors from rsh:"
833		cat fatal
834		remote_fail "Can't install on $TARGET_MACHINE"
835	fi
836	if [ -s nonfatal -a "$VERBOSE" != "q" ]; then
837		echo "Non-fatal errors from rsh:"
838		cat nonfatal
839	fi
840	rm -f fatal nonfatal errors
841	test "$IMODE" = "T" && echo "Files can be extracted on \
842$TARGET_MACHINE using 'tar xvf $TARGET_DIR/Install.tar'"
843	STATE=4
844}
845
846function okexit {
847	cd /tmp
848	test "$CLEANUP" = c && remove_dir $INSTALL_DIR
849	save_state
850	rm -rf $modstatedir
851	rm -f $modlist
852	[ -n "$cryptotree" ] && rm -rf "$cryptotree"
853	verbose "Install complete"
854	exit 0
855}
856
857#
858# Process options
859#
860
861RCOPTS=""
862LIBCREATE="no"
863LIBSRC=""
864ENV_PATH=$CODEMGR_WS
865OBJD="debug"
866KMDB="yes"
867
868test -s $INSTALL_RC && RCOPTS=`cat $INSTALL_RC`
869set $INSTALL $DEFAULT_OPTIONS $RCOPTS $*
870shift
871
872while getopts acd:D:G:hi:k:Kl:Lmno:pPqRs:t:T:uvVw:xX36 opt
873do
874	case $opt in
875	    w)	ENV_PATH="$OPTARG"; SRC="$ENV_PATH/usr/src";;
876	    s)	UTS="$OPTARG";;
877	    k)	KARCH="$OPTARG";;
878	  t|T)	TARGET="$OPTARG"; IMODE=$opt; CLEANUP="c";;
879	    n)	TARGET=""; IMODE="n"; CLEANUP="p";;
880	    u)	files="unix genunix";;
881	    m)	files="Modules";;
882	    a)	files="All";;
883	v|V|q)	VERBOSE=$opt;;
884	  c|p)	CLEANUP=$opt;;
885	    L)	LIBCREATE="yes"; CLEANUP="c";;
886	    l)	LIBSRC="$OPTARG";;
887	    D)	INSTALL_LIB="$OPTARG";;
888	    d)	INSTALL_DIR="$OPTARG/$TRAILER";;
889	    G)	GLOM=yes; GLOMNAME="$OPTARG";;
890	P|X|x)	echo "-$opt is obsolete; ignored";;
891	    h)	usage "${INSTALL}: installs unix and modules";;
892	    R)	x=$OPTIND; restore_state; OPTIND=$x;;
893	    i)	IMPL="$OPTARG";;
894	    o)	OBJD="$OPTARG";;
895	    K)  KMDB="no";;
896	    3)  WANT64="no";;
897	    6)  WANT32="no";;
898	   \?)	usage "Illegal option";;
899	esac
900done
901shift `expr $OPTIND - 1`
902
903ENV_NAME=`basename $ENV_PATH`
904
905#
906# The rest of the command line is a list of individual files to copy.
907# If non-null, this list overrides the -uma options.
908#
909
910if [[ $# -gt 0 ]] ; then
911	files="$*"
912	KMDB="no"
913fi
914
915case "$VERBOSE" in
916	v)	V="v"; SHV="x";;
917	V)	V="v"; SHV="x"; set -x;;
918	q)	V=""; SHV="";;
919esac
920
921#
922# Create temp directory for Install's files
923#
924
925tstmkdir $INSTALL_DIR
926
927TARFILE=$INSTALL_DIR/Install.${KARCH}.tar
928INSTALL_FILES=$INSTALL_DIR/$KARCH
929
930#
931# Extract the target machine and target directory from a target of the
932# form [user@]machine:/dir .
933#
934
935if [ "$IMODE" != "n" ]; then
936	eval `echo $TARGET | nawk -F':' '{
937		if (NF != 2 || !length($1) || !length($2))
938			print "usage \"Invalid target\""
939		m = $1; d = $2
940		if ($1 ~ /@/) {
941		    k = split($1, f, "@");
942		    if (k != 2 || !length(f[1]) || !length (f[2]))
943			    print "usage \"Invalid target\""
944		    u = f[1]; m = f[2]
945		}
946		print "TARGET_USER=" u ";"
947		print "TARGET_MACHINE=" m ";"
948		print "TARGET_DIR=" d ";"
949	}'`
950	if [ -z "$TARGET_USER" ]; then
951		TARGET_USER=$LOGNAME
952	fi
953fi
954
955#
956# Allow the use of library source or target for the install
957#
958
959if [ -n "$LIBSRC" ]; then
960	LIBSRC="`basename $LIBSRC .tar`.tar"
961	TARFILE=$INSTALL_LIB/$LIBSRC
962	test -s $TARFILE || fail "Can't find tarfile $TARFILE"
963	verbose "Installing from library tarfile $TARFILE"
964	STATE=3
965elif [ "$LIBCREATE" = "yes" ]; then
966	tstmkdir $INSTALL_LIB
967	TARFILE="$INSTALL_LIB/${ENV_NAME}.${KARCH}.tar"
968fi
969
970#
971# The next few lines allow recovery and activation with -R,
972# and library installs with -l.
973#
974
975[[ $STATE -eq 1 ]] && copy_kmdb
976[[ $STATE -eq 2 ]] && make_tarfile
977[[ $STATE -eq 3 ]] && remote_install
978[[ $STATE -eq 4 ]] && okexit
979
980save_state
981
982cd $DOT
983DOTDOT=`cd ..; pwd`
984
985#
986# Try to be smart: if DOTDOT ends in uts, then infer UTS and KARCH from DOT
987# Otherwise, if SRC is set, infer UTS = $SRC/uts.
988#
989
990if [ "`basename $DOTDOT`" = "uts" ]; then
991	UTS=$DOTDOT
992	KARCH=`basename $DOT`
993	if [ ! -n "$SRC" ]; then
994		SRC=`dirname $DOTDOT`
995		verbose "Setting SRC to $SRC"
996	fi
997	export SRC
998fi
999
1000if [ -z "$UTS" -a -n "$SRC" ]; then
1001	UTS="${SRC}/uts"
1002	test -n "$KARCH" || fail "no karch specified (e.g. -k sun4u)"
1003fi
1004
1005if [ "$LIBCREATE" = "yes" ]; then
1006	TARFILE=$INSTALL_LIB/${ENV_NAME}.${KARCH}.tar
1007else
1008	TARFILE=$INSTALL_DIR/Install.${KARCH}.tar
1009fi
1010INSTALL_FILES=$INSTALL_DIR/$KARCH
1011save_state
1012
1013cd $DOT
1014test -z "$UTS" && fail 'Cannot find kernel sources -- $SRC not set'
1015test -d "$UTS" || fail "${UTS}: no such directory"
1016
1017#
1018# Convert UTS into an absolute path.
1019#
1020
1021cd $UTS
1022UTS=`pwd`
1023
1024test "`basename $UTS`" = "uts" || \
1025	verbose "Warning: source path $UTS doesn't end in 'uts'"
1026
1027remove_dir $INSTALL_DIR/$KARCH
1028rm -f $TARFILE
1029
1030copy_kernel	# sets STATE=1 if successful
1031copy_kmdb	# sets STATE=2 if successful
1032make_tarfile	# sets STATE=3 if successful
1033remote_install	# sets STATE=4 if successful
1034
1035okexit
1036