xref: /illumos-gate/usr/src/lib/brand/shared/zone/common.ksh (revision 716c180559045549271833327182dc6a266134f1)
1#
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or http://www.opensolaris.org/os/licensing.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
22#
23
24#
25# Send the error message to the screen and to the logfile.
26#
27error()
28{
29        typeset fmt="$1"
30        shift
31
32        printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@"
33        [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2
34}
35
36fatal()
37{
38        typeset fmt="$1"
39        shift
40
41	error "$fmt" "$@"
42	exit $EXIT_CODE
43}
44
45fail_fatal() {
46	printf "ERROR: "
47	printf "$@"
48	printf "\n"
49	exit $ZONE_SUBPROC_FATAL
50}
51
52#
53# Send the provided printf()-style arguments to the screen and to the logfile.
54#
55log()
56{
57        typeset fmt="$1"
58        shift
59
60        printf "${MSG_PREFIX}${fmt}\n" "$@"
61        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
62}
63
64#
65# Print provided text to the screen if the shell variable "OPT_V" is set.
66# The text is always sent to the logfile.
67#
68vlog()
69{
70        typeset fmt="$1"
71        shift
72
73        [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@"
74        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
75}
76
77#
78# Validate that the directory is safe.
79#
80# It is possible for a malicious zone root user to modify a zone's filesystem
81# so that modifications made to the zone's filesystem by administrators in the
82# global zone modify the global zone's filesystem.  We can prevent this by
83# ensuring that all components of paths accessed by scripts are real (i.e.,
84# non-symlink) directories.
85#
86# NOTE: The specified path should be an absolute path as would be seen from
87# within the zone.  Also, this function does not check parent directories.
88# If, for example, you need to ensure that every component of the path
89# '/foo/bar/baz' is a directory and not a symlink, then do the following:
90#
91#	safe_dir /foo
92#	safe_dir /foo/bar
93#	safe_dir /foo/bar/baz
94#
95safe_dir()
96{
97	typeset dir="$1"
98
99	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
100		fatal "$e_baddir" "$dir"
101	fi
102}
103
104# Like safe_dir except the dir doesn't have to exist.
105safe_opt_dir()
106{
107	typeset dir="$1"
108
109	[[ ! -e $ZONEROOT/$dir ]] && return
110
111	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
112		fatal "$e_baddir" "$dir"
113	fi
114}
115
116# Only make a copy if we haven't already done so.
117safe_backup()
118{
119	typeset src="$1"
120	typeset dst="$2"
121
122	if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then
123		/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
124	fi
125}
126
127# Make a copy even if the destination already exists.
128safe_copy()
129{
130	typeset src="$1"
131	typeset dst="$2"
132
133	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
134		/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
135	fi
136}
137
138# Move a file
139safe_move()
140{
141	typeset src="$1"
142	typeset dst="$2"
143
144	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
145		/usr/bin/mv $src $dst || fatal "$e_badfile" "$src"
146	fi
147}
148
149safe_rm()
150{
151	if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then
152		rm -f "$ZONEROOT/$1"
153	fi
154}
155
156#
157# Replace the file with a wrapper pointing to the native brand code.
158# However, we only do the replacement if the file hasn't already been
159# replaced with our wrapper.  This function expects the cwd to be the
160# location of the file we're replacing.
161#
162# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm'
163# the file before we setup the wrapper while others are hardlinks to rc scripts
164# that we need to maintain.
165#
166safe_replace()
167{
168	typeset filename="$1"
169	typeset runname="$2"
170	typeset mode="$3"
171	typeset own="$4"
172	typeset rem="$5"
173
174	if [ -h $filename -o ! -f $filename ]; then
175		return
176	fi
177
178	egrep -s "Solaris Brand Replacement" $filename
179	if [ $? -eq 0 ]; then
180		return
181	fi
182
183	safe_backup $filename $filename.pre_p2v
184	if [ $rem = "remove" ]; then
185		rm -f $filename
186	fi
187
188	cat <<-END >$filename || exit 1
189	#!/bin/sh -p
190	#
191	# Solaris Brand Replacement
192	#
193	# Attention.  This file has been replaced with a new version for
194	# use in a virtualized environment.  Modification of this script is not
195	# supported and all changes will be lost upon reboot.  The
196	# {name}.pre_p2v version of this file is a backup copy of the
197	# original and should not be deleted.
198	#
199	END
200
201	echo ". $runname \"\$@\"" >>$filename || exit 1
202
203	chmod $mode $filename
204	chown $own $filename
205}
206
207safe_wrap()
208{
209	typeset filename="$1"
210	typeset runname="$2"
211	typeset mode="$3"
212	typeset own="$4"
213
214	if [ -f $filename ]; then
215		log "$e_cannot_wrap" "$filename"
216		exit 1
217	fi
218
219	cat <<-END >$filename || exit 1
220	#!/bin/sh
221	#
222	# Solaris Brand Wrapper
223	#
224	# Attention.  This file has been created for use in a
225	# virtualized environment.  Modification of this script
226	# is not supported and all changes will be lost upon reboot.
227	#
228	END
229
230	echo ". $runname \"\$@\"" >>$filename || exit 1
231
232	chmod $mode $filename
233	chown $own $filename
234}
235
236#
237# Read zonecfg fs entries and save the relevant data, one entry per
238# line.
239# This assumes the properties from the zonecfg output, e.g.:
240#	fs:
241#		dir: /opt
242#		special: /opt
243#		raw not specified
244#		type: lofs
245#		options: [noexec,ro,noatime]
246#
247# and it assumes the order of the fs properties as above.
248#
249get_fs_info()
250{
251	zonecfg -z $zonename info fs | nawk '{
252		if ($1 == "options:") {
253			# Remove brackets.
254			options=substr($2, 2, length($2) - 2);
255			printf("%s %s %s %s\n", dir, type, special, options);
256		} else if ($1 == "dir:") {
257			dir=$2;
258		} else if ($1 == "special:") {
259			special=$2;
260		} else if ($1 == "type:") {
261			type=$2
262		}
263	}' >> $fstmpfile
264}
265
266#
267# Mount zonecfg fs entries into the zonepath.
268#
269mnt_fs()
270{
271	if [ ! -s $fstmpfile ]; then
272		return;
273	fi
274
275	# Sort the fs entries so we can handle nested mounts.
276	sort $fstmpfile | nawk -v zonepath=$zonepath '{
277		if (NF == 4)
278			options="-o " $4;
279		else
280			options=""
281
282		# Create the mount point.  Ignore errors since we might have
283		# a nested mount with a pre-existing mount point.
284		cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1"
285		system(cmd);
286
287		cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \
288		    zonepath "/root" $1;
289		if (system(cmd) != 0) {
290			printf("command failed: %s\n", cmd);
291			exit 1;
292		}
293	}' >>$LOGFILE
294}
295
296#
297# Unmount zonecfg fs entries from the zonepath.
298#
299umnt_fs()
300{
301	if [ ! -s $fstmpfile ]; then
302		return;
303	fi
304
305	# Reverse sort the fs entries so we can handle nested unmounts.
306	sort -r $fstmpfile | nawk -v zonepath=$zonepath '{
307		cmd="/usr/sbin/umount " zonepath "/root" $1
308		if (system(cmd) != 0) {
309			printf("command failed: %s\n", cmd);
310		}
311	}' >>$LOGFILE
312}
313
314# Find the dataset mounted on the zonepath.
315get_zonepath_ds() {
316	ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \
317	    /usr/bin/nawk -v zonepath=$1 '{
318		if ($2 == zonepath)
319			print $1
320	}'`
321
322	if [ -z "$ZONEPATH_DS" ]; then
323		fail_fatal "$f_no_ds"
324	fi
325}
326
327#
328# Perform any cleanup in the zoneroot after unpacking the archive.
329#
330post_unpack()
331{
332	( cd "$ZONEROOT" && \
333	    find . \( -type b -o -type c \) -exec rm -f "{}" \; )
334}
335
336#
337# Determine flar compression style from identification file.
338#
339get_compression()
340{
341	typeset ident=$1
342	typeset line=$(grep "^files_compressed_method=" $ident)
343
344	print ${line##*=}
345}
346
347#
348# Determine flar archive style from identification file.
349#
350get_archiver()
351{
352        typeset ident=$1
353        typeset line=$(grep "^files_archived_method=" $ident)
354
355        print ${line##*=}
356}
357
358#
359# Unpack flar into current directory (which should be zoneroot).  The flash
360# archive is standard input.  See flash_archive(4) man page.
361#
362# We can't use "flar split" since it will only unpack into a directory called
363# "archive".  We need to unpack in place in order to properly handle nested
364# fs mounts within the zone root.  This function does the unpacking into the
365# current directory.
366#
367# This code is derived from the gen_split() function in /usr/sbin/flar so
368# we keep the same style as the original.
369#
370install_flar()
371{
372	typeset result
373        typeset archiver_command
374        typeset archiver_arguments
375
376	vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar"
377
378	# Read cookie
379	read -r input_line
380	if (( $? != 0 )); then
381		log "$not_readable" "$install_media"
382		return 1
383	fi
384	# The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers.
385	if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then
386		log "$not_flar"
387		return 1
388	fi
389
390	while [ true ]
391	do
392		# We should always be at the start of a section here
393		read -r input_line
394		if [[ ${input_line%%=*} != "section_begin" ]]; then
395			log "$bad_flar"
396			return 1
397		fi
398		section_name=${input_line##*=}
399
400		# If we're at the archive, we're done skipping sections.
401		if [[ "$section_name" == "archive" ]]; then
402			break
403		fi
404
405		#
406		# Save identification section to a file so we can determine
407		# how to unpack the archive.
408		#
409		if [[ "$section_name" == "identification" ]]; then
410			/usr/bin/rm -f identification
411			while read -r input_line
412			do
413				if [[ ${input_line%%=*} == \
414				    "section_begin" ]]; then
415					/usr/bin/rm -f identification
416					log "$bad_flar"
417					return 1
418				fi
419
420				if [[ $input_line == \
421				    "section_end=$section_name" ]]; then
422					break;
423				fi
424				echo $input_line >> identification
425			done
426
427			continue
428		fi
429
430		#
431		# Otherwise skip past this section; read lines until detecting
432		# section_end.  According to flash_archive(4) we can have
433		# an arbitrary number of sections but the archive section
434		# must be last.
435		#
436		success=0
437		while read -r input_line
438		do
439			if [[ $input_line == "section_end=$section_name" ]];
440			then
441				success=1
442				break
443			fi
444			# Fail if we miss the end of the section
445			if [[ ${input_line%%=*} == "section_begin" ]]; then
446				/usr/bin/rm -f identification
447				log "$bad_flar"
448				return 1
449			fi
450		done
451		if (( $success == 0 )); then
452			#
453			# If we get here we read to the end of the file before
454			# seeing the end of the section we were reading.
455			#
456			/usr/bin/rm -f identification
457			log "$bad_flar"
458			return 1
459		fi
460	done
461
462	# Check for an archive made from a ZFS root pool.
463	egrep -s "^rootpool=" identification
464        if (( $? == 0 )); then
465		/usr/bin/rm -f identification
466                log "$bad_zfs_flar"
467                return 1
468        fi
469
470	# Get the information needed to unpack the archive.
471	archiver=$(get_archiver identification)
472	if [[ $archiver == "pax" ]]; then
473		# pax archiver specified
474		archiver_command="/usr/bin/pax"
475		if [[ -s $fspaxfile ]]; then
476			archiver_arguments="-r -p e -c \
477			    $(/usr/bin/cat $fspaxfile)"
478		else
479			archiver_arguments="-r -p e"
480		fi
481	elif [[ $archiver == "cpio" || -z $archiver ]]; then
482		# cpio archived specified OR no archiver specified - use default
483		archiver_command="/usr/bin/cpio"
484		archiver_arguments="-icdumfE $fscpiofile"
485	else
486		# unknown archiver specified
487		log "$unknown_archiver" $archiver
488		return 1
489	fi
490
491	if [[ ! -x $archiver_command ]]; then
492		/usr/bin/rm -f identification
493		log "$cmd_not_exec" $archiver_command
494		return 1
495	fi
496
497	compression=$(get_compression identification)
498
499	# We're done with the identification file
500	/usr/bin/rm -f identification
501
502	# Extract archive
503	if [[ $compression == "compress" ]]; then
504		/usr/bin/zcat | \
505		    $archiver_command $archiver_arguments 2>/dev/null
506	else
507		$archiver_command $archiver_arguments 2>/dev/null
508	fi
509	result=$?
510
511	post_unpack
512
513	(( $result != 0 )) && return 1
514
515	return 0
516}
517
518#
519# Get the archive base.
520#
521# We must unpack the archive in the right place within the zonepath so
522# that files are installed into the various mounted filesystems that are set
523# up in the zone's configuration.  These are already mounted for us by the
524# mntfs function.
525#
526# Archives can be made of either a physical host's root file system or a
527# zone's zonepath.  For a physical system, if the archive is made using an
528# absolute path (/...) we can't use it.  For a zone the admin can make the
529# archive from a variety of locations;
530#
531#   a) zonepath itself: This will be a single dir, probably named with the
532#      zone name, it will contain a root dir and under the root we'll see all
533#      the top level dirs; etc, var, usr...  We must be above the ZONEPATH
534#      when we unpack the archive but this will only work if the the archive's
535#      top-level dir name matches the ZONEPATH base-level dir name.  If not,
536#      this is an error.
537#
538#   b) inside the zonepath: We'll see root and it will contain all the top
539#      level dirs; etc, var, usr....  We must be in the ZONEPATH when we unpack
540#      the archive.
541#
542#   c) inside the zonepath root: We'll see all the top level dirs, ./etc,
543#      ./var, ./usr....  This is also the case we see when we get an archive
544#      of a physical sytem.  We must be in ZONEROOT when we unpack the archive.
545#
546# Note that there can be a directory named "root" under the ZONEPATH/root
547# directory.
548#
549# This function handles the above possibilities so that we reject absolute
550# path archives and figure out where in the file system we need to be to
551# properly unpack the archive into the zone.  It sets the ARCHIVE_BASE
552# variable to the location where the achive should be unpacked.
553#
554get_archive_base()
555{
556	stage1=$1
557	archive=$2
558	stage2=$3
559
560	vlog "$m_analyse_archive"
561
562	base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{
563		# Check for an absolute path archive
564		if (substr($0, 1, 1) == "/")
565			exit 1
566
567		if ($1 != ".")
568			dirs[$1] = 1
569		else
570			dirs[$2] = 1
571	}
572	END {
573		for (d in dirs) {
574			cnt++
575			if (d == "bin")  sawbin = 1
576			if (d == "etc")  sawetc = 1
577			if (d == "root") sawroot = 1
578			if (d == "var")  sawvar = 1
579                }
580
581		if (cnt == 1) {
582			# If only one top-level dir named root, we are in the
583			# zonepath, otherwise this must be an archive *of*
584			# the zonepath so print the top-level dir name.
585			if (sawroot)
586				print "*zonepath*"
587			else
588				for (d in dirs) print d
589		} else {
590			# We are either in the zonepath or in the zonepath/root
591			# (or at the top level of a full system archive which
592			# looks like the zonepath/root case).  Figure out which
593			# one.
594			if (sawroot && !sawbin && !sawetc && !sawvar)
595				print "*zonepath*"
596			else
597				print "*zoneroot*"
598		}
599	}'`
600
601	if (( $? != 0 )); then
602		umnt_fs
603		fatal "$e_absolute_archive"
604	fi
605
606	if [[ "$base" == "*zoneroot*" ]]; then
607		ARCHIVE_BASE=$ZONEROOT
608	elif [[ "$base" == "*zonepath*" ]]; then
609		ARCHIVE_BASE=$ZONEPATH
610	else
611		# We need to be in the dir above the ZONEPATH but we need to
612		# validate that $base matches the final component of ZONEPATH.
613		bname=`basename $ZONEPATH`
614
615		if [[ "$bname" != "$base" ]]; then
616			umnt_fs
617			fatal "$e_mismatch_archive" "$base" "$bname"
618		fi
619		ARCHIVE_BASE=`dirname $ZONEPATH`
620	fi
621}
622
623#
624# Unpack cpio archive into zoneroot.
625#
626install_cpio()
627{
628	stage1=$1
629	archive=$2
630
631	get_archive_base "$stage1" "$archive" "cpio -it"
632
633	cpioopts="-idmfE $fscpiofile"
634
635	vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts"
636
637	# Ignore errors from cpio since we expect some errors depending on
638	# how the archive was made.
639	( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts )
640
641	post_unpack
642
643	return 0
644}
645
646#
647# Unpack pax archive into zoneroot.
648#
649install_pax()
650{
651	archive=$1
652
653	get_archive_base "cat" "$archive" "pax"
654
655	if [[ -s $fspaxfile ]]; then
656		filtopt="-c $(/usr/bin/cat $fspaxfile)"
657	fi
658
659	vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt"
660
661	# Ignore errors from pax since we expect some errors depending on
662	# how the archive was made.
663	( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt )
664
665	post_unpack
666
667	return 0
668}
669
670#
671# Unpack UFS dump into zoneroot.
672#
673install_ufsdump()
674{
675	archive=$1
676
677	vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\""
678
679	#
680	# ufsrestore goes interactive if you ^C it.  To prevent that,
681	# we make sure its stdin is not a terminal.
682	#
683	( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
684	result=$?
685
686	post_unpack
687
688	return $result
689}
690
691#
692# Copy directory hierarchy into zoneroot.
693#
694install_dir()
695{
696	source_dir=$1
697
698	cpioopts="-pdm"
699
700	first=1
701	filt=$(for i in $(cat $fspaxfile)
702		do
703			echo $i | egrep -s "/" && continue
704			if [[ $first == 1 ]]; then
705				printf "^%s" $i
706				first=0
707			else
708				printf "|^%s" $i
709			fi
710		done)
711
712	list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
713	flist=$(for i in $list
714	do
715		printf "%s " "$i"
716	done)
717	findopts="-xdev ( -type d -o -type f -o -type l ) -print"
718
719	vlog "cd \"$source_dir\" && find $flist $findopts | "
720	vlog "cpio $cpioopts \"$ZONEROOT\""
721
722	# Ignore errors from cpio since we expect some errors depending on
723	# how the archive was made.
724	( cd "$source_dir" && find $flist $findopts | \
725	    cpio $cpioopts "$ZONEROOT" )
726
727	post_unpack
728
729	return 0
730}
731
732#
733# This is a common function for laying down a zone image from a variety of
734# different sources.  This can be used to either install a fresh zone or as
735# part of zone migration during attach.
736#
737# The first argument specifies the type of image: archive, directory or stdin.
738# The second argument specifies the image itself.  In the case of stdin, the
739# second argument specifies the format of the stream (cpio, flar, etc.).
740# Any validation or post-processing on the image is done elsewhere.
741#
742# This function calls a 'sanity_check' function which must be provided by
743# the script which includes this code.
744#
745install_image()
746{
747	intype=$1
748	insrc=$2
749
750	if [[ -z "$intype" || -z "$insrc" ]]; then
751		return 1
752	fi
753
754	filetype="unknown"
755	filetypename="unknown"
756	stage1="cat"
757
758	if [[ "$intype" == "directory" ]]; then
759		if [[ "$insrc" == "-" ]]; then
760			# Indicates that the existing zonepath is prepopulated.
761			filetype="existing"
762			filetypename="existing"
763		else
764			if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
765				fatal "$e_path_abs" "$insrc"
766			fi
767
768			if [[ ! -e "$insrc" ]]; then
769				log "$e_not_found" "$insrc"
770				fatal "$e_install_abort"
771			fi
772
773			if [[ ! -r "$insrc" ]]; then
774				log "$e_not_readable" "$insrc"
775				fatal "$e_install_abort"
776			fi
777
778			if [[ ! -d "$insrc" ]]; then
779				log "$e_not_dir"
780				fatal "$e_install_abort"
781			fi
782
783			sanity_check $insrc
784
785			filetype="directory"
786			filetypename="directory"
787		fi
788
789	else
790		# Common code for both archive and stdin stream.
791
792		if [[ "$intype" == "archive" ]]; then
793			if [[ ! -f "$insrc" ]]; then
794				log "$e_unknown_archive"
795				fatal "$e_install_abort"
796			fi
797			ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
798		else
799			# For intype == stdin, the insrc parameter specifies
800			# the stream format coming on stdin.
801			ftype="$insrc"
802			insrc="-"
803		fi
804
805		# Setup vars for the archive type we have.
806		case "$ftype" in
807		*cpio*)		filetype="cpio"
808				filetypename="cpio archive"
809			;;
810		*bzip2*)	filetype="bzip2"
811				filetypename="bzipped cpio archive"
812			;;
813		*gzip*)		filetype="gzip"
814				filetypename="gzipped cpio archive"
815			;;
816		*ufsdump*)	filetype="ufsdump"
817				filetypename="ufsdump archive"
818			;;
819		"flar")
820				filetype="flar"
821				filetypename="flash archive"
822			;;
823		"flash")
824				filetype="flar"
825				filetypename="flash archive"
826			;;
827		*Flash\ Archive*)
828				filetype="flar"
829				filetypename="flash archive"
830			;;
831		"tar")
832				filetype="tar"
833				filetypename="tar archive"
834			;;
835		*USTAR\ tar\ archive)
836				filetype="tar"
837				filetypename="tar archive"
838			;;
839		"pax")
840				filetype="xustar"
841				filetypename="pax (xustar) archive"
842			;;
843		*USTAR\ tar\ archive\ extended\ format*)
844				filetype="xustar"
845				filetypename="pax (xustar) archive"
846			;;
847		"zfs")
848				filetype="zfs"
849				filetypename="ZFS send stream"
850			;;
851		*ZFS\ snapshot\ stream*)
852				filetype="zfs"
853				filetypename="ZFS send stream"
854			;;
855		*)		log "$e_unknown_archive"
856				fatal "$e_install_abort"
857			;;
858		esac
859	fi
860
861	vlog "$filetypename"
862
863	# Check for a non-empty root if no '-d -' option.
864	if [[ "$filetype" != "existing" ]]; then
865		cnt=$(ls $ZONEROOT | wc -l)
866		if (( $cnt != 0 )); then
867			fatal "$e_root_full" "$ZONEROOT"
868		fi
869	fi
870
871	fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
872	if [[ -z "$fstmpfile" ]]; then
873		fatal "$e_tmpfile"
874	fi
875
876	# Make sure we always have the files holding the directories to filter
877	# out when extracting from a CPIO or PAX archive.  We'll add the fs
878	# entries to these files in get_fs_info()
879	fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX)
880	if [[ -z "$fscpiofile" ]]; then
881		rm -f $fstmpfile
882		fatal "$e_tmpfile"
883	fi
884
885	# Filter out these directories.
886	echo 'dev/*' >>$fscpiofile
887	echo 'devices/*' >>$fscpiofile
888	echo 'devices' >>$fscpiofile
889	echo 'proc/*' >>$fscpiofile
890	echo 'tmp/*' >>$fscpiofile
891	echo 'var/run/*' >>$fscpiofile
892	echo 'system/contract/*' >>$fscpiofile
893	echo 'system/object/*' >>$fscpiofile
894
895	fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX)
896	if [[ -z "$fspaxfile" ]]; then
897		rm -f $fstmpfile $fscpiofile
898		fatal "$e_tmpfile"
899	fi
900
901	printf "%s " \
902	    "dev devices proc tmp var/run system/contract system/object" \
903	    >>$fspaxfile
904
905	# Set up any fs mounts so the archive will install into the correct
906	# locations.
907	get_fs_info
908	mnt_fs
909	if (( $? != 0 )); then
910		umnt_fs >/dev/null 2>&1
911		rm -f $fstmpfile $fscpiofile $fspaxfile
912		fatal "$mount_failed"
913	fi
914
915	if [[ "$filetype" == "existing" ]]; then
916		log "$no_installing"
917	else
918		log "$installing"
919	fi
920
921	#
922	# Install the image into the zonepath.
923	#
924	unpack_result=0
925	stage1="cat"
926	if [[ "$filetype" == "gzip" ]]; then
927		stage1="gzcat"
928		filetype="cpio"
929	elif [[ "$filetype" == "bzip2" ]]; then
930		stage1="bzcat"
931		filetype="cpio"
932	fi
933
934	if [[ "$filetype" == "cpio" ]]; then
935		install_cpio "$stage1" "$insrc"
936		unpack_result=$?
937
938	elif [[ "$filetype" == "flar" ]]; then
939		( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
940		unpack_result=$?
941
942	elif [[ "$filetype" == "xustar" ]]; then
943		install_pax "$insrc"
944		unpack_result=$?
945
946	elif [[ "$filetype" = "tar" ]]; then
947		vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
948		# Ignore errors from tar since we expect some errors depending
949		# on how the archive was made.
950		( cd "$ZONEROOT" && tar -xf "$insrc" )
951		unpack_result=0
952		post_unpack
953
954	elif [[ "$filetype" == "ufsdump" ]]; then
955		install_ufsdump "$insrc"
956		unpack_result=$?
957
958	elif [[ "$filetype" == "directory" ]]; then
959		install_dir "$insrc"
960		unpack_result=$?
961
962	elif [[ "$filetype" == "zfs" ]]; then
963		#
964		# Given a 'zfs send' stream file, receive the snapshot into
965		# the zone's dataset.  We're getting the original system's
966		# zonepath dataset.  Destroy the existing dataset created
967		# above since this recreates it.
968		#
969		if [[ -z "$DATASET" ]]; then
970			fatal "$f_nodataset"
971		fi
972		/usr/sbin/zfs destroy "$DATASET"
973		if (( $? != 0 )); then
974			log "$f_zfsdestroy" "$DATASET"
975		fi
976
977		vlog "$stage1 $insrc | zfs receive -F $DATASET"
978		( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET )
979		unpack_result=$?
980	fi
981
982	# Clean up any fs mounts used during unpacking.
983	umnt_fs
984	rm -f $fstmpfile $fscpiofile $fspaxfile
985
986	chmod 700 $zonepath
987
988	(( $unpack_result != 0 )) && fatal "$f_unpack_failed"
989
990	# Verify this is a valid image.
991	sanity_check $ZONEROOT
992
993	return 0
994}
995
996# Setup i18n output
997TEXTDOMAIN="SUNW_OST_OSCMD"
998export TEXTDOMAIN
999
1000e_cannot_wrap=$(gettext "%s: error: wrapper file already exists")
1001e_baddir=$(gettext "Invalid '%s' directory within the zone")
1002e_badfile=$(gettext "Invalid '%s' file within the zone")
1003e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
1004e_not_found=$(gettext "%s: error: file or directory not found.")
1005e_install_abort=$(gettext "Installation aborted.")
1006e_not_readable=$(gettext "Cannot read directory '%s'")
1007e_not_dir=$(gettext "Error: must be a directory")
1008e_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.")
1009e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
1010e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).")
1011e_tmpfile=$(gettext "Unable to create temporary file")
1012e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
1013f_mkdir=$(gettext "Unable to create directory %s.")
1014f_chmod=$(gettext "Unable to chmod directory %s.")
1015f_chown=$(gettext "Unable to chown directory %s.")
1016
1017
1018m_analyse_archive=$(gettext "Analysing the archive")
1019
1020not_readable=$(gettext "Cannot read file '%s'")
1021not_flar=$(gettext "Input is not a flash archive")
1022bad_flar=$(gettext "Flash archive is a corrupt")
1023bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.")
1024f_unpack_failed=$(gettext "Unpacking the archive failed")
1025unknown_archiver=$(gettext "Archiver %s is not supported")
1026cmd_not_exec=$(gettext "Required command '%s' not executable!")
1027
1028#
1029# Exit values used by the script, as #defined in <sys/zone.h>
1030#
1031#	ZONE_SUBPROC_OK
1032#	===============
1033#	Installation was successful
1034#
1035#	ZONE_SUBPROC_USAGE
1036#	==================
1037#	Improper arguments were passed, so print a usage message before exiting
1038#
1039#	ZONE_SUBPROC_NOTCOMPLETE
1040#	========================
1041#	Installation did not complete, but another installation attempt can be
1042#	made without an uninstall
1043#
1044#	ZONE_SUBPROC_FATAL
1045#	==================
1046#	Installation failed and an uninstall will be required before another
1047#	install can be attempted
1048#
1049ZONE_SUBPROC_OK=0
1050ZONE_SUBPROC_USAGE=253
1051ZONE_SUBPROC_NOTCOMPLETE=254
1052ZONE_SUBPROC_FATAL=255
1053
1054