xref: /illumos-gate/usr/src/lib/brand/shared/zone/common.ksh (revision 62ac53366ae15a996820cda28eda6998f2347413)
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 2009 Sun Microsystems, Inc.  All rights reserved.
22# Use is subject to license terms.
23#
24
25#
26# Send the error message to the screen and to the logfile.
27#
28error()
29{
30        typeset fmt="$1"
31        shift
32
33        printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@"
34        [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2
35}
36
37fatal()
38{
39        typeset fmt="$1"
40        shift
41
42	error "$fmt" "$@"
43	exit $EXIT_CODE
44}
45
46#
47# Send the provided printf()-style arguments to the screen and to the logfile.
48#
49log()
50{
51        typeset fmt="$1"
52        shift
53
54        printf "${MSG_PREFIX}${fmt}\n" "$@"
55        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
56}
57
58#
59# Print provided text to the screen if the shell variable "OPT_V" is set.
60# The text is always sent to the logfile.
61#
62vlog()
63{
64        typeset fmt="$1"
65        shift
66
67        [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@"
68        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
69}
70
71# Validate that the directory is safe.
72safe_dir()
73{
74	typeset dir="$1"
75
76	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
77		fatal "$e_baddir" "$dir"
78	fi
79}
80
81# Only make a copy if we haven't already done so.
82safe_backup()
83{
84	typeset src="$1"
85	typeset dst="$2"
86
87	if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then
88		/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
89	fi
90}
91
92# Make a copy even if the destination already exists.
93safe_copy()
94{
95	typeset src="$1"
96	typeset dst="$2"
97
98	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
99		/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
100	fi
101}
102
103# Move a file
104safe_move()
105{
106	typeset src="$1"
107	typeset dst="$2"
108
109	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
110		/usr/bin/mv $src $dst || fatal "$e_badfile" "$src"
111	fi
112}
113
114#
115# Read zonecfg ipd and fs entries and save the relevant data, one entry per
116# line.
117# This assumes the properties from the zonecfg output, e.g.:
118#	inherit-pkg-dir:
119#		dir: /usr
120#	fs:
121#		dir: /opt
122#		special: /opt
123#		raw not specified
124#		type: lofs
125#		options: [noexec,ro,noatime]
126#
127# and it assumes the order of the fs properties as above.  This also saves the
128# inherit-pkg-dir patterns into the ipd.{cpio|pax} temporary files for
129# filtering while extracting the image into the zonepath.  We have to save the
130# IPD patterns in the appropriate format for filtering with the different
131# archivers and we don't know what format we'll get until after the flash
132# archive is unpacked.
133#
134get_fs_info()
135{
136	zonecfg -z $zonename info inherit-pkg-dir | \
137	    nawk -v ipdcpiof=$ipdcpiofile -v ipdpaxf=$ipdpaxfile '{
138		if ($1 == "dir:") {
139			dir=$2;
140			printf("%s lofs %s ro\n", dir, dir);
141
142			if (substr(dir, 1, 1) == "/") {
143				printf("%s\n", substr(dir, 2)) >> ipdcpiof
144				printf("%s/*\n", substr(dir, 2)) >> ipdcpiof
145			} else {
146				printf("%s\n", dir) >> ipdcpiof
147				printf("%s/*\n", dir) >> ipdcpiof
148			}
149
150			if (substr(dir, 1, 1) == "/") {
151				printf("%s ", substr(dir, 2)) >> ipdpaxf
152			} else {
153				printf("%s ", dir) >> ipdpaxf
154			}
155		}
156	}' >> $fstmpfile
157
158	zonecfg -z $zonename info fs | nawk '{
159		if ($1 == "options:") {
160			# Remove brackets.
161			options=substr($2, 2, length($2) - 2);
162			printf("%s %s %s %s\n", dir, type, special, options);
163		} else if ($1 == "dir:") {
164			dir=$2;
165		} else if ($1 == "special:") {
166			special=$2;
167		} else if ($1 == "type:") {
168			type=$2
169		}
170	}' >> $fstmpfile
171}
172
173#
174# Mount zonecfg fs entries into the zonepath.
175#
176mnt_fs()
177{
178	if [ ! -s $fstmpfile ]; then
179		return;
180	fi
181
182	# Sort the fs entries so we can handle nested mounts.
183	sort $fstmpfile | nawk -v zonepath=$zonepath '{
184		if (NF == 4)
185			options="-o " $4;
186		else
187			options=""
188
189		# Create the mount point.  Ignore errors since we might have
190		# a nested mount with a pre-existing mount point.
191		cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1"
192		system(cmd);
193
194		cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \
195		    zonepath "/root" $1;
196		if (system(cmd) != 0) {
197			printf("command failed: %s\n", cmd);
198			exit 1;
199		}
200	}' >>$LOGFILE
201}
202
203#
204# Unmount zonecfg fs entries from the zonepath.
205#
206umnt_fs()
207{
208	if [ ! -s $fstmpfile ]; then
209		return;
210	fi
211
212	# Reverse sort the fs entries so we can handle nested unmounts.
213	sort -r $fstmpfile | nawk -v zonepath=$zonepath '{
214		cmd="/usr/sbin/umount " zonepath "/root" $1
215		if (system(cmd) != 0) {
216			printf("command failed: %s\n", cmd);
217		}
218	}' >>$LOGFILE
219}
220
221#
222# Perform any cleanup in the zoneroot after unpacking the archive.
223#
224post_unpack()
225{
226	( cd "$ZONEROOT" && \
227	    find . \( -type b -o -type c \) -exec rm -f "{}" \; )
228}
229
230#
231# Determine flar compression style from identification file.
232#
233get_compression()
234{
235	typeset ident=$1
236	typeset line=$(grep "^files_compressed_method=" $ident)
237
238	print ${line##*=}
239}
240
241#
242# Determine flar archive style from identification file.
243#
244get_archiver()
245{
246        typeset ident=$1
247        typeset line=$(grep "^files_archived_method=" $ident)
248
249        print ${line##*=}
250}
251
252#
253# Unpack flar into current directory (which should be zoneroot).  The flash
254# archive is standard input.  See flash_archive(4) man page.
255#
256# We can't use "flar split" since it will only unpack into a directory called
257# "archive".  We need to unpack in place in order to properly handle nested
258# fs mounts within the zone root.  This function does the unpacking into the
259# current directory.
260#
261# This code is derived from the gen_split() function in /usr/sbin/flar so
262# we keep the same style as the original.
263#
264install_flar()
265{
266	typeset result
267        typeset archiver_command
268        typeset archiver_arguments
269
270	vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar"
271
272	# Read cookie
273	read -r input_line
274	if (( $? != 0 )); then
275		log "$not_readable" "$install_media"
276		return 1
277	fi
278	# The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers.
279	if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then
280		log "$not_flar"
281		return 1
282	fi
283
284	while [ true ]
285	do
286		# We should always be at the start of a section here
287		read -r input_line
288		if [[ ${input_line%%=*} != "section_begin" ]]; then
289			log "$bad_flar"
290			return 1
291		fi
292		section_name=${input_line##*=}
293
294		# If we're at the archive, we're done skipping sections.
295		if [[ "$section_name" == "archive" ]]; then
296			break
297		fi
298
299		#
300		# Save identification section to a file so we can determine
301		# how to unpack the archive.
302		#
303		if [[ "$section_name" == "identification" ]]; then
304			/usr/bin/rm -f identification
305			while read -r input_line
306			do
307				if [[ ${input_line%%=*} == \
308				    "section_begin" ]]; then
309					/usr/bin/rm -f identification
310					log "$bad_flar"
311					return 1
312				fi
313
314				if [[ $input_line == \
315				    "section_end=$section_name" ]]; then
316					break;
317				fi
318				echo $input_line >> identification
319			done
320
321			continue
322		fi
323
324		#
325		# Otherwise skip past this section; read lines until detecting
326		# section_end.  According to flash_archive(4) we can have
327		# an arbitrary number of sections but the archive section
328		# must be last.
329		#
330		success=0
331		while read -r input_line
332		do
333			if [[ $input_line == "section_end=$section_name" ]];
334			then
335				success=1
336				break
337			fi
338			# Fail if we miss the end of the section
339			if [[ ${input_line%%=*} == "section_begin" ]]; then
340				/usr/bin/rm -f identification
341				log "$bad_flar"
342				return 1
343			fi
344		done
345		if (( $success == 0 )); then
346			#
347			# If we get here we read to the end of the file before
348			# seeing the end of the section we were reading.
349			#
350			/usr/bin/rm -f identification
351			log "$bad_flar"
352			return 1
353		fi
354	done
355
356	# Get the information needed to unpack the archive.
357	archiver=$(get_archiver identification)
358	if [[ $archiver == "pax" ]]; then
359		# pax archiver specified
360		archiver_command="/usr/bin/pax"
361		if [[ -s $ipdpaxfile ]]; then
362			archiver_arguments="-r -p e -c \
363			    $(/usr/bin/cat $ipdpaxfile)"
364		else
365			archiver_arguments="-r -p e"
366		fi
367	elif [[ $archiver == "cpio" || -z $archiver ]]; then
368		# cpio archived specified OR no archiver specified - use default
369		archiver_command="/usr/bin/cpio"
370		archiver_arguments="-icdumfE $ipdcpiofile"
371	else
372		# unknown archiver specified
373		log "$unknown_archiver" $archiver
374		return 1
375	fi
376
377	if [[ ! -x $archiver_command ]]; then
378		/usr/bin/rm -f identification
379		log "$cmd_not_exec" $archiver_command
380		return 1
381	fi
382
383	compression=$(get_compression identification)
384
385	# We're done with the identification file
386	/usr/bin/rm -f identification
387
388	# Extract archive
389	if [[ $compression == "compress" ]]; then
390		/usr/bin/zcat | \
391		    $archiver_command $archiver_arguments 2>/dev/null
392	else
393		$archiver_command $archiver_arguments 2>/dev/null
394	fi
395	result=$?
396
397	post_unpack
398
399	(( $result != 0 )) && return 1
400
401	return 0
402}
403
404#
405# Unpack cpio archive into zoneroot.
406#
407install_cpio()
408{
409	stage1=$1
410	archive=$2
411
412	# Check the first few members of the archive for an absolute path.
413	for i in `$stage1 "$archive" | cpio -it | head | cut -b1`
414	do
415		if [[ "$i" == "/" ]]; then
416			umnt_fs
417			fatal "$e_absolute_archive"
418		fi
419	done
420
421	cpioopts="-idmfE $ipdcpiofile"
422
423	vlog "cd \"$ZONEROOT\" && $stage1 \"$archive\" | cpio $cpioopts"
424
425	( cd "$ZONEROOT" && $stage1 "$archive" | cpio $cpioopts )
426	result=$?
427
428	post_unpack
429
430	return $result
431}
432
433#
434# Unpack pax archive into zoneroot.
435#
436install_pax()
437{
438	archive=$1
439
440	# Check the first few members of the archive for an absolute path.
441	for i in `pax -f "$archive" | head | cut -b1`
442	do
443		if [[ "$i" == "/" ]]; then
444			umnt_fs
445			fatal "$e_absolute_archive"
446		fi
447	done
448
449	if [[ -s $ipdpaxfile ]]; then
450		filtopt="-c $(/usr/bin/cat $ipdpaxfile)"
451	fi
452
453	vlog "cd \"$ZONEROOT\" && pax -r -f \"$archive\" $filtopt"
454
455	( cd "$ZONEROOT" && pax -r -f "$archive" $filtopt )
456	result=$?
457
458	post_unpack
459
460	return $result
461}
462
463#
464# Unpack UFS dump into zoneroot.
465#
466install_ufsdump()
467{
468	archive=$1
469
470	vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\""
471
472	#
473	# ufsrestore goes interactive if you ^C it.  To prevent that,
474	# we make sure its stdin is not a terminal.
475	# Note that there is no way to filter inherit-pkg-dirs for a full
476	# restore so there will be warnings in the log file.
477	#
478	( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
479	result=$?
480
481	post_unpack
482
483	return $result
484}
485
486#
487# Copy directory hierarchy into zoneroot.
488#
489install_dir()
490{
491	source_dir=$1
492
493	cpioopts="-pdm"
494
495	first=1
496	filt=$(for i in $(cat $ipdpaxfile)
497		do
498			echo $i | egrep -s "/" && continue
499			if [[ $first == 1 ]]; then
500				printf "^%s" $i
501				first=0
502			else
503				printf "|^%s" $i
504			fi
505		done)
506
507	list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
508	flist=$(for i in $list
509	do
510		printf "%s " "$i"
511	done)
512	findopts="-xdev ( -type d -o -type f -o -type l ) -print"
513
514	vlog "cd \"$source_dir\" && find $flist $findopts | "
515	vlog "cpio $cpioopts \"$ZONEROOT\""
516
517	( cd "$source_dir" && find $flist $findopts | \
518	    cpio $cpioopts "$ZONEROOT" )
519	result=$?
520
521	post_unpack
522
523	return $result
524}
525
526#
527# This is a common function for laying down a zone image from a variety of
528# different sources.  This can be used to either install a fresh zone or as
529# part of zone migration during attach.
530#
531# The first argument specifies the type of image: archive, directory or stdin.
532# The second argument specifies the image itself.  In the case of stdin, the
533# second argument specifies the format of the stream (cpio, flar, etc.).
534# Any validation or post-processing on the image is done elsewhere.
535#
536# This function calls a 'sanity_check' function which must be provided by
537# the script which includes this code.
538#
539install_image()
540{
541	intype=$1
542	insrc=$2
543
544	if [[ -z "$intype" || -z "$insrc" ]]; then
545		return 1
546	fi
547
548	filetype="unknown"
549	filetypename="unknown"
550	stage1="cat"
551
552	if [[ "$intype" == "directory" ]]; then
553		if [[ "$insrc" == "-" ]]; then
554			# Indicates that the existing zonepath is prepopulated.
555			filetype="existing"
556			filetypename="existing"
557		else
558			if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
559				fatal "$e_path_abs" "$insrc"
560			fi
561
562			if [[ ! -e "$insrc" ]]; then
563				log "$e_not_found" "$insrc"
564				fatal "$e_install_abort"
565			fi
566
567			if [[ ! -r "$insrc" ]]; then
568				log "$e_not_readable" "$insrc"
569				fatal "$e_install_abort"
570			fi
571
572			if [[ ! -d "$insrc" ]]; then
573				log "$e_not_dir"
574				fatal "$e_install_abort"
575			fi
576
577			sanity_check $insrc
578
579			filetype="directory"
580			filetypename="directory"
581		fi
582
583	else
584		# Common code for both archive and stdin stream.
585
586		if [[ "$intype" == "archive" ]]; then
587			if [[ ! -f "$insrc" ]]; then
588				log "$e_unknown_archive"
589				fatal "$e_install_abort"
590			fi
591			ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
592		else
593			# For intype == stdin, the insrc parameter specifies
594			# the stream format coming on stdin.
595			ftype="$insrc"
596			insrc="-"
597		fi
598
599		# Setup vars for the archive type we have.
600		case "$ftype" in
601		*cpio*)		filetype="cpio"
602				filetypename="cpio archive"
603			;;
604		*bzip2*)	filetype="bzip2"
605				filetypename="bzipped cpio archive"
606			;;
607		*gzip*)		filetype="gzip"
608				filetypename="gzipped cpio archive"
609			;;
610		*ufsdump*)	filetype="ufsdump"
611				filetypename="ufsdump archive"
612			;;
613		"flar")
614				filetype="flar"
615				filetypename="flash archive"
616			;;
617		"flash")
618				filetype="flar"
619				filetypename="flash archive"
620			;;
621		*Flash\ Archive*)
622				filetype="flar"
623				filetypename="flash archive"
624			;;
625		"tar")
626				filetype="tar"
627				filetypename="tar archive"
628			;;
629		*USTAR\ tar\ archive)
630				filetype="tar"
631				filetypename="tar archive"
632			;;
633		"pax")
634				filetype="xustar"
635				filetypename="pax (xustar) archive"
636			;;
637		*USTAR\ tar\ archive\ extended\ format*)
638				filetype="xustar"
639				filetypename="pax (xustar) archive"
640			;;
641		"zfs")
642				filetype="zfs"
643				filetypename="ZFS send stream"
644			;;
645		*ZFS\ snapshot\ stream*)
646				filetype="zfs"
647				filetypename="ZFS send stream"
648			;;
649		*)		log "$e_unknown_archive"
650				fatal "$e_install_abort"
651			;;
652		esac
653	fi
654
655	vlog "$filetypename"
656
657	# Check for a non-empty root if no '-d -' option.
658	if [[ "$filetype" != "existing" ]]; then
659		cnt=$(ls $ZONEROOT | wc -l)
660		if (( $cnt != 0 )); then
661			fatal "$e_root_full" "$ZONEROOT"
662		fi
663	fi
664
665	fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
666	if [[ -z "$fstmpfile" ]]; then
667		fatal "$e_tmpfile"
668	fi
669
670	# Make sure we always have the files holding the directories to filter
671	# out when extracting from a CPIO or PAX archive.  We'll add the fs
672	# entries to these files in get_fs_info() (there may be no IPDs for
673	# some brands but thats ok).
674	ipdcpiofile=$(/usr/bin/mktemp -t -p /var/tmp ipd.cpio.XXXXXX)
675	if [[ -z "$ipdcpiofile" ]]; then
676		rm -f $fstmpfile
677		fatal "$e_tmpfile"
678	fi
679
680	# In addition to the IPDs, also filter out these directories.
681	echo 'dev/*' >>$ipdcpiofile
682	echo 'devices/*' >>$ipdcpiofile
683	echo 'devices' >>$ipdcpiofile
684	echo 'proc/*' >>$ipdcpiofile
685	echo 'tmp/*' >>$ipdcpiofile
686	echo 'var/run/*' >>$ipdcpiofile
687	echo 'system/contract/*' >>$ipdcpiofile
688	echo 'system/object/*' >>$ipdcpiofile
689
690	ipdpaxfile=$(/usr/bin/mktemp -t -p /var/tmp ipd.pax.XXXXXX)
691	if [[ -z "$ipdpaxfile" ]]; then
692		rm -f $fstmpfile $ipdcpiofile
693		fatal "$e_tmpfile"
694	fi
695
696	printf "%s " \
697	    "dev devices proc tmp var/run system/contract system/object" \
698	    >>$ipdpaxfile
699
700	# Set up any fs mounts so the archive will install into the correct
701	# locations.
702	get_fs_info
703	mnt_fs
704	if (( $? != 0 )); then
705		umnt_fs >/dev/null 2>&1
706		rm -f $fstmpfile $ipdcpiofile $ipdpaxfile
707		fatal "$mount_failed"
708	fi
709
710	if [[ "$filetype" == "existing" ]]; then
711		log "$no_installing"
712	else
713		log "$installing"
714	fi
715
716	#
717	# Install the image into the zonepath.
718	#
719	unpack_result=0
720	stage1="cat"
721	if [[ "$filetype" == "gzip" ]]; then
722		stage1="gzcat"
723		filetype="cpio"
724	elif [[ "$filetype" == "bzip2" ]]; then
725		stage1="bzcat"
726		filetype="cpio"
727	fi
728
729	if [[ "$filetype" == "cpio" ]]; then
730		install_cpio "$stage1" "$insrc"
731		unpack_result=$?
732
733	elif [[ "$filetype" == "flar" ]]; then
734		( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
735		unpack_result=$?
736
737	elif [[ "$filetype" == "xustar" ]]; then
738		install_pax "$insrc"
739		unpack_result=$?
740
741	elif [[ "$filetype" = "tar" ]]; then
742		vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
743		( cd "$ZONEROOT" && tar -xf "$insrc" )
744		unpack_result=$?
745		post_unpack
746
747	elif [[ "$filetype" == "ufsdump" ]]; then
748		install_ufsdump "$insrc"
749		unpack_result=$?
750
751	elif [[ "$filetype" == "directory" ]]; then
752		install_dir "$insrc"
753		unpack_result=$?
754
755	elif [[ "$filetype" == "zfs" ]]; then
756		#
757		# Given a 'zfs send' stream file, receive the snapshot into
758		# the zone's dataset.  We're getting the original system's
759		# zonepath dataset.  Destroy the existing dataset created
760		# above since this recreates it.
761		#
762		if [[ -z "$DATASET" ]]; then
763			fatal "$f_nodataset"
764		fi
765		/usr/sbin/zfs destroy "$DATASET"
766		if (( $? != 0 )); then
767			log "$f_zfsdestroy" "$DATASET"
768		fi
769
770		vlog "$stage1 $insrc | zfs receive -F $DATASET"
771		( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET )
772		unpack_result=$?
773	fi
774
775	vlog "$unpack_done" $unpack_result
776
777	# Clean up any fs mounts used during unpacking.
778	umnt_fs
779	rm -f $fstmpfile $ipdcpiofile $ipdpaxfile
780
781	#
782	# If the archive was of a zone then the archive might have been made
783	# of the zonepath (single dir), inside the zonepath (dev, root, etc.,
784	# or just even just root) or inside the zonepath root (all the top
785	# level dirs).  Try to normalize these possibilities.
786	#
787	dirsize=$(ls $ZONEROOT | wc -l)
788	if [[ -d $ZONEROOT/root && -d $ZONEROOT/root/etc && \
789	    -d $ZONEROOT/root/var ]]; then
790		# The archive was made of the zoneroot.
791		mkdir -m 0755 $ZONEPATH/.attach_root
792		mv $ZONEROOT/root/* $ZONEPATH/.attach_root
793		mv $ZONEROOT/root/.[a-zA-Z]* $ZONEPATH/.attach_root \
794		    >/dev/null 2>&1
795		rm -rf $ZONEROOT
796		mv $ZONEPATH/.attach_root $ZONEROOT
797
798	elif (( $dirsize == 1 )); then
799		# The archive was made of the the zonepath.
800
801		dir=$(ls $ZONEROOT)
802
803		if [[ -d $ZONEROOT/$dir/root ]]; then
804			mkdir -m 0755 $ZONEPATH/.attach_root
805			mv $ZONEROOT/$dir/root/* $ZONEPATH/.attach_root
806			mv $ZONEROOT/$dir/root/.[a-zA-Z]* \
807			    $ZONEPATH/.attach_root >/dev/null 2>&1
808			rm -rf $ZONEROOT
809			mv $ZONEPATH/.attach_root $ZONEROOT
810		else
811			# We don't know where this archive was made.
812			fatal "$e_bad_zone_layout"
813		fi
814
815	elif [[ ! -d $ZONEROOT/etc ]]; then
816		# We were expecting that the archive was made inside the
817		# zoneroot but there's no etc dir, so we don't know where
818		# this archive was made.
819		fatal "$e_bad_zone_layout"
820	fi
821
822	chmod 700 $zonepath
823
824	# Verify this is a valid image.
825	sanity_check $ZONEROOT
826
827	return 0
828}
829
830# Setup i18n output
831TEXTDOMAIN="SUNW_OST_OSCMD"
832export TEXTDOMAIN
833
834e_baddir=$(gettext "Invalid '%s' directory within the zone")
835e_badfile=$(gettext "Invalid '%s' file within the zone")
836e_bad_zone_layout=$(gettext "Unexpected zone layout.")
837e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
838e_not_found=$(gettext "%s: error: file or directory not found.")
839e_install_abort=$(gettext "Installation aborted.")
840e_not_readable=$(gettext "Cannot read directory '%s'")
841e_not_dir=$(gettext "Error: must be a directory")
842e_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.")
843e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
844e_tmpfile=$(gettext "Unable to create temporary file")
845e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
846
847
848not_readable=$(gettext "Cannot read file '%s'")
849not_flar=$(gettext "Input is not a flash archive")
850bad_flar=$(gettext "Flash archive is a corrupt")
851unknown_archiver=$(gettext "Archiver %s is not supported")
852cmd_not_exec=$(gettext "Required command '%s' not executable!")
853
854#
855# Exit values used by the script, as #defined in <sys/zone.h>
856#
857#	ZONE_SUBPROC_OK
858#	===============
859#	Installation was successful
860#
861#	ZONE_SUBPROC_USAGE
862#	==================
863#	Improper arguments were passed, so print a usage message before exiting
864#
865#	ZONE_SUBPROC_NOTCOMPLETE
866#	========================
867#	Installation did not complete, but another installation attempt can be
868#	made without an uninstall
869#
870#	ZONE_SUBPROC_FATAL
871#	==================
872#	Installation failed and an uninstall will be required before another
873#	install can be attempted
874#
875ZONE_SUBPROC_OK=0
876ZONE_SUBPROC_USAGE=253
877ZONE_SUBPROC_NOTCOMPLETE=254
878ZONE_SUBPROC_FATAL=255
879
880