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 2010 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
45sanity_ok=$(gettext     "  Sanity Check: Passed.  Looks like a Solaris 10 system.")
46sanity_fail=$(gettext   "  Sanity Check: FAILED (see log for details).")
47
48
49p2ving=$(gettext        "Postprocessing: This may take a while...")
50p2v_prog=$(gettext      "   Postprocess: ")
51p2v_done=$(gettext      "        Result: Postprocessing complete.")
52p2v_fail=$(gettext      "        Result: Postprocessing failed.")
53
54root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
55
56media_missing=\
57$(gettext "you must specify an installation source using '-a', '-d' or '-r'.\n%s")
58
59cfgchoice_missing=\
60$(gettext "you must specify -u (sys-unconfig) or -p (preserve identity).\n%s")
61
62mount_failed=$(gettext "ERROR: zonecfg(8) 'fs' mount failed")
63
64not_flar=$(gettext "Input is not a flash archive")
65bad_flar=$(gettext "Flash archive is a corrupt")
66unknown_archiver=$(gettext "Archiver %s is not supported")
67
68# Clean up on interrupt
69trap_cleanup()
70{
71	msg=$(gettext "Installation cancelled due to interrupt.")
72	log "$msg"
73
74	# umount any mounted file systems
75	umnt_fs
76
77	trap_exit
78}
79
80# If the install failed then clean up the ZFS datasets we created.
81trap_exit()
82{
83	if (( $EXIT_CODE != $ZONE_SUBPROC_OK )); then
84		/usr/lib/brand/solaris10/uninstall $ZONENAME $ZONEPATH -F
85	fi
86
87	exit $EXIT_CODE
88}
89
90#
91# The main body of the script starts here.
92#
93# This script should never be called directly by a user but rather should
94# only be called by zoneadm to install a s10 system image into a zone.
95#
96
97#
98# Exit code to return if install is interrupted or exit code is otherwise
99# unspecified.
100#
101EXIT_CODE=$ZONE_SUBPROC_USAGE
102
103trap trap_cleanup INT
104trap trap_exit EXIT
105
106# If we weren't passed at least two arguments, exit now.
107(( $# < 2 )) && exit $ZONE_SUBPROC_USAGE
108
109ZONENAME="$1"
110ZONEPATH="$2"
111# XXX shared/common script currently uses lower case zonename & zonepath
112zonename="$ZONENAME"
113zonepath="$ZONEPATH"
114
115ZONEROOT="$ZONEPATH/root"
116logdir="$ZONEROOT/var/log"
117
118shift; shift	# remove ZONENAME and ZONEPATH from arguments array
119
120unset inst_type
121unset msg
122unset silent_mode
123unset OPT_V
124
125#
126# It is worth noting here that we require the end user to pick one of
127# -u (sys-unconfig) or -p (preserve config).  This is because we can't
128# really know in advance which option makes a better default.  Forcing
129# the user to pick one or the other means that they will consider their
130# choice and hopefully not be surprised or disappointed with the result.
131#
132unset unconfig_zone
133unset preserve_zone
134unset SANITY_SKIP
135
136while getopts "a:d:Fpr:suv" opt
137do
138	case "$opt" in
139		a)
140			if [[ -n "$inst_type" ]]; then
141				fatal "$incompat_options" "$m_usage"
142			fi
143		 	inst_type="archive"
144			install_media="$OPTARG"
145			;;
146		d)
147			if [[ -n "$inst_type" ]]; then
148				fatal "$incompat_options" "$m_usage"
149			fi
150		 	inst_type="directory"
151			install_media="$OPTARG"
152			;;
153		F)	SANITY_SKIP=1;;
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
213[[ "$SANITY_SKIP" == "1" ]] && touch $ZONEROOT/.sanity_skip
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
247# Add a service tag for this zone.
248add_svc_tag "$ZONENAME" "install $inst_type `basename $install_media`"
249
250log ""
251log "$install_good" "$ZONENAME"
252
253safe_dir /var
254safe_dir /var/log
255safe_copy $LOGFILE $zone_logfile
256
257log "$install_log" "$zone_logfile"
258rm -f $LOGFILE
259
260# This needs to be set since the exit trap handler is going run.
261EXIT_CODE=$ZONE_SUBPROC_OK
262
263exit $ZONE_SUBPROC_OK
264