xref: /illumos-gate/usr/src/lib/brand/shared/zone/common.ksh (revision 6e1ae2a33c618c4c2b14aec7d2f21743ddea5837)
1edfa49ffS#
2edfa49ffS# CDDL HEADER START
3edfa49ffS#
4edfa49ffS# The contents of this file are subject to the terms of the
5edfa49ffS# Common Development and Distribution License (the "License").
6edfa49ffS# You may not use this file except in compliance with the License.
7edfa49ffS#
8edfa49ffS# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9edfa49ffS# or http://www.opensolaris.org/os/licensing.
10edfa49ffS# See the License for the specific language governing permissions
11edfa49ffS# and limitations under the License.
12edfa49ffS#
13edfa49ffS# When distributing Covered Code, include this CDDL HEADER in each
14edfa49ffS# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15edfa49ffS# If applicable, add the following below this CDDL HEADER, with the
16edfa49ffS# fields enclosed by brackets "[]" replaced with your own identifying
17edfa49ffS# information: Portions Copyright [yyyy] [name of copyright owner]
18edfa49ffS#
19edfa49ffS# CDDL HEADER END
20edfa49ffS#
21*6e1ae2a3SGary Pennington# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
22edfa49ffS#
23edfa49ffS
24edfa49ffS#
25edfa49ffS# Send the error message to the screen and to the logfile.
26edfa49ffS#
27edfa49ffSerror()
28edfa49ffS{
29edfa49ffS        typeset fmt="$1"
30edfa49ffS        shift
31edfa49ffS
32edfa49ffS        printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@"
33edfa49ffS        [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2
34edfa49ffS}
35edfa49ffS
36edfa49ffSfatal()
37edfa49ffS{
38edfa49ffS        typeset fmt="$1"
39edfa49ffS        shift
40edfa49ffS
41edfa49ffS	error "$fmt" "$@"
42edfa49ffS	exit $EXIT_CODE
43edfa49ffS}
44edfa49ffS
45e71ca95cSGerald Jelinekfail_fatal() {
46e71ca95cSGerald Jelinek	printf "ERROR: "
47e71ca95cSGerald Jelinek	printf "$@"
48e71ca95cSGerald Jelinek	printf "\n"
49e71ca95cSGerald Jelinek	exit $ZONE_SUBPROC_FATAL
50e71ca95cSGerald Jelinek}
51e71ca95cSGerald Jelinek
52edfa49ffS#
53edfa49ffS# Send the provided printf()-style arguments to the screen and to the logfile.
54edfa49ffS#
55edfa49ffSlog()
56edfa49ffS{
57edfa49ffS        typeset fmt="$1"
58edfa49ffS        shift
59edfa49ffS
60edfa49ffS        printf "${MSG_PREFIX}${fmt}\n" "$@"
61edfa49ffS        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
62edfa49ffS}
63edfa49ffS
64edfa49ffS#
65edfa49ffS# Print provided text to the screen if the shell variable "OPT_V" is set.
66edfa49ffS# The text is always sent to the logfile.
67edfa49ffS#
68edfa49ffSvlog()
69edfa49ffS{
70edfa49ffS        typeset fmt="$1"
71edfa49ffS        shift
72edfa49ffS
73edfa49ffS        [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@"
74edfa49ffS        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
75edfa49ffS}
76edfa49ffS
77e71ca95cSGerald Jelinek#
78edfa49ffS# Validate that the directory is safe.
79e71ca95cSGerald Jelinek#
80e71ca95cSGerald Jelinek# It is possible for a malicious zone root user to modify a zone's filesystem
81e71ca95cSGerald Jelinek# so that modifications made to the zone's filesystem by administrators in the
82e71ca95cSGerald Jelinek# global zone modify the global zone's filesystem.  We can prevent this by
83e71ca95cSGerald Jelinek# ensuring that all components of paths accessed by scripts are real (i.e.,
84e71ca95cSGerald Jelinek# non-symlink) directories.
85e71ca95cSGerald Jelinek#
86e71ca95cSGerald Jelinek# NOTE: The specified path should be an absolute path as would be seen from
87e71ca95cSGerald Jelinek# within the zone.  Also, this function does not check parent directories.
88e71ca95cSGerald Jelinek# If, for example, you need to ensure that every component of the path
89e71ca95cSGerald Jelinek# '/foo/bar/baz' is a directory and not a symlink, then do the following:
90e71ca95cSGerald Jelinek#
91e71ca95cSGerald Jelinek#	safe_dir /foo
92e71ca95cSGerald Jelinek#	safe_dir /foo/bar
93e71ca95cSGerald Jelinek#	safe_dir /foo/bar/baz
94e71ca95cSGerald Jelinek#
95edfa49ffSsafe_dir()
96edfa49ffS{
97edfa49ffS	typeset dir="$1"
98edfa49ffS
99edfa49ffS	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
100edfa49ffS		fatal "$e_baddir" "$dir"
101edfa49ffS	fi
102edfa49ffS}
103edfa49ffS
104e71ca95cSGerald Jelinek# Like safe_dir except the dir doesn't have to exist.
105e71ca95cSGerald Jelineksafe_opt_dir()
106e71ca95cSGerald Jelinek{
107e71ca95cSGerald Jelinek	typeset dir="$1"
108e71ca95cSGerald Jelinek
109e71ca95cSGerald Jelinek	[[ ! -e $ZONEROOT/$dir ]] && return
110e71ca95cSGerald Jelinek
111e71ca95cSGerald Jelinek	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
112e71ca95cSGerald Jelinek		fatal "$e_baddir" "$dir"
113e71ca95cSGerald Jelinek	fi
114e71ca95cSGerald Jelinek}
115e71ca95cSGerald Jelinek
116edfa49ffS# Only make a copy if we haven't already done so.
117edfa49ffSsafe_backup()
118edfa49ffS{
119edfa49ffS	typeset src="$1"
120edfa49ffS	typeset dst="$2"
121edfa49ffS
122edfa49ffS	if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then
123edfa49ffS		/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
124edfa49ffS	fi
125edfa49ffS}
126edfa49ffS
127edfa49ffS# Make a copy even if the destination already exists.
128edfa49ffSsafe_copy()
129edfa49ffS{
130edfa49ffS	typeset src="$1"
131edfa49ffS	typeset dst="$2"
132edfa49ffS
133edfa49ffS	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
134edfa49ffS		/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
135edfa49ffS	fi
136edfa49ffS}
137edfa49ffS
138edfa49ffS# Move a file
139edfa49ffSsafe_move()
140edfa49ffS{
141edfa49ffS	typeset src="$1"
142edfa49ffS	typeset dst="$2"
143edfa49ffS
144edfa49ffS	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
145edfa49ffS		/usr/bin/mv $src $dst || fatal "$e_badfile" "$src"
146edfa49ffS	fi
147edfa49ffS}
148edfa49ffS
149e71ca95cSGerald Jelineksafe_rm()
150e71ca95cSGerald Jelinek{
151e71ca95cSGerald Jelinek	if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then
152e71ca95cSGerald Jelinek		rm -f "$ZONEROOT/$1"
153e71ca95cSGerald Jelinek	fi
154e71ca95cSGerald Jelinek}
155e71ca95cSGerald Jelinek
156e71ca95cSGerald Jelinek#
157e71ca95cSGerald Jelinek# Replace the file with a wrapper pointing to the native brand code.
158e71ca95cSGerald Jelinek# However, we only do the replacement if the file hasn't already been
159e71ca95cSGerald Jelinek# replaced with our wrapper.  This function expects the cwd to be the
160e71ca95cSGerald Jelinek# location of the file we're replacing.
161e71ca95cSGerald Jelinek#
162e71ca95cSGerald Jelinek# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm'
163e71ca95cSGerald Jelinek# the file before we setup the wrapper while others are hardlinks to rc scripts
164e71ca95cSGerald Jelinek# that we need to maintain.
165e71ca95cSGerald Jelinek#
166e71ca95cSGerald Jelineksafe_replace()
167e71ca95cSGerald Jelinek{
168e71ca95cSGerald Jelinek	typeset filename="$1"
169e71ca95cSGerald Jelinek	typeset runname="$2"
170e71ca95cSGerald Jelinek	typeset mode="$3"
171e71ca95cSGerald Jelinek	typeset own="$4"
172e71ca95cSGerald Jelinek	typeset rem="$5"
173e71ca95cSGerald Jelinek
174e71ca95cSGerald Jelinek	if [ -h $filename -o ! -f $filename ]; then
175e71ca95cSGerald Jelinek		return
176e71ca95cSGerald Jelinek	fi
177e71ca95cSGerald Jelinek
178e71ca95cSGerald Jelinek	egrep -s "Solaris Brand Replacement" $filename
179e71ca95cSGerald Jelinek	if [ $? -eq 0 ]; then
180e71ca95cSGerald Jelinek		return
181e71ca95cSGerald Jelinek	fi
182e71ca95cSGerald Jelinek
183e71ca95cSGerald Jelinek	safe_backup $filename $filename.pre_p2v
184e71ca95cSGerald Jelinek	if [ $rem = "remove" ]; then
185e71ca95cSGerald Jelinek		rm -f $filename
186e71ca95cSGerald Jelinek	fi
187e71ca95cSGerald Jelinek
188e71ca95cSGerald Jelinek	cat <<-END >$filename || exit 1
1891022fd2aS	#!/bin/sh -p
190e71ca95cSGerald Jelinek	#
191e71ca95cSGerald Jelinek	# Solaris Brand Replacement
192e71ca95cSGerald Jelinek	#
193e71ca95cSGerald Jelinek	# Attention.  This file has been replaced with a new version for
194e71ca95cSGerald Jelinek	# use in a virtualized environment.  Modification of this script is not
195e71ca95cSGerald Jelinek	# supported and all changes will be lost upon reboot.  The
196e71ca95cSGerald Jelinek	# {name}.pre_p2v version of this file is a backup copy of the
197e71ca95cSGerald Jelinek	# original and should not be deleted.
198e71ca95cSGerald Jelinek	#
199e71ca95cSGerald Jelinek	END
200e71ca95cSGerald Jelinek
201e71ca95cSGerald Jelinek	echo ". $runname \"\$@\"" >>$filename || exit 1
202e71ca95cSGerald Jelinek
203e71ca95cSGerald Jelinek	chmod $mode $filename
204e71ca95cSGerald Jelinek	chown $own $filename
205e71ca95cSGerald Jelinek}
206e71ca95cSGerald Jelinek
207ae104932SJonathan Adamssafe_wrap()
208ae104932SJonathan Adams{
209ae104932SJonathan Adams	typeset filename="$1"
210ae104932SJonathan Adams	typeset runname="$2"
211ae104932SJonathan Adams	typeset mode="$3"
212ae104932SJonathan Adams	typeset own="$4"
213ae104932SJonathan Adams
214ae104932SJonathan Adams	if [ -f $filename ]; then
215ae104932SJonathan Adams		log "$e_cannot_wrap" "$filename"
216ae104932SJonathan Adams		exit 1
217ae104932SJonathan Adams	fi
218ae104932SJonathan Adams
219ae104932SJonathan Adams	cat <<-END >$filename || exit 1
220ae104932SJonathan Adams	#!/bin/sh
221ae104932SJonathan Adams	#
222ae104932SJonathan Adams	# Solaris Brand Wrapper
223ae104932SJonathan Adams	#
224ae104932SJonathan Adams	# Attention.  This file has been created for use in a
225ae104932SJonathan Adams	# virtualized environment.  Modification of this script
226ae104932SJonathan Adams	# is not supported and all changes will be lost upon reboot.
227ae104932SJonathan Adams	#
228ae104932SJonathan Adams	END
229ae104932SJonathan Adams
230ae104932SJonathan Adams	echo ". $runname \"\$@\"" >>$filename || exit 1
231ae104932SJonathan Adams
232ae104932SJonathan Adams	chmod $mode $filename
233ae104932SJonathan Adams	chown $own $filename
234ae104932SJonathan Adams}
235ae104932SJonathan Adams
236edfa49ffS#
237*6e1ae2a3SGary Pennington# Read zonecfg fs entries and save the relevant data, one entry per
238edfa49ffS# line.
239edfa49ffS# This assumes the properties from the zonecfg output, e.g.:
240edfa49ffS#	fs:
241edfa49ffS#		dir: /opt
242edfa49ffS#		special: /opt
243edfa49ffS#		raw not specified
244edfa49ffS#		type: lofs
245edfa49ffS#		options: [noexec,ro,noatime]
246edfa49ffS#
247*6e1ae2a3SGary Pennington# and it assumes the order of the fs properties as above.
248edfa49ffS#
249edfa49ffSget_fs_info()
250edfa49ffS{
251edfa49ffS	zonecfg -z $zonename info fs | nawk '{
252edfa49ffS		if ($1 == "options:") {
253edfa49ffS			# Remove brackets.
254edfa49ffS			options=substr($2, 2, length($2) - 2);
255edfa49ffS			printf("%s %s %s %s\n", dir, type, special, options);
256edfa49ffS		} else if ($1 == "dir:") {
257edfa49ffS			dir=$2;
258edfa49ffS		} else if ($1 == "special:") {
259edfa49ffS			special=$2;
260edfa49ffS		} else if ($1 == "type:") {
261edfa49ffS			type=$2
262edfa49ffS		}
263edfa49ffS	}' >> $fstmpfile
264edfa49ffS}
265edfa49ffS
266edfa49ffS#
267edfa49ffS# Mount zonecfg fs entries into the zonepath.
268edfa49ffS#
269edfa49ffSmnt_fs()
270edfa49ffS{
271edfa49ffS	if [ ! -s $fstmpfile ]; then
272edfa49ffS		return;
273edfa49ffS	fi
274edfa49ffS
275edfa49ffS	# Sort the fs entries so we can handle nested mounts.
276edfa49ffS	sort $fstmpfile | nawk -v zonepath=$zonepath '{
277edfa49ffS		if (NF == 4)
278edfa49ffS			options="-o " $4;
279edfa49ffS		else
280edfa49ffS			options=""
281edfa49ffS
282edfa49ffS		# Create the mount point.  Ignore errors since we might have
283edfa49ffS		# a nested mount with a pre-existing mount point.
284edfa49ffS		cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1"
285edfa49ffS		system(cmd);
286edfa49ffS
287edfa49ffS		cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \
288edfa49ffS		    zonepath "/root" $1;
289edfa49ffS		if (system(cmd) != 0) {
290edfa49ffS			printf("command failed: %s\n", cmd);
291edfa49ffS			exit 1;
292edfa49ffS		}
293edfa49ffS	}' >>$LOGFILE
294edfa49ffS}
295edfa49ffS
296edfa49ffS#
297edfa49ffS# Unmount zonecfg fs entries from the zonepath.
298edfa49ffS#
299edfa49ffSumnt_fs()
300edfa49ffS{
301edfa49ffS	if [ ! -s $fstmpfile ]; then
302edfa49ffS		return;
303edfa49ffS	fi
304edfa49ffS
305edfa49ffS	# Reverse sort the fs entries so we can handle nested unmounts.
306edfa49ffS	sort -r $fstmpfile | nawk -v zonepath=$zonepath '{
307edfa49ffS		cmd="/usr/sbin/umount " zonepath "/root" $1
308edfa49ffS		if (system(cmd) != 0) {
309edfa49ffS			printf("command failed: %s\n", cmd);
310edfa49ffS		}
311edfa49ffS	}' >>$LOGFILE
312edfa49ffS}
313edfa49ffS
314e71ca95cSGerald Jelinek# Find the dataset mounted on the zonepath.
315e71ca95cSGerald Jelinekget_zonepath_ds() {
316e71ca95cSGerald Jelinek	ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \
317e71ca95cSGerald Jelinek	    /usr/bin/nawk -v zonepath=$1 '{
318e71ca95cSGerald Jelinek		if ($2 == zonepath)
319e71ca95cSGerald Jelinek			print $1
320e71ca95cSGerald Jelinek	}'`
321e71ca95cSGerald Jelinek
322e71ca95cSGerald Jelinek	if [ -z "$ZONEPATH_DS" ]; then
323e71ca95cSGerald Jelinek		fail_fatal "$f_no_ds"
324e71ca95cSGerald Jelinek	fi
325e71ca95cSGerald Jelinek}
326e71ca95cSGerald Jelinek
327eba00995S#
328eba00995S# Perform any cleanup in the zoneroot after unpacking the archive.
329eba00995S#
330eba00995Spost_unpack()
331eba00995S{
332eba00995S	( cd "$ZONEROOT" && \
333eba00995S	    find . \( -type b -o -type c \) -exec rm -f "{}" \; )
334eba00995S}
335eba00995S
336edfa49ffS#
337edfa49ffS# Determine flar compression style from identification file.
338edfa49ffS#
339edfa49ffSget_compression()
340edfa49ffS{
341edfa49ffS	typeset ident=$1
342edfa49ffS	typeset line=$(grep "^files_compressed_method=" $ident)
343edfa49ffS
344edfa49ffS	print ${line##*=}
345edfa49ffS}
346edfa49ffS
347edfa49ffS#
348edfa49ffS# Determine flar archive style from identification file.
349edfa49ffS#
350edfa49ffSget_archiver()
351edfa49ffS{
352edfa49ffS        typeset ident=$1
353edfa49ffS        typeset line=$(grep "^files_archived_method=" $ident)
354edfa49ffS
355edfa49ffS        print ${line##*=}
356edfa49ffS}
357edfa49ffS
358edfa49ffS#
359edfa49ffS# Unpack flar into current directory (which should be zoneroot).  The flash
360edfa49ffS# archive is standard input.  See flash_archive(4) man page.
361edfa49ffS#
362edfa49ffS# We can't use "flar split" since it will only unpack into a directory called
363edfa49ffS# "archive".  We need to unpack in place in order to properly handle nested
364edfa49ffS# fs mounts within the zone root.  This function does the unpacking into the
365edfa49ffS# current directory.
366edfa49ffS#
367edfa49ffS# This code is derived from the gen_split() function in /usr/sbin/flar so
368edfa49ffS# we keep the same style as the original.
369edfa49ffS#
370edfa49ffSinstall_flar()
371edfa49ffS{
372edfa49ffS	typeset result
373edfa49ffS        typeset archiver_command
374edfa49ffS        typeset archiver_arguments
375edfa49ffS
37674bbcaa8S	vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar"
377edfa49ffS
378edfa49ffS	# Read cookie
379edfa49ffS	read -r input_line
380edfa49ffS	if (( $? != 0 )); then
381edfa49ffS		log "$not_readable" "$install_media"
382edfa49ffS		return 1
383edfa49ffS	fi
384edfa49ffS	# The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers.
385edfa49ffS	if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then
386edfa49ffS		log "$not_flar"
387edfa49ffS		return 1
388edfa49ffS	fi
389edfa49ffS
390edfa49ffS	while [ true ]
391edfa49ffS	do
392edfa49ffS		# We should always be at the start of a section here
393edfa49ffS		read -r input_line
394edfa49ffS		if [[ ${input_line%%=*} != "section_begin" ]]; then
395edfa49ffS			log "$bad_flar"
396edfa49ffS			return 1
397edfa49ffS		fi
398edfa49ffS		section_name=${input_line##*=}
399edfa49ffS
400edfa49ffS		# If we're at the archive, we're done skipping sections.
401edfa49ffS		if [[ "$section_name" == "archive" ]]; then
402edfa49ffS			break
403edfa49ffS		fi
404edfa49ffS
405edfa49ffS		#
406edfa49ffS		# Save identification section to a file so we can determine
407edfa49ffS		# how to unpack the archive.
408edfa49ffS		#
409edfa49ffS		if [[ "$section_name" == "identification" ]]; then
410edfa49ffS			/usr/bin/rm -f identification
411edfa49ffS			while read -r input_line
412edfa49ffS			do
413edfa49ffS				if [[ ${input_line%%=*} == \
414edfa49ffS				    "section_begin" ]]; then
415edfa49ffS					/usr/bin/rm -f identification
416edfa49ffS					log "$bad_flar"
417edfa49ffS					return 1
418edfa49ffS				fi
419edfa49ffS
420edfa49ffS				if [[ $input_line == \
421edfa49ffS				    "section_end=$section_name" ]]; then
422edfa49ffS					break;
423edfa49ffS				fi
424edfa49ffS				echo $input_line >> identification
425edfa49ffS			done
426edfa49ffS
427edfa49ffS			continue
428edfa49ffS		fi
429edfa49ffS
430edfa49ffS		#
431edfa49ffS		# Otherwise skip past this section; read lines until detecting
432edfa49ffS		# section_end.  According to flash_archive(4) we can have
433edfa49ffS		# an arbitrary number of sections but the archive section
434edfa49ffS		# must be last.
435edfa49ffS		#
436edfa49ffS		success=0
437edfa49ffS		while read -r input_line
438edfa49ffS		do
439edfa49ffS			if [[ $input_line == "section_end=$section_name" ]];
440edfa49ffS			then
441edfa49ffS				success=1
442edfa49ffS				break
443edfa49ffS			fi
444edfa49ffS			# Fail if we miss the end of the section
445edfa49ffS			if [[ ${input_line%%=*} == "section_begin" ]]; then
446edfa49ffS				/usr/bin/rm -f identification
447edfa49ffS				log "$bad_flar"
448edfa49ffS				return 1
449edfa49ffS			fi
450edfa49ffS		done
451edfa49ffS		if (( $success == 0 )); then
452edfa49ffS			#
453edfa49ffS			# If we get here we read to the end of the file before
454edfa49ffS			# seeing the end of the section we were reading.
455edfa49ffS			#
456edfa49ffS			/usr/bin/rm -f identification
457edfa49ffS			log "$bad_flar"
458edfa49ffS			return 1
459edfa49ffS		fi
460edfa49ffS	done
461edfa49ffS
462cec6066bS	# Check for an archive made from a ZFS root pool.
463cec6066bS	egrep -s "^rootpool=" identification
464cec6066bS        if (( $? == 0 )); then
465cec6066bS		/usr/bin/rm -f identification
466cec6066bS                log "$bad_zfs_flar"
467cec6066bS                return 1
468cec6066bS        fi
469cec6066bS
470edfa49ffS	# Get the information needed to unpack the archive.
471edfa49ffS	archiver=$(get_archiver identification)
472edfa49ffS	if [[ $archiver == "pax" ]]; then
473edfa49ffS		# pax archiver specified
474edfa49ffS		archiver_command="/usr/bin/pax"
475*6e1ae2a3SGary Pennington		if [[ -s $fspaxfile ]]; then
476edfa49ffS			archiver_arguments="-r -p e -c \
477*6e1ae2a3SGary Pennington			    $(/usr/bin/cat $fspaxfile)"
478edfa49ffS		else
479edfa49ffS			archiver_arguments="-r -p e"
480edfa49ffS		fi
481edfa49ffS	elif [[ $archiver == "cpio" || -z $archiver ]]; then
482edfa49ffS		# cpio archived specified OR no archiver specified - use default
483edfa49ffS		archiver_command="/usr/bin/cpio"
484*6e1ae2a3SGary Pennington		archiver_arguments="-icdumfE $fscpiofile"
485edfa49ffS	else
486edfa49ffS		# unknown archiver specified
487edfa49ffS		log "$unknown_archiver" $archiver
488edfa49ffS		return 1
489edfa49ffS	fi
490edfa49ffS
491edfa49ffS	if [[ ! -x $archiver_command ]]; then
492edfa49ffS		/usr/bin/rm -f identification
493edfa49ffS		log "$cmd_not_exec" $archiver_command
494edfa49ffS		return 1
495edfa49ffS	fi
496edfa49ffS
497edfa49ffS	compression=$(get_compression identification)
498edfa49ffS
499edfa49ffS	# We're done with the identification file
500edfa49ffS	/usr/bin/rm -f identification
501edfa49ffS
502edfa49ffS	# Extract archive
503edfa49ffS	if [[ $compression == "compress" ]]; then
504eba00995S		/usr/bin/zcat | \
505edfa49ffS		    $archiver_command $archiver_arguments 2>/dev/null
506edfa49ffS	else
507eba00995S		$archiver_command $archiver_arguments 2>/dev/null
508edfa49ffS	fi
509edfa49ffS	result=$?
510edfa49ffS
511eba00995S	post_unpack
512eba00995S
513edfa49ffS	(( $result != 0 )) && return 1
514edfa49ffS
515edfa49ffS	return 0
516edfa49ffS}
517edfa49ffS
5188c20418dSGerald Jelinek#
5198c20418dSGerald Jelinek# Get the archive base.
5208c20418dSGerald Jelinek#
5218c20418dSGerald Jelinek# We must unpack the archive in the right place within the zonepath so
5228c20418dSGerald Jelinek# that files are installed into the various mounted filesystems that are set
5238c20418dSGerald Jelinek# up in the zone's configuration.  These are already mounted for us by the
5248c20418dSGerald Jelinek# mntfs function.
5258c20418dSGerald Jelinek#
5268c20418dSGerald Jelinek# Archives can be made of either a physical host's root file system or a
5278c20418dSGerald Jelinek# zone's zonepath.  For a physical system, if the archive is made using an
5288c20418dSGerald Jelinek# absolute path (/...) we can't use it.  For a zone the admin can make the
5298c20418dSGerald Jelinek# archive from a variety of locations;
5308c20418dSGerald Jelinek#
5318c20418dSGerald Jelinek#   a) zonepath itself: This will be a single dir, probably named with the
5328c20418dSGerald Jelinek#      zone name, it will contain a root dir and under the root we'll see all
5338c20418dSGerald Jelinek#      the top level dirs; etc, var, usr...  We must be above the ZONEPATH
5348c20418dSGerald Jelinek#      when we unpack the archive but this will only work if the the archive's
5358c20418dSGerald Jelinek#      top-level dir name matches the ZONEPATH base-level dir name.  If not,
5368c20418dSGerald Jelinek#      this is an error.
5378c20418dSGerald Jelinek#
5388c20418dSGerald Jelinek#   b) inside the zonepath: We'll see root and it will contain all the top
5398c20418dSGerald Jelinek#      level dirs; etc, var, usr....  We must be in the ZONEPATH when we unpack
5408c20418dSGerald Jelinek#      the archive.
5418c20418dSGerald Jelinek#
5428c20418dSGerald Jelinek#   c) inside the zonepath root: We'll see all the top level dirs, ./etc,
5438c20418dSGerald Jelinek#      ./var, ./usr....  This is also the case we see when we get an archive
5448c20418dSGerald Jelinek#      of a physical sytem.  We must be in ZONEROOT when we unpack the archive.
5458c20418dSGerald Jelinek#
5468c20418dSGerald Jelinek# Note that there can be a directory named "root" under the ZONEPATH/root
5478c20418dSGerald Jelinek# directory.
5488c20418dSGerald Jelinek#
5498c20418dSGerald Jelinek# This function handles the above possibilities so that we reject absolute
5508c20418dSGerald Jelinek# path archives and figure out where in the file system we need to be to
5518c20418dSGerald Jelinek# properly unpack the archive into the zone.  It sets the ARCHIVE_BASE
5528c20418dSGerald Jelinek# variable to the location where the achive should be unpacked.
5538c20418dSGerald Jelinek#
5548c20418dSGerald Jelinekget_archive_base()
5558c20418dSGerald Jelinek{
5568c20418dSGerald Jelinek	stage1=$1
5578c20418dSGerald Jelinek	archive=$2
5588c20418dSGerald Jelinek	stage2=$3
5598c20418dSGerald Jelinek
5608c20418dSGerald Jelinek	vlog "$m_analyse_archive"
5618c20418dSGerald Jelinek
5628c20418dSGerald Jelinek	base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{
5638c20418dSGerald Jelinek		# Check for an absolute path archive
5648c20418dSGerald Jelinek		if (substr($0, 1, 1) == "/")
5658c20418dSGerald Jelinek			exit 1
5668c20418dSGerald Jelinek
5678c20418dSGerald Jelinek		if ($1 != ".")
5688c20418dSGerald Jelinek			dirs[$1] = 1
5698c20418dSGerald Jelinek		else
5708c20418dSGerald Jelinek			dirs[$2] = 1
5718c20418dSGerald Jelinek	}
5728c20418dSGerald Jelinek	END {
5738c20418dSGerald Jelinek		for (d in dirs) {
5748c20418dSGerald Jelinek			cnt++
5758c20418dSGerald Jelinek			if (d == "bin")  sawbin = 1
5768c20418dSGerald Jelinek			if (d == "etc")  sawetc = 1
5778c20418dSGerald Jelinek			if (d == "root") sawroot = 1
5788c20418dSGerald Jelinek			if (d == "var")  sawvar = 1
5798c20418dSGerald Jelinek                }
5808c20418dSGerald Jelinek
5818c20418dSGerald Jelinek		if (cnt == 1) {
5828c20418dSGerald Jelinek			# If only one top-level dir named root, we are in the
5838c20418dSGerald Jelinek			# zonepath, otherwise this must be an archive *of*
5848c20418dSGerald Jelinek			# the zonepath so print the top-level dir name.
5858c20418dSGerald Jelinek			if (sawroot)
5868c20418dSGerald Jelinek				print "*zonepath*"
5878c20418dSGerald Jelinek			else
5888c20418dSGerald Jelinek				for (d in dirs) print d
5898c20418dSGerald Jelinek		} else {
5908c20418dSGerald Jelinek			# We are either in the zonepath or in the zonepath/root
5918c20418dSGerald Jelinek			# (or at the top level of a full system archive which
5928c20418dSGerald Jelinek			# looks like the zonepath/root case).  Figure out which
5938c20418dSGerald Jelinek			# one.
5948c20418dSGerald Jelinek			if (sawroot && !sawbin && !sawetc && !sawvar)
5958c20418dSGerald Jelinek				print "*zonepath*"
5968c20418dSGerald Jelinek			else
5978c20418dSGerald Jelinek				print "*zoneroot*"
5988c20418dSGerald Jelinek		}
5998c20418dSGerald Jelinek	}'`
6008c20418dSGerald Jelinek
6018c20418dSGerald Jelinek	if (( $? != 0 )); then
6028c20418dSGerald Jelinek		umnt_fs
6038c20418dSGerald Jelinek		fatal "$e_absolute_archive"
6048c20418dSGerald Jelinek	fi
6058c20418dSGerald Jelinek
6068c20418dSGerald Jelinek	if [[ "$base" == "*zoneroot*" ]]; then
6078c20418dSGerald Jelinek		ARCHIVE_BASE=$ZONEROOT
6088c20418dSGerald Jelinek	elif [[ "$base" == "*zonepath*" ]]; then
6098c20418dSGerald Jelinek		ARCHIVE_BASE=$ZONEPATH
6108c20418dSGerald Jelinek	else
6118c20418dSGerald Jelinek		# We need to be in the dir above the ZONEPATH but we need to
6128c20418dSGerald Jelinek		# validate that $base matches the final component of ZONEPATH.
6138c20418dSGerald Jelinek		bname=`basename $ZONEPATH`
6148c20418dSGerald Jelinek
6158c20418dSGerald Jelinek		if [[ "$bname" != "$base" ]]; then
6168c20418dSGerald Jelinek			umnt_fs
6178c20418dSGerald Jelinek			fatal "$e_mismatch_archive" "$base" "$bname"
6188c20418dSGerald Jelinek		fi
6198c20418dSGerald Jelinek		ARCHIVE_BASE=`dirname $ZONEPATH`
6208c20418dSGerald Jelinek	fi
6218c20418dSGerald Jelinek}
6228c20418dSGerald Jelinek
623edfa49ffS#
624edfa49ffS# Unpack cpio archive into zoneroot.
625edfa49ffS#
626edfa49ffSinstall_cpio()
627edfa49ffS{
628edfa49ffS	stage1=$1
629edfa49ffS	archive=$2
630edfa49ffS
6318c20418dSGerald Jelinek	get_archive_base "$stage1" "$archive" "cpio -it"
63262ac5336S
633*6e1ae2a3SGary Pennington	cpioopts="-idmfE $fscpiofile"
634edfa49ffS
6358c20418dSGerald Jelinek	vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts"
636eba00995S
637cec6066bS	# Ignore errors from cpio since we expect some errors depending on
638cec6066bS	# how the archive was made.
6398c20418dSGerald Jelinek	( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts )
640eba00995S
641eba00995S	post_unpack
642edfa49ffS
643cec6066bS	return 0
644edfa49ffS}
645edfa49ffS
646edfa49ffS#
647edfa49ffS# Unpack pax archive into zoneroot.
648edfa49ffS#
649edfa49ffSinstall_pax()
650edfa49ffS{
651edfa49ffS	archive=$1
652edfa49ffS
6538c20418dSGerald Jelinek	get_archive_base "cat" "$archive" "pax"
65462ac5336S
655*6e1ae2a3SGary Pennington	if [[ -s $fspaxfile ]]; then
656*6e1ae2a3SGary Pennington		filtopt="-c $(/usr/bin/cat $fspaxfile)"
657edfa49ffS	fi
658edfa49ffS
6598c20418dSGerald Jelinek	vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt"
660edfa49ffS
661cec6066bS	# Ignore errors from pax since we expect some errors depending on
662cec6066bS	# how the archive was made.
6638c20418dSGerald Jelinek	( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt )
664eba00995S
665eba00995S	post_unpack
666eba00995S
667cec6066bS	return 0
668edfa49ffS}
669edfa49ffS
670edfa49ffS#
671edfa49ffS# Unpack UFS dump into zoneroot.
672edfa49ffS#
673edfa49ffSinstall_ufsdump()
674edfa49ffS{
675edfa49ffS	archive=$1
676edfa49ffS
677eba00995S	vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\""
678edfa49ffS
679edfa49ffS	#
680edfa49ffS	# ufsrestore goes interactive if you ^C it.  To prevent that,
681edfa49ffS	# we make sure its stdin is not a terminal.
682edfa49ffS	#
683eba00995S	( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
684eba00995S	result=$?
685eba00995S
686eba00995S	post_unpack
687eba00995S
688eba00995S	return $result
689edfa49ffS}
690edfa49ffS
691edfa49ffS#
692edfa49ffS# Copy directory hierarchy into zoneroot.
693edfa49ffS#
694edfa49ffSinstall_dir()
695edfa49ffS{
696edfa49ffS	source_dir=$1
697edfa49ffS
698edfa49ffS	cpioopts="-pdm"
699edfa49ffS
700edfa49ffS	first=1
701*6e1ae2a3SGary Pennington	filt=$(for i in $(cat $fspaxfile)
702edfa49ffS		do
703edfa49ffS			echo $i | egrep -s "/" && continue
704edfa49ffS			if [[ $first == 1 ]]; then
705edfa49ffS				printf "^%s" $i
706edfa49ffS				first=0
707edfa49ffS			else
708edfa49ffS				printf "|^%s" $i
709edfa49ffS			fi
710edfa49ffS		done)
711edfa49ffS
712edfa49ffS	list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
713edfa49ffS	flist=$(for i in $list
714edfa49ffS	do
715edfa49ffS		printf "%s " "$i"
716edfa49ffS	done)
717edfa49ffS	findopts="-xdev ( -type d -o -type f -o -type l ) -print"
718edfa49ffS
719edfa49ffS	vlog "cd \"$source_dir\" && find $flist $findopts | "
720eba00995S	vlog "cpio $cpioopts \"$ZONEROOT\""
721edfa49ffS
722cec6066bS	# Ignore errors from cpio since we expect some errors depending on
723cec6066bS	# how the archive was made.
724edfa49ffS	( cd "$source_dir" && find $flist $findopts | \
725eba00995S	    cpio $cpioopts "$ZONEROOT" )
726eba00995S
727eba00995S	post_unpack
728eba00995S
729cec6066bS	return 0
730edfa49ffS}
731edfa49ffS
73274bbcaa8S#
73374bbcaa8S# This is a common function for laying down a zone image from a variety of
73474bbcaa8S# different sources.  This can be used to either install a fresh zone or as
73574bbcaa8S# part of zone migration during attach.
73674bbcaa8S#
73774bbcaa8S# The first argument specifies the type of image: archive, directory or stdin.
73874bbcaa8S# The second argument specifies the image itself.  In the case of stdin, the
73974bbcaa8S# second argument specifies the format of the stream (cpio, flar, etc.).
74074bbcaa8S# Any validation or post-processing on the image is done elsewhere.
74174bbcaa8S#
74274bbcaa8S# This function calls a 'sanity_check' function which must be provided by
74374bbcaa8S# the script which includes this code.
74474bbcaa8S#
74574bbcaa8Sinstall_image()
74674bbcaa8S{
74774bbcaa8S	intype=$1
74874bbcaa8S	insrc=$2
74974bbcaa8S
75074bbcaa8S	if [[ -z "$intype" || -z "$insrc" ]]; then
75174bbcaa8S		return 1
75274bbcaa8S	fi
75374bbcaa8S
75474bbcaa8S	filetype="unknown"
75574bbcaa8S	filetypename="unknown"
75674bbcaa8S	stage1="cat"
75774bbcaa8S
75874bbcaa8S	if [[ "$intype" == "directory" ]]; then
75974bbcaa8S		if [[ "$insrc" == "-" ]]; then
76074bbcaa8S			# Indicates that the existing zonepath is prepopulated.
76174bbcaa8S			filetype="existing"
76274bbcaa8S			filetypename="existing"
76374bbcaa8S		else
76474bbcaa8S			if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
76574bbcaa8S				fatal "$e_path_abs" "$insrc"
76674bbcaa8S			fi
76774bbcaa8S
76874bbcaa8S			if [[ ! -e "$insrc" ]]; then
76974bbcaa8S				log "$e_not_found" "$insrc"
77074bbcaa8S				fatal "$e_install_abort"
77174bbcaa8S			fi
77274bbcaa8S
77374bbcaa8S			if [[ ! -r "$insrc" ]]; then
77474bbcaa8S				log "$e_not_readable" "$insrc"
77574bbcaa8S				fatal "$e_install_abort"
77674bbcaa8S			fi
77774bbcaa8S
77874bbcaa8S			if [[ ! -d "$insrc" ]]; then
77974bbcaa8S				log "$e_not_dir"
78074bbcaa8S				fatal "$e_install_abort"
78174bbcaa8S			fi
78274bbcaa8S
78374bbcaa8S			sanity_check $insrc
78474bbcaa8S
78574bbcaa8S			filetype="directory"
78674bbcaa8S			filetypename="directory"
78774bbcaa8S		fi
78874bbcaa8S
78974bbcaa8S	else
79074bbcaa8S		# Common code for both archive and stdin stream.
79174bbcaa8S
79274bbcaa8S		if [[ "$intype" == "archive" ]]; then
79374bbcaa8S			if [[ ! -f "$insrc" ]]; then
79474bbcaa8S				log "$e_unknown_archive"
79574bbcaa8S				fatal "$e_install_abort"
79674bbcaa8S			fi
79774bbcaa8S			ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
79874bbcaa8S		else
79974bbcaa8S			# For intype == stdin, the insrc parameter specifies
80074bbcaa8S			# the stream format coming on stdin.
80174bbcaa8S			ftype="$insrc"
80274bbcaa8S			insrc="-"
80374bbcaa8S		fi
80474bbcaa8S
80574bbcaa8S		# Setup vars for the archive type we have.
80674bbcaa8S		case "$ftype" in
80774bbcaa8S		*cpio*)		filetype="cpio"
80874bbcaa8S				filetypename="cpio archive"
80974bbcaa8S			;;
81074bbcaa8S		*bzip2*)	filetype="bzip2"
81174bbcaa8S				filetypename="bzipped cpio archive"
81274bbcaa8S			;;
81374bbcaa8S		*gzip*)		filetype="gzip"
81474bbcaa8S				filetypename="gzipped cpio archive"
81574bbcaa8S			;;
81674bbcaa8S		*ufsdump*)	filetype="ufsdump"
81774bbcaa8S				filetypename="ufsdump archive"
81874bbcaa8S			;;
81974bbcaa8S		"flar")
82074bbcaa8S				filetype="flar"
82174bbcaa8S				filetypename="flash archive"
82274bbcaa8S			;;
82374bbcaa8S		"flash")
82474bbcaa8S				filetype="flar"
82574bbcaa8S				filetypename="flash archive"
82674bbcaa8S			;;
82774bbcaa8S		*Flash\ Archive*)
82874bbcaa8S				filetype="flar"
82974bbcaa8S				filetypename="flash archive"
83074bbcaa8S			;;
83174bbcaa8S		"tar")
83274bbcaa8S				filetype="tar"
83374bbcaa8S				filetypename="tar archive"
83474bbcaa8S			;;
83574bbcaa8S		*USTAR\ tar\ archive)
83674bbcaa8S				filetype="tar"
83774bbcaa8S				filetypename="tar archive"
83874bbcaa8S			;;
83974bbcaa8S		"pax")
84074bbcaa8S				filetype="xustar"
84174bbcaa8S				filetypename="pax (xustar) archive"
84274bbcaa8S			;;
84374bbcaa8S		*USTAR\ tar\ archive\ extended\ format*)
84474bbcaa8S				filetype="xustar"
84574bbcaa8S				filetypename="pax (xustar) archive"
84674bbcaa8S			;;
84774bbcaa8S		"zfs")
84874bbcaa8S				filetype="zfs"
84974bbcaa8S				filetypename="ZFS send stream"
85074bbcaa8S			;;
85174bbcaa8S		*ZFS\ snapshot\ stream*)
85274bbcaa8S				filetype="zfs"
85374bbcaa8S				filetypename="ZFS send stream"
85474bbcaa8S			;;
85574bbcaa8S		*)		log "$e_unknown_archive"
85674bbcaa8S				fatal "$e_install_abort"
85774bbcaa8S			;;
85874bbcaa8S		esac
85974bbcaa8S	fi
86074bbcaa8S
86174bbcaa8S	vlog "$filetypename"
86274bbcaa8S
86374bbcaa8S	# Check for a non-empty root if no '-d -' option.
86474bbcaa8S	if [[ "$filetype" != "existing" ]]; then
86574bbcaa8S		cnt=$(ls $ZONEROOT | wc -l)
86674bbcaa8S		if (( $cnt != 0 )); then
86774bbcaa8S			fatal "$e_root_full" "$ZONEROOT"
86874bbcaa8S		fi
86974bbcaa8S	fi
87074bbcaa8S
87174bbcaa8S	fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
87274bbcaa8S	if [[ -z "$fstmpfile" ]]; then
87374bbcaa8S		fatal "$e_tmpfile"
87474bbcaa8S	fi
87574bbcaa8S
87674bbcaa8S	# Make sure we always have the files holding the directories to filter
87774bbcaa8S	# out when extracting from a CPIO or PAX archive.  We'll add the fs
878*6e1ae2a3SGary Pennington	# entries to these files in get_fs_info()
879*6e1ae2a3SGary Pennington	fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX)
880*6e1ae2a3SGary Pennington	if [[ -z "$fscpiofile" ]]; then
88174bbcaa8S		rm -f $fstmpfile
88274bbcaa8S		fatal "$e_tmpfile"
88374bbcaa8S	fi
88474bbcaa8S
885*6e1ae2a3SGary Pennington	# Filter out these directories.
886*6e1ae2a3SGary Pennington	echo 'dev/*' >>$fscpiofile
887*6e1ae2a3SGary Pennington	echo 'devices/*' >>$fscpiofile
888*6e1ae2a3SGary Pennington	echo 'devices' >>$fscpiofile
889*6e1ae2a3SGary Pennington	echo 'proc/*' >>$fscpiofile
890*6e1ae2a3SGary Pennington	echo 'tmp/*' >>$fscpiofile
891*6e1ae2a3SGary Pennington	echo 'var/run/*' >>$fscpiofile
892*6e1ae2a3SGary Pennington	echo 'system/contract/*' >>$fscpiofile
893*6e1ae2a3SGary Pennington	echo 'system/object/*' >>$fscpiofile
894*6e1ae2a3SGary Pennington
895*6e1ae2a3SGary Pennington	fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX)
896*6e1ae2a3SGary Pennington	if [[ -z "$fspaxfile" ]]; then
897*6e1ae2a3SGary Pennington		rm -f $fstmpfile $fscpiofile
89874bbcaa8S		fatal "$e_tmpfile"
89974bbcaa8S	fi
90074bbcaa8S
90174bbcaa8S	printf "%s " \
90274bbcaa8S	    "dev devices proc tmp var/run system/contract system/object" \
903*6e1ae2a3SGary Pennington	    >>$fspaxfile
90474bbcaa8S
90574bbcaa8S	# Set up any fs mounts so the archive will install into the correct
90674bbcaa8S	# locations.
90774bbcaa8S	get_fs_info
90874bbcaa8S	mnt_fs
90974bbcaa8S	if (( $? != 0 )); then
91074bbcaa8S		umnt_fs >/dev/null 2>&1
911*6e1ae2a3SGary Pennington		rm -f $fstmpfile $fscpiofile $fspaxfile
91274bbcaa8S		fatal "$mount_failed"
91374bbcaa8S	fi
91474bbcaa8S
91574bbcaa8S	if [[ "$filetype" == "existing" ]]; then
91674bbcaa8S		log "$no_installing"
91774bbcaa8S	else
91874bbcaa8S		log "$installing"
91974bbcaa8S	fi
92074bbcaa8S
92174bbcaa8S	#
92274bbcaa8S	# Install the image into the zonepath.
92374bbcaa8S	#
92474bbcaa8S	unpack_result=0
92574bbcaa8S	stage1="cat"
92674bbcaa8S	if [[ "$filetype" == "gzip" ]]; then
92774bbcaa8S		stage1="gzcat"
92874bbcaa8S		filetype="cpio"
92974bbcaa8S	elif [[ "$filetype" == "bzip2" ]]; then
93074bbcaa8S		stage1="bzcat"
93174bbcaa8S		filetype="cpio"
93274bbcaa8S	fi
93374bbcaa8S
93474bbcaa8S	if [[ "$filetype" == "cpio" ]]; then
93574bbcaa8S		install_cpio "$stage1" "$insrc"
93674bbcaa8S		unpack_result=$?
93774bbcaa8S
93874bbcaa8S	elif [[ "$filetype" == "flar" ]]; then
93974bbcaa8S		( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
94074bbcaa8S		unpack_result=$?
94174bbcaa8S
94274bbcaa8S	elif [[ "$filetype" == "xustar" ]]; then
94374bbcaa8S		install_pax "$insrc"
94474bbcaa8S		unpack_result=$?
94574bbcaa8S
94674bbcaa8S	elif [[ "$filetype" = "tar" ]]; then
94774bbcaa8S		vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
948cec6066bS		# Ignore errors from tar since we expect some errors depending
949cec6066bS		# on how the archive was made.
95074bbcaa8S		( cd "$ZONEROOT" && tar -xf "$insrc" )
951cec6066bS		unpack_result=0
95274bbcaa8S		post_unpack
95374bbcaa8S
95474bbcaa8S	elif [[ "$filetype" == "ufsdump" ]]; then
95574bbcaa8S		install_ufsdump "$insrc"
95674bbcaa8S		unpack_result=$?
95774bbcaa8S
95874bbcaa8S	elif [[ "$filetype" == "directory" ]]; then
95974bbcaa8S		install_dir "$insrc"
96074bbcaa8S		unpack_result=$?
96174bbcaa8S
96274bbcaa8S	elif [[ "$filetype" == "zfs" ]]; then
96374bbcaa8S		#
96474bbcaa8S		# Given a 'zfs send' stream file, receive the snapshot into
96574bbcaa8S		# the zone's dataset.  We're getting the original system's
96674bbcaa8S		# zonepath dataset.  Destroy the existing dataset created
96774bbcaa8S		# above since this recreates it.
96874bbcaa8S		#
96974bbcaa8S		if [[ -z "$DATASET" ]]; then
97074bbcaa8S			fatal "$f_nodataset"
97174bbcaa8S		fi
97274bbcaa8S		/usr/sbin/zfs destroy "$DATASET"
97374bbcaa8S		if (( $? != 0 )); then
97474bbcaa8S			log "$f_zfsdestroy" "$DATASET"
97574bbcaa8S		fi
97674bbcaa8S
97774bbcaa8S		vlog "$stage1 $insrc | zfs receive -F $DATASET"
97874bbcaa8S		( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET )
97974bbcaa8S		unpack_result=$?
98074bbcaa8S	fi
98174bbcaa8S
98274bbcaa8S	# Clean up any fs mounts used during unpacking.
98374bbcaa8S	umnt_fs
984*6e1ae2a3SGary Pennington	rm -f $fstmpfile $fscpiofile $fspaxfile
98574bbcaa8S
98674bbcaa8S	chmod 700 $zonepath
98774bbcaa8S
988cec6066bS	(( $unpack_result != 0 )) && fatal "$f_unpack_failed"
989cec6066bS
99074bbcaa8S	# Verify this is a valid image.
99174bbcaa8S	sanity_check $ZONEROOT
99274bbcaa8S
99374bbcaa8S	return 0
99474bbcaa8S}
99574bbcaa8S
996edfa49ffS# Setup i18n output
997edfa49ffSTEXTDOMAIN="SUNW_OST_OSCMD"
998edfa49ffSexport TEXTDOMAIN
999edfa49ffS
1000ae104932SJonathan Adamse_cannot_wrap=$(gettext "%s: error: wrapper file already exists")
1001edfa49ffSe_baddir=$(gettext "Invalid '%s' directory within the zone")
1002edfa49ffSe_badfile=$(gettext "Invalid '%s' file within the zone")
100374bbcaa8Se_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
100474bbcaa8Se_not_found=$(gettext "%s: error: file or directory not found.")
100574bbcaa8Se_install_abort=$(gettext "Installation aborted.")
100674bbcaa8Se_not_readable=$(gettext "Cannot read directory '%s'")
100774bbcaa8Se_not_dir=$(gettext "Error: must be a directory")
100874bbcaa8Se_unknown_archive=$(gettext "Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.")
100962ac5336Se_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
10108c20418dSGerald Jelineke_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).")
101174bbcaa8Se_tmpfile=$(gettext "Unable to create temporary file")
101274bbcaa8Se_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
1013e71ca95cSGerald Jelinekf_mkdir=$(gettext "Unable to create directory %s.")
1014e71ca95cSGerald Jelinekf_chmod=$(gettext "Unable to chmod directory %s.")
1015e71ca95cSGerald Jelinekf_chown=$(gettext "Unable to chown directory %s.")
101674bbcaa8S
101774bbcaa8S
10188c20418dSGerald Jelinekm_analyse_archive=$(gettext "Analysing the archive")
10198c20418dSGerald Jelinek
102074bbcaa8Snot_readable=$(gettext "Cannot read file '%s'")
102174bbcaa8Snot_flar=$(gettext "Input is not a flash archive")
102274bbcaa8Sbad_flar=$(gettext "Flash archive is a corrupt")
1023cec6066bSbad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.")
1024cec6066bSf_unpack_failed=$(gettext "Unpacking the archive failed")
102574bbcaa8Sunknown_archiver=$(gettext "Archiver %s is not supported")
102674bbcaa8Scmd_not_exec=$(gettext "Required command '%s' not executable!")
1027edfa49ffS
1028edfa49ffS#
1029edfa49ffS# Exit values used by the script, as #defined in <sys/zone.h>
1030edfa49ffS#
1031edfa49ffS#	ZONE_SUBPROC_OK
1032edfa49ffS#	===============
1033edfa49ffS#	Installation was successful
1034edfa49ffS#
1035edfa49ffS#	ZONE_SUBPROC_USAGE
1036edfa49ffS#	==================
1037edfa49ffS#	Improper arguments were passed, so print a usage message before exiting
1038edfa49ffS#
1039edfa49ffS#	ZONE_SUBPROC_NOTCOMPLETE
1040edfa49ffS#	========================
1041edfa49ffS#	Installation did not complete, but another installation attempt can be
1042edfa49ffS#	made without an uninstall
1043edfa49ffS#
1044edfa49ffS#	ZONE_SUBPROC_FATAL
1045edfa49ffS#	==================
1046edfa49ffS#	Installation failed and an uninstall will be required before another
1047edfa49ffS#	install can be attempted
1048edfa49ffS#
1049edfa49ffSZONE_SUBPROC_OK=0
1050edfa49ffSZONE_SUBPROC_USAGE=253
1051edfa49ffSZONE_SUBPROC_NOTCOMPLETE=254
1052edfa49ffSZONE_SUBPROC_FATAL=255
1053edfa49ffS
1054