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#
23# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24#
25
26. /usr/lib/brand/solaris10/common.ksh
27
28m_attach_log=$(gettext "Log File: %s")
29m_zfs=$(gettext "A ZFS file system was created for the zone.")
30m_attaching=$(gettext "Attaching...")
31m_usage=$(gettext  "solaris10 brand usage:\n\tattach [-a archive | -d directory | -r recv_type]\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 -r recv_type option specifies the type of archive to be read from\n\tstdin.")
32m_complete=$(gettext "Attach complete.")
33
34install_fail=$(gettext  "*** Attach FAILED ***")
35
36f_n_unimpl=$(gettext "The -n option is not yet implemented.")
37f_zfs=$(gettext "Error creating a ZFS file system (%s) for the zone.")
38f_nodataset=$(gettext "Error: there is no ZFS file system for the zone.")
39f_zfsdestroy=$(gettext "Error destroying ZFS file system %s.")
40
41f_sanity_notzone=$(gettext "Error: this is a system image and not a zone image.")
42
43f_baddir=$(gettext "Invalid '%s' directory within the zone")
44
45# Clean up on interrupt
46trap_cleanup()
47{
48	msg=$(gettext "Installation cancelled due to interrupt.")
49	log "$msg"
50
51	# umount any mounted file systems
52	umnt_fs
53
54	trap_exit
55}
56
57# If the attach failed then clean up the ZFS datasets we created.
58trap_exit()
59{
60	if [[ $EXIT_CODE != $ZONE_SUBPROC_OK && $rm_ds == 1 ]]; then
61		/usr/lib/brand/solaris10/uninstall $ZONENAME $ZONEPATH -F
62	fi
63
64	exit $EXIT_CODE
65}
66
67EXIT_CODE=$ZONE_SUBPROC_USAGE
68install_media="-"
69rm_ds=0
70
71trap trap_cleanup INT
72trap trap_exit EXIT
73
74# If we weren't passed at least two arguments, exit now.
75(( $# < 2 )) && exit $ZONE_SUBPROC_USAGE
76
77ZONENAME="$1"
78ZONEPATH="$2"
79# XXX shared/common script currently uses lower case zonename & zonepath
80zonename="$ZONENAME"
81zonepath="$ZONEPATH"
82
83shift; shift	# remove ZONENAME and ZONEPATH from arguments array
84
85ZONEROOT="$ZONEPATH/root"
86logdir="$ZONEROOT/var/log"
87
88noexecute=0
89
90unset inst_type
91
92# Other brand attach options are invalid for this brand.
93while getopts "a:d:nr:" opt; do
94	case $opt in
95		a)
96			if [[ -n "$inst_type" ]]; then
97				fatal "$incompat_options" "$m_usage"
98			fi
99		 	inst_type="archive"
100			install_media="$OPTARG"
101			;;
102		d)
103			if [[ -n "$inst_type" ]]; then
104				fatal "$incompat_options" "$m_usage"
105			fi
106		 	inst_type="directory"
107			install_media="$OPTARG"
108			# '-d -' means use the existing zonepath.
109			if [[ "$install_media" == "$ZONEPATH" ]]; then
110				install_media="-"
111			fi
112			;;
113		n)	noexecute=1 ;;
114		r)
115			if [[ -n "$inst_type" ]]; then
116				fatal "$incompat_options" "$m_usage"
117			fi
118		 	inst_type="stdin"
119			install_media="$OPTARG"
120			;;
121		?)	printf "$m_usage\n"
122			exit $ZONE_SUBPROC_USAGE;;
123		*)	printf "$m_usage\n"
124			exit $ZONE_SUBPROC_USAGE;;
125	esac
126done
127shift $((OPTIND-1))
128
129if [[ $noexecute == 1 && -n "$inst_type" ]]; then
130	fatal "$m_usage"
131fi
132
133if [ $noexecute -eq 1 ]; then
134	#
135	# The zone doesn't have to exist when the -n option is used, so do
136	# this work early.
137	#
138
139	# XXX do the sw validation for solaris10 minimal patch level to ensure
140	# everything will be ok.
141	EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE
142	fatal "$f_n_unimpl"
143fi
144
145EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE
146
147if [[ -z "$inst_type" ]]; then
148 	inst_type="directory"
149
150elif [[ "$install_media" != "-" ]]; then
151	#
152	# If we're not using a pre-existing zone directory layout then create
153	# the zone datasets and mount them.
154	#
155	unset DATASET
156	pdir=$(/usr/bin/dirname $ZONEPATH)
157	zds=$(/usr/sbin/zfs list -H -t filesystem -o name $pdir 2>/dev/null)
158	if (( $? == 0 )); then
159		pnm=$(/usr/bin/basename $ZONEPATH)
160		/usr/sbin/zfs create "$zds/$pnm"
161		if (( $? == 0 )); then
162			vlog "$m_zfs"
163			DATASET="$zds/$pnm"
164			rm_ds=1
165		else
166			log "$f_zfs" "$zds/$pnm"
167		fi
168	fi
169
170	create_active_ds
171fi
172
173#
174# The zone's datasets are now in place, validate that things
175# are setup correctly.
176#
177
178get_zonepath_ds $zonepath
179
180/usr/sbin/zfs list -H -o name $ZONEPATH_DS/ROOT >/dev/null 2>&1
181(( $? != 0 )) && fail_fatal "$f_no_active_ds"
182
183zfs set mountpoint=legacy $ZONEPATH_DS/ROOT >/dev/null 2>&1
184zfs set zoned=on $ZONEPATH_DS/ROOT >/dev/null 2>&1
185
186get_active_ds $ZONEPATH_DS
187zfs list -H -o name $ACTIVE_DS >/dev/null 2>&1
188(( $? != 0 )) && fail_fatal "$f_zfs_create"
189
190zfs set canmount=noauto $ACTIVE_DS >/dev/null 2>&1
191zfs inherit mountpoint $ACTIVE_DS >/dev/null 2>&1
192zfs inherit zoned $ACTIVE_DS >/dev/null 2>&1
193
194if [ ! -d $ZONEROOT ]; then
195	mkdir -p $ZONEROOT || fail_fatal "$f_mkdir" "$ZONEROOT"
196	chmod 700 $ZONEPATH || fail_fatal "$f_chmod" "$ZONEPATH"
197fi
198
199mnted=`zfs get -H mounted $ACTIVE_DS | cut -f3`
200if [[ $mnted = "no" ]]; then
201	mount -F zfs $ACTIVE_DS $ZONEROOT || fail_fatal "$f_zfs_mount"
202fi
203
204LOGFILE=$(/usr/bin/mktemp -t -p /var/tmp $zonename.attach_log.XXXXXX)
205if [[ -z "$LOGFILE" ]]; then
206	fatal "$e_tmpfile"
207fi
208exec 2>>"$LOGFILE"
209log "$m_attach_log" "$LOGFILE"
210
211log "$m_attaching"
212install_image "$inst_type" "$install_media"
213
214mk_zone_dirs
215
216#
217# Perform a final check that this is really a zone image and not an archive of
218# a system image which would need p2v.  Check for a well-known S10 SMF service
219# that shouldn't exist in a zone.
220#
221if [[ -e $ZONEROOT/var/svc/manifest/system/sysevent.xml ]]; then
222	log "$f_sanity_notzone"
223	exit $ZONE_SUBPROC_NOTCOMPLETE
224fi
225
226EXIT_CODE=$ZONE_SUBPROC_OK
227
228log "$m_complete"
229
230zone_logfile="${logdir}/$zonename.attach$$.log"
231
232safe_dir /var
233safe_dir /var/log
234safe_copy $LOGFILE $zone_logfile
235
236log "$m_attach_log" "$zone_logfile"
237rm -f $LOGFILE
238
239exit $ZONE_SUBPROC_OK
240