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
136
137while getopts "a:d:pr:suv" opt
138do
139	case "$opt" in
140		a)
141			if [[ -n "$inst_type" ]]; then
142				fatal "$incompat_options" "$m_usage"
143			fi
144		 	inst_type="archive"
145			install_media="$OPTARG"
146			;;
147		d)
148			if [[ -n "$inst_type" ]]; then
149				fatal "$incompat_options" "$m_usage"
150			fi
151		 	inst_type="directory"
152			install_media="$OPTARG"
153			;;
154		p)	preserve_zone="-p";;
155		r)
156			if [[ -n "$inst_type" ]]; then
157				fatal "$incompat_options" "$m_usage"
158			fi
159		 	inst_type="stdin"
160			install_media="$OPTARG"
161			;;
162		s)	silent_mode=1;;
163		u)	unconfig_zone="-u";;
164		v)	OPT_V="-v";;
165		*)	printf "$m_usage\n"
166			exit $ZONE_SUBPROC_USAGE;;
167	esac
168done
169shift OPTIND-1
170
171# The install can't be both verbose AND silent...
172if [[ -n $silent_mode && -n $OPT_V ]]; then
173	fatal "$incompat_options" "$m_usage"
174fi
175
176if [[ -z $install_media ]]; then
177	fatal "$media_missing" "$m_usage"
178fi
179
180# The install can't both preserve and unconfigure
181if [[ -n $unconfig_zone && -n $preserve_zone ]]; then
182	fatal "$incompat_options" "$m_usage"
183fi
184
185# Must pick one or the other.
186if [[ -z $unconfig_zone && -z $preserve_zone ]]; then
187	fatal "$cfgchoice_missing" "$m_usage"
188fi
189
190LOGFILE=$(/usr/bin/mktemp -t -p /var/tmp $ZONENAME.install_log.XXXXXX)
191if [[ -z "$LOGFILE" ]]; then
192	fatal "$e_tmpfile"
193fi
194zone_logfile="${logdir}/$ZONENAME.install$$.log"
195exec 2>>"$LOGFILE"
196log "$install_log" "$LOGFILE"
197
198vlog "Starting pre-installation tasks."
199
200#
201# From here on out, an unspecified exit or interrupt should exit with
202# ZONE_SUBPROC_NOTCOMPLETE, meaning a user will need to do an uninstall before
203# attempting another install, as we've modified the directories we were going
204# to install to in some way.
205#
206EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE
207
208create_active_ds
209
210vlog "Installation started for zone \"$ZONENAME\""
211install_image "$inst_type" "$install_media"
212
213log "$p2ving"
214vlog "running: p2v $OPT_V $unconfig_zone $ZONENAME $ZONEPATH"
215
216#
217# Run p2v.
218#
219# Getting the output to the right places is a little tricky because what
220# we want is for p2v to output in the same way the installer does: verbose
221# messages to the log file always, and verbose messages printed to the
222# user if the user passes -v.  This rules out simple redirection.  And
223# we can't use tee or other tricks because they cause us to lose the
224# return value from the p2v script due to the way shell pipelines work.
225#
226# The simplest way to do this seems to be to hand off the management of
227# the log file to the p2v script.  So we run p2v with -l to tell it where
228# to find the log file and then reopen the log (O_APPEND) when p2v is done.
229#
230/usr/lib/brand/solaris10/p2v -l "$LOGFILE" -m "$p2v_prog" \
231     $OPT_V $unconfig_zone $ZONENAME $ZONEPATH
232p2v_result=$?
233exec 2>>$LOGFILE
234
235if (( $p2v_result == 0 )); then
236	vlog "$p2v_done"
237else
238	log "$p2v_fail"
239	log ""
240	log "$install_fail"
241	log "$install_log" "$LOGFILE"
242	exit $ZONE_SUBPROC_FATAL
243fi
244
245log ""
246log "$install_good" "$ZONENAME"
247
248safe_dir /var
249safe_dir /var/log
250safe_copy $LOGFILE $zone_logfile
251
252log "$install_log" "$zone_logfile"
253rm -f $LOGFILE
254
255# This needs to be set since the exit trap handler is going run.
256EXIT_CODE=$ZONE_SUBPROC_OK
257
258exit $ZONE_SUBPROC_OK
259