1#!/bin/ksh -p
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# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23# Use is subject to license terms.
24#
25
26. /usr/lib/brand/solaris10/common.ksh
27
28m_usage=$(gettext "solaris10 brand usage:\n\tinstall -u | -p [-v | -s] -a archive | -d directory.\n\tThe -a archive option specifies an archive name which can be a flar,\n\ttar, pax or cpio archive.\n\tThe -d directory option specifies an existing directory.\n\tThe -u option unconfigures the zone, -p preserves the configuration.")
29
30no_install=$(gettext "Could not create install directory '%s'")
31
32product_vers=$(gettext  "       Product: %s")
33install_vers=$(gettext  "     Installer: %s")
34install_zone=$(gettext  "          Zone: %s")
35install_path=$(gettext  "          Path: %s")
36installing=$(gettext    "    Installing: This may take several minutes...")
37no_installing=$(gettext "    Installing: Using pre-existing data in zonepath")
38install_prog=$(gettext  "    Installing: %s")
39
40install_fail=$(gettext  "        Result: *** Installation FAILED ***")
41install_log=$(gettext   "      Log File: %s")
42
43install_good=$(gettext  "        Result: Installation completed successfully.")
44
45unpack_done=$(gettext   " Unpack result: %d")
46
47sanity_ok=$(gettext     "  Sanity Check: Passed.  Looks like a Solaris 10 system.")
48sanity_fail=$(gettext   "  Sanity Check: FAILED (see log for details).")
49
50
51p2ving=$(gettext        "Postprocessing: This may take a while...")
52p2v_prog=$(gettext      "   Postprocess: ")
53p2v_done=$(gettext      "        Result: Postprocessing complete.")
54p2v_fail=$(gettext      "        Result: Postprocessing failed.")
55
56root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
57
58media_missing=\
59$(gettext "you must specify an installation source using '-a', '-d' or '-r'.\n%s")
60
61cfgchoice_missing=\
62$(gettext "you must specify -u (sys-unconfig) or -p (preserve identity).\n%s")
63
64mount_failed=$(gettext "ERROR: zonecfg(1M) 'fs' mount failed")
65
66not_flar=$(gettext "Input is not a flash archive")
67bad_flar=$(gettext "Flash archive is a corrupt")
68unknown_archiver=$(gettext "Archiver %s is not supported")
69
70# Clean up on interrupt
71trap_cleanup()
72{
73	msg=$(gettext "Installation cancelled due to interrupt.")
74	log "$msg"
75
76	# umount any mounted file systems
77	umnt_fs
78
79	trap_exit
80}
81
82# If the install failed then clean up the ZFS datasets we created.
83trap_exit()
84{
85	if (( $EXIT_CODE != $ZONE_SUBPROC_OK )); then
86		/usr/lib/brand/solaris10/uninstall $ZONENAME $ZONEPATH -F
87	fi
88
89	exit $EXIT_CODE
90}
91
92#
93# The main body of the script starts here.
94#
95# This script should never be called directly by a user but rather should
96# only be called by zoneadm to install a s10 system image into a zone.
97#
98
99#
100# Exit code to return if install is interrupted or exit code is otherwise
101# unspecified.
102#
103EXIT_CODE=$ZONE_SUBPROC_USAGE
104
105trap trap_cleanup INT
106trap trap_exit EXIT
107
108# If we weren't passed at least two arguments, exit now.
109(( $# < 2 )) && exit $ZONE_SUBPROC_USAGE
110
111ZONENAME="$1"
112ZONEPATH="$2"
113# XXX shared/common script currently uses lower case zonename & zonepath
114zonename="$ZONENAME"
115zonepath="$ZONEPATH"
116
117ZONEROOT="$ZONEPATH/root"
118logdir="$ZONEROOT/var/log"
119
120shift; shift	# remove ZONENAME and ZONEPATH from arguments array
121
122unset inst_type
123unset msg
124unset silent_mode
125unset OPT_V
126
127#
128# It is worth noting here that we require the end user to pick one of
129# -u (sys-unconfig) or -p (preserve config).  This is because we can't
130# really know in advance which option makes a better default.  Forcing
131# the user to pick one or the other means that they will consider their
132# choice and hopefully not be surprised or disappointed with the result.
133#
134unset unconfig_zone
135unset preserve_zone
136unset SANITY_SKIP
137
138while getopts "a:d:Fpr:suv" opt
139do
140	case "$opt" in
141		a)
142			if [[ -n "$inst_type" ]]; then
143				fatal "$incompat_options" "$m_usage"
144			fi
145		 	inst_type="archive"
146			install_media="$OPTARG"
147			;;
148		d)
149			if [[ -n "$inst_type" ]]; then
150				fatal "$incompat_options" "$m_usage"
151			fi
152		 	inst_type="directory"
153			install_media="$OPTARG"
154			;;
155		F)	SANITY_SKIP=1;;
156		p)	preserve_zone="-p";;
157		r)
158			if [[ -n "$inst_type" ]]; then
159				fatal "$incompat_options" "$m_usage"
160			fi
161		 	inst_type="stdin"
162			install_media="$OPTARG"
163			;;
164		s)	silent_mode=1;;
165		u)	unconfig_zone="-u";;
166		v)	OPT_V="-v";;
167		*)	printf "$m_usage\n"
168			exit $ZONE_SUBPROC_USAGE;;
169	esac
170done
171shift OPTIND-1
172
173# The install can't be both verbose AND silent...
174if [[ -n $silent_mode && -n $OPT_V ]]; then
175	fatal "$incompat_options" "$m_usage"
176fi
177
178if [[ -z $install_media ]]; then
179	fatal "$media_missing" "$m_usage"
180fi
181
182# The install can't both preserve and unconfigure
183if [[ -n $unconfig_zone && -n $preserve_zone ]]; then
184	fatal "$incompat_options" "$m_usage"
185fi
186
187# Must pick one or the other.
188if [[ -z $unconfig_zone && -z $preserve_zone ]]; then
189	fatal "$cfgchoice_missing" "$m_usage"
190fi
191
192LOGFILE=$(/usr/bin/mktemp -t -p /var/tmp $ZONENAME.install_log.XXXXXX)
193if [[ -z "$LOGFILE" ]]; then
194	fatal "$e_tmpfile"
195fi
196zone_logfile="${logdir}/$ZONENAME.install$$.log"
197exec 2>>"$LOGFILE"
198log "$install_log" "$LOGFILE"
199
200vlog "Starting pre-installation tasks."
201
202#
203# From here on out, an unspecified exit or interrupt should exit with
204# ZONE_SUBPROC_NOTCOMPLETE, meaning a user will need to do an uninstall before
205# attempting another install, as we've modified the directories we were going
206# to install to in some way.
207#
208EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE
209
210create_active_ds
211
212vlog "Installation started for zone \"$ZONENAME\""
213install_image "$inst_type" "$install_media"
214
215log "$p2ving"
216vlog "running: p2v $OPT_V $unconfig_zone $ZONENAME $ZONEPATH"
217
218#
219# Run p2v.
220#
221# Getting the output to the right places is a little tricky because what
222# we want is for p2v to output in the same way the installer does: verbose
223# messages to the log file always, and verbose messages printed to the
224# user if the user passes -v.  This rules out simple redirection.  And
225# we can't use tee or other tricks because they cause us to lose the
226# return value from the p2v script due to the way shell pipelines work.
227#
228# The simplest way to do this seems to be to hand off the management of
229# the log file to the p2v script.  So we run p2v with -l to tell it where
230# to find the log file and then reopen the log (O_APPEND) when p2v is done.
231#
232/usr/lib/brand/solaris10/p2v -l "$LOGFILE" -m "$p2v_prog" \
233     $OPT_V $unconfig_zone $ZONENAME $ZONEPATH
234p2v_result=$?
235exec 2>>$LOGFILE
236
237if (( $p2v_result == 0 )); then
238	vlog "$p2v_done"
239else
240	log "$p2v_fail"
241	log ""
242	log "$install_fail"
243	log "$install_log" "$LOGFILE"
244	exit $ZONE_SUBPROC_FATAL
245fi
246
247log ""
248log "$install_good" "$ZONENAME"
249
250safe_dir /var
251safe_dir /var/log
252safe_copy $LOGFILE $zone_logfile
253
254log "$install_log" "$zone_logfile"
255rm -f $LOGFILE
256
257# This needs to be set since the exit trap handler is going run.
258EXIT_CODE=$ZONE_SUBPROC_OK
259
260exit $ZONE_SUBPROC_OK
261