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