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