common.ksh revision 6e1ae2a33c618c4c2b14aec7d2f21743ddea5837
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
#
# Send the error message to the screen and to the logfile.
#
error()
{
typeset fmt="$1"
shift
printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@"
[[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2
}
fatal()
{
typeset fmt="$1"
shift
error "$fmt" "$@"
exit $EXIT_CODE
}
fail_fatal() {
printf "ERROR: "
printf "$@"
printf "\n"
exit $ZONE_SUBPROC_FATAL
}
#
# Send the provided printf()-style arguments to the screen and to the logfile.
#
log()
{
typeset fmt="$1"
shift
printf "${MSG_PREFIX}${fmt}\n" "$@"
[[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
}
#
# Print provided text to the screen if the shell variable "OPT_V" is set.
# The text is always sent to the logfile.
#
vlog()
{
typeset fmt="$1"
shift
[[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@"
[[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
}
#
# Validate that the directory is safe.
#
# It is possible for a malicious zone root user to modify a zone's filesystem
# so that modifications made to the zone's filesystem by administrators in the
# global zone modify the global zone's filesystem. We can prevent this by
# ensuring that all components of paths accessed by scripts are real (i.e.,
# non-symlink) directories.
#
# NOTE: The specified path should be an absolute path as would be seen from
# within the zone. Also, this function does not check parent directories.
# If, for example, you need to ensure that every component of the path
# '/foo/bar/baz' is a directory and not a symlink, then do the following:
#
# safe_dir /foo
# safe_dir /foo/bar
# safe_dir /foo/bar/baz
#
safe_dir()
{
typeset dir="$1"
if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
fatal "$e_baddir" "$dir"
fi
}
# Like safe_dir except the dir doesn't have to exist.
safe_opt_dir()
{
typeset dir="$1"
[[ ! -e $ZONEROOT/$dir ]] && return
if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
fatal "$e_baddir" "$dir"
fi
}
# Only make a copy if we haven't already done so.
safe_backup()
{
typeset src="$1"
typeset dst="$2"
if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then
/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
fi
}
# Make a copy even if the destination already exists.
safe_copy()
{
typeset src="$1"
typeset dst="$2"
if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
/usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
fi
}
# Move a file
safe_move()
{
typeset src="$1"
typeset dst="$2"
if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
/usr/bin/mv $src $dst || fatal "$e_badfile" "$src"
fi
}
safe_rm()
{
if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then
rm -f "$ZONEROOT/$1"
fi
}
#
# Replace the file with a wrapper pointing to the native brand code.
# However, we only do the replacement if the file hasn't already been
# replaced with our wrapper. This function expects the cwd to be the
# location of the file we're replacing.
#
# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm'
# the file before we setup the wrapper while others are hardlinks to rc scripts
# that we need to maintain.
#
safe_replace()
{
typeset filename="$1"
typeset runname="$2"
typeset mode="$3"
typeset own="$4"
typeset rem="$5"
if [ -h $filename -o ! -f $filename ]; then
return
fi
egrep -s "Solaris Brand Replacement" $filename
if [ $? -eq 0 ]; then
return
fi
safe_backup $filename $filename.pre_p2v
if [ $rem = "remove" ]; then
rm -f $filename
fi
cat <<-END >$filename || exit 1
#!/bin/sh -p
#
# Solaris Brand Replacement
#
# Attention. This file has been replaced with a new version for
# use in a virtualized environment. Modification of this script is not
# supported and all changes will be lost upon reboot. The
# {name}.pre_p2v version of this file is a backup copy of the
# original and should not be deleted.
#
END
echo ". $runname \"\$@\"" >>$filename || exit 1
chmod $mode $filename
chown $own $filename
}
safe_wrap()
{
typeset filename="$1"
typeset runname="$2"
typeset mode="$3"
typeset own="$4"
if [ -f $filename ]; then
log "$e_cannot_wrap" "$filename"
exit 1
fi
cat <<-END >$filename || exit 1
#!/bin/sh
#
# Solaris Brand Wrapper
#
# Attention. This file has been created for use in a
# virtualized environment. Modification of this script
# is not supported and all changes will be lost upon reboot.
#
END
echo ". $runname \"\$@\"" >>$filename || exit 1
chmod $mode $filename
chown $own $filename
}
#
# Read zonecfg fs entries and save the relevant data, one entry per
# line.
# This assumes the properties from the zonecfg output, e.g.:
# fs:
# dir: /opt
# special: /opt
# raw not specified
# type: lofs
# options: [noexec,ro,noatime]
#
# and it assumes the order of the fs properties as above.
#
get_fs_info()
{
zonecfg -z $zonename info fs | nawk '{
if ($1 == "options:") {
# Remove brackets.
options=substr($2, 2, length($2) - 2);
printf("%s %s %s %s\n", dir, type, special, options);
} else if ($1 == "dir:") {
dir=$2;
} else if ($1 == "special:") {
special=$2;
} else if ($1 == "type:") {
type=$2
}
}' >> $fstmpfile
}
#
# Mount zonecfg fs entries into the zonepath.
#
mnt_fs()
{
if [ ! -s $fstmpfile ]; then
return;
fi
# Sort the fs entries so we can handle nested mounts.
sort $fstmpfile | nawk -v zonepath=$zonepath '{
if (NF == 4)
options="-o " $4;
else
options=""
# Create the mount point. Ignore errors since we might have
# a nested mount with a pre-existing mount point.
cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1"
system(cmd);
cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \
zonepath "/root" $1;
if (system(cmd) != 0) {
printf("command failed: %s\n", cmd);
exit 1;
}
}' >>$LOGFILE
}
#
# Unmount zonecfg fs entries from the zonepath.
#
umnt_fs()
{
if [ ! -s $fstmpfile ]; then
return;
fi
# Reverse sort the fs entries so we can handle nested unmounts.
sort -r $fstmpfile | nawk -v zonepath=$zonepath '{
cmd="/usr/sbin/umount " zonepath "/root" $1
if (system(cmd) != 0) {
printf("command failed: %s\n", cmd);
}
}' >>$LOGFILE
}
# Find the dataset mounted on the zonepath.
get_zonepath_ds() {
ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \
/usr/bin/nawk -v zonepath=$1 '{
if ($2 == zonepath)
print $1
}'`
if [ -z "$ZONEPATH_DS" ]; then
fail_fatal "$f_no_ds"
fi
}
#
# Perform any cleanup in the zoneroot after unpacking the archive.
#
post_unpack()
{
( cd "$ZONEROOT" && \
find . \( -type b -o -type c \) -exec rm -f "{}" \; )
}
#
# Determine flar compression style from identification file.
#
get_compression()
{
typeset ident=$1
typeset line=$(grep "^files_compressed_method=" $ident)
print ${line##*=}
}
#
# Determine flar archive style from identification file.
#
get_archiver()
{
typeset ident=$1
typeset line=$(grep "^files_archived_method=" $ident)
print ${line##*=}
}
#
# Unpack flar into current directory (which should be zoneroot). The flash
# archive is standard input. See flash_archive(4) man page.
#
# We can't use "flar split" since it will only unpack into a directory called
# "archive". We need to unpack in place in order to properly handle nested
# fs mounts within the zone root. This function does the unpacking into the
# current directory.
#
# This code is derived from the gen_split() function in /usr/sbin/flar so
# we keep the same style as the original.
#
install_flar()
{
typeset result
typeset archiver_command
typeset archiver_arguments
vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar"
# Read cookie
read -r input_line
if (( $? != 0 )); then
log "$not_readable" "$install_media"
return 1
fi
# The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers.
if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then
log "$not_flar"
return 1
fi
while [ true ]
do
# We should always be at the start of a section here
read -r input_line
if [[ ${input_line%%=*} != "section_begin" ]]; then
log "$bad_flar"
return 1
fi
section_name=${input_line##*=}
# If we're at the archive, we're done skipping sections.
if [[ "$section_name" == "archive" ]]; then
break
fi
#
# Save identification section to a file so we can determine
# how to unpack the archive.
#
if [[ "$section_name" == "identification" ]]; then
/usr/bin/rm -f identification
while read -r input_line
do
if [[ ${input_line%%=*} == \
"section_begin" ]]; then
/usr/bin/rm -f identification
log "$bad_flar"
return 1
fi
if [[ $input_line == \
"section_end=$section_name" ]]; then
break;
fi
echo $input_line >> identification
done
continue
fi
#
# Otherwise skip past this section; read lines until detecting
# section_end. According to flash_archive(4) we can have
# an arbitrary number of sections but the archive section
# must be last.
#
success=0
while read -r input_line
do
if [[ $input_line == "section_end=$section_name" ]];
then
success=1
break
fi
# Fail if we miss the end of the section
if [[ ${input_line%%=*} == "section_begin" ]]; then
/usr/bin/rm -f identification
log "$bad_flar"
return 1
fi
done
if (( $success == 0 )); then
#
# If we get here we read to the end of the file before
# seeing the end of the section we were reading.
#
/usr/bin/rm -f identification
log "$bad_flar"
return 1
fi
done
# Check for an archive made from a ZFS root pool.
egrep -s "^rootpool=" identification
if (( $? == 0 )); then
/usr/bin/rm -f identification
log "$bad_zfs_flar"
return 1
fi
# Get the information needed to unpack the archive.
archiver=$(get_archiver identification)
if [[ $archiver == "pax" ]]; then
# pax archiver specified
archiver_command="/usr/bin/pax"
if [[ -s $fspaxfile ]]; then
archiver_arguments="-r -p e -c \
$(/usr/bin/cat $fspaxfile)"
else
archiver_arguments="-r -p e"
fi
elif [[ $archiver == "cpio" || -z $archiver ]]; then
# cpio archived specified OR no archiver specified - use default
archiver_command="/usr/bin/cpio"
archiver_arguments="-icdumfE $fscpiofile"
else
# unknown archiver specified
log "$unknown_archiver" $archiver
return 1
fi
if [[ ! -x $archiver_command ]]; then
/usr/bin/rm -f identification
log "$cmd_not_exec" $archiver_command
return 1
fi
compression=$(get_compression identification)
# We're done with the identification file
/usr/bin/rm -f identification
# Extract archive
if [[ $compression == "compress" ]]; then
/usr/bin/zcat | \
$archiver_command $archiver_arguments 2>/dev/null
else
$archiver_command $archiver_arguments 2>/dev/null
fi
result=$?
post_unpack
(( $result != 0 )) && return 1
return 0
}
#
# Get the archive base.
#
# We must unpack the archive in the right place within the zonepath so
# that files are installed into the various mounted filesystems that are set
# up in the zone's configuration. These are already mounted for us by the
# mntfs function.
#
# Archives can be made of either a physical host's root file system or a
# zone's zonepath. For a physical system, if the archive is made using an
# absolute path (/...) we can't use it. For a zone the admin can make the
# archive from a variety of locations;
#
# a) zonepath itself: This will be a single dir, probably named with the
# zone name, it will contain a root dir and under the root we'll see all
# the top level dirs; etc, var, usr... We must be above the ZONEPATH
# when we unpack the archive but this will only work if the the archive's
# top-level dir name matches the ZONEPATH base-level dir name. If not,
# this is an error.
#
# b) inside the zonepath: We'll see root and it will contain all the top
# level dirs; etc, var, usr.... We must be in the ZONEPATH when we unpack
# the archive.
#
# c) inside the zonepath root: We'll see all the top level dirs, ./etc,
# ./var, ./usr.... This is also the case we see when we get an archive
# of a physical sytem. We must be in ZONEROOT when we unpack the archive.
#
# Note that there can be a directory named "root" under the ZONEPATH/root
# directory.
#
# This function handles the above possibilities so that we reject absolute
# path archives and figure out where in the file system we need to be to
# properly unpack the archive into the zone. It sets the ARCHIVE_BASE
# variable to the location where the achive should be unpacked.
#
get_archive_base()
{
stage1=$1
archive=$2
stage2=$3
vlog "$m_analyse_archive"
base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{
# Check for an absolute path archive
if (substr($0, 1, 1) == "/")
exit 1
if ($1 != ".")
dirs[$1] = 1
else
dirs[$2] = 1
}
END {
for (d in dirs) {
cnt++
if (d == "bin") sawbin = 1
if (d == "etc") sawetc = 1
if (d == "root") sawroot = 1
if (d == "var") sawvar = 1
}
if (cnt == 1) {
# If only one top-level dir named root, we are in the
# zonepath, otherwise this must be an archive *of*
# the zonepath so print the top-level dir name.
if (sawroot)
print "*zonepath*"
else
for (d in dirs) print d
} else {
# We are either in the zonepath or in the zonepath/root
# (or at the top level of a full system archive which
# looks like the zonepath/root case). Figure out which
# one.
if (sawroot && !sawbin && !sawetc && !sawvar)
print "*zonepath*"
else
print "*zoneroot*"
}
}'`
if (( $? != 0 )); then
umnt_fs
fatal "$e_absolute_archive"
fi
if [[ "$base" == "*zoneroot*" ]]; then
ARCHIVE_BASE=$ZONEROOT
elif [[ "$base" == "*zonepath*" ]]; then
ARCHIVE_BASE=$ZONEPATH
else
# We need to be in the dir above the ZONEPATH but we need to
# validate that $base matches the final component of ZONEPATH.
bname=`basename $ZONEPATH`
if [[ "$bname" != "$base" ]]; then
umnt_fs
fatal "$e_mismatch_archive" "$base" "$bname"
fi
ARCHIVE_BASE=`dirname $ZONEPATH`
fi
}
#
# Unpack cpio archive into zoneroot.
#
install_cpio()
{
stage1=$1
archive=$2
get_archive_base "$stage1" "$archive" "cpio -it"
cpioopts="-idmfE $fscpiofile"
vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts"
# Ignore errors from cpio since we expect some errors depending on
# how the archive was made.
( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts )
post_unpack
return 0
}
#
# Unpack pax archive into zoneroot.
#
install_pax()
{
archive=$1
get_archive_base "cat" "$archive" "pax"
if [[ -s $fspaxfile ]]; then
filtopt="-c $(/usr/bin/cat $fspaxfile)"
fi
vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt"
# Ignore errors from pax since we expect some errors depending on
# how the archive was made.
( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt )
post_unpack
return 0
}
#
# Unpack UFS dump into zoneroot.
#
install_ufsdump()
{
archive=$1
vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\""
#
# ufsrestore goes interactive if you ^C it. To prevent that,
# we make sure its stdin is not a terminal.
#
( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
result=$?
post_unpack
return $result
}
#
# Copy directory hierarchy into zoneroot.
#
install_dir()
{
source_dir=$1
cpioopts="-pdm"
first=1
filt=$(for i in $(cat $fspaxfile)
do
echo $i | egrep -s "/" && continue
if [[ $first == 1 ]]; then
printf "^%s" $i
first=0
else
printf "|^%s" $i
fi
done)
list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
flist=$(for i in $list
do
printf "%s " "$i"
done)
findopts="-xdev ( -type d -o -type f -o -type l ) -print"
vlog "cd \"$source_dir\" && find $flist $findopts | "
vlog "cpio $cpioopts \"$ZONEROOT\""
# Ignore errors from cpio since we expect some errors depending on
# how the archive was made.
( cd "$source_dir" && find $flist $findopts | \
cpio $cpioopts "$ZONEROOT" )
post_unpack
return 0
}
#
# This is a common function for laying down a zone image from a variety of
# different sources. This can be used to either install a fresh zone or as
# part of zone migration during attach.
#
# The first argument specifies the type of image: archive, directory or stdin.
# The second argument specifies the image itself. In the case of stdin, the
# second argument specifies the format of the stream (cpio, flar, etc.).
# Any validation or post-processing on the image is done elsewhere.
#
# This function calls a 'sanity_check' function which must be provided by
# the script which includes this code.
#
install_image()
{
intype=$1
insrc=$2
if [[ -z "$intype" || -z "$insrc" ]]; then
return 1
fi
filetype="unknown"
filetypename="unknown"
stage1="cat"
if [[ "$intype" == "directory" ]]; then
if [[ "$insrc" == "-" ]]; then
# Indicates that the existing zonepath is prepopulated.
filetype="existing"
filetypename="existing"
else
if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
fatal "$e_path_abs" "$insrc"
fi
if [[ ! -e "$insrc" ]]; then
log "$e_not_found" "$insrc"
fatal "$e_install_abort"
fi
if [[ ! -r "$insrc" ]]; then
log "$e_not_readable" "$insrc"
fatal "$e_install_abort"
fi
if [[ ! -d "$insrc" ]]; then
log "$e_not_dir"
fatal "$e_install_abort"
fi
sanity_check $insrc
filetype="directory"
filetypename="directory"
fi
else
# Common code for both archive and stdin stream.
if [[ "$intype" == "archive" ]]; then
if [[ ! -f "$insrc" ]]; then
log "$e_unknown_archive"
fatal "$e_install_abort"
fi
ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
else
# For intype == stdin, the insrc parameter specifies
# the stream format coming on stdin.
ftype="$insrc"
insrc="-"
fi
# Setup vars for the archive type we have.
case "$ftype" in
*cpio*) filetype="cpio"
filetypename="cpio archive"
;;
*bzip2*) filetype="bzip2"
filetypename="bzipped cpio archive"
;;
*gzip*) filetype="gzip"
filetypename="gzipped cpio archive"
;;
*ufsdump*) filetype="ufsdump"
filetypename="ufsdump archive"
;;
"flar")
filetype="flar"
filetypename="flash archive"
;;
"flash")
filetype="flar"
filetypename="flash archive"
;;
*Flash\ Archive*)
filetype="flar"
filetypename="flash archive"
;;
"tar")
filetype="tar"
filetypename="tar archive"
;;
*USTAR\ tar\ archive)
filetype="tar"
filetypename="tar archive"
;;
"pax")
filetype="xustar"
filetypename="pax (xustar) archive"
;;
*USTAR\ tar\ archive\ extended\ format*)
filetype="xustar"
filetypename="pax (xustar) archive"
;;
"zfs")
filetype="zfs"
filetypename="ZFS send stream"
;;
*ZFS\ snapshot\ stream*)
filetype="zfs"
filetypename="ZFS send stream"
;;
*) log "$e_unknown_archive"
fatal "$e_install_abort"
;;
esac
fi
vlog "$filetypename"
# Check for a non-empty root if no '-d -' option.
if [[ "$filetype" != "existing" ]]; then
cnt=$(ls $ZONEROOT | wc -l)
if (( $cnt != 0 )); then
fatal "$e_root_full" "$ZONEROOT"
fi
fi
fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
if [[ -z "$fstmpfile" ]]; then
fatal "$e_tmpfile"
fi
# Make sure we always have the files holding the directories to filter
# out when extracting from a CPIO or PAX archive. We'll add the fs
# entries to these files in get_fs_info()
fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX)
if [[ -z "$fscpiofile" ]]; then
rm -f $fstmpfile
fatal "$e_tmpfile"
fi
# Filter out these directories.
echo 'dev/*' >>$fscpiofile
echo 'devices/*' >>$fscpiofile
echo 'devices' >>$fscpiofile
echo 'proc/*' >>$fscpiofile
echo 'tmp/*' >>$fscpiofile
echo 'var/run/*' >>$fscpiofile
echo 'system/contract/*' >>$fscpiofile
echo 'system/object/*' >>$fscpiofile
fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX)
if [[ -z "$fspaxfile" ]]; then
rm -f $fstmpfile $fscpiofile
fatal "$e_tmpfile"
fi
printf "%s " \
"dev devices proc tmp var/run system/contract system/object" \
>>$fspaxfile
# Set up any fs mounts so the archive will install into the correct
# locations.
get_fs_info
mnt_fs
if (( $? != 0 )); then
umnt_fs >/dev/null 2>&1
rm -f $fstmpfile $fscpiofile $fspaxfile
fatal "$mount_failed"
fi
if [[ "$filetype" == "existing" ]]; then
log "$no_installing"
else
log "$installing"
fi
#
# Install the image into the zonepath.
#
unpack_result=0
stage1="cat"
if [[ "$filetype" == "gzip" ]]; then
stage1="gzcat"
filetype="cpio"
elif [[ "$filetype" == "bzip2" ]]; then
stage1="bzcat"
filetype="cpio"
fi
if [[ "$filetype" == "cpio" ]]; then
install_cpio "$stage1" "$insrc"
unpack_result=$?
elif [[ "$filetype" == "flar" ]]; then
( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
unpack_result=$?
elif [[ "$filetype" == "xustar" ]]; then
install_pax "$insrc"
unpack_result=$?
elif [[ "$filetype" = "tar" ]]; then
vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
# Ignore errors from tar since we expect some errors depending
# on how the archive was made.
( cd "$ZONEROOT" && tar -xf "$insrc" )
unpack_result=0
post_unpack
elif [[ "$filetype" == "ufsdump" ]]; then
install_ufsdump "$insrc"
unpack_result=$?
elif [[ "$filetype" == "directory" ]]; then
install_dir "$insrc"
unpack_result=$?
elif [[ "$filetype" == "zfs" ]]; then
#
# Given a 'zfs send' stream file, receive the snapshot into
# the zone's dataset. We're getting the original system's
# zonepath dataset. Destroy the existing dataset created
# above since this recreates it.
#
if [[ -z "$DATASET" ]]; then
fatal "$f_nodataset"
fi
/usr/sbin/zfs destroy "$DATASET"
if (( $? != 0 )); then
log "$f_zfsdestroy" "$DATASET"
fi
vlog "$stage1 $insrc | zfs receive -F $DATASET"
( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET )
unpack_result=$?
fi
# Clean up any fs mounts used during unpacking.
umnt_fs
rm -f $fstmpfile $fscpiofile $fspaxfile
chmod 700 $zonepath
(( $unpack_result != 0 )) && fatal "$f_unpack_failed"
# Verify this is a valid image.
sanity_check $ZONEROOT
return 0
}
# Setup i18n output
TEXTDOMAIN="SUNW_OST_OSCMD"
export TEXTDOMAIN
e_cannot_wrap=$(gettext "%s: error: wrapper file already exists")
e_baddir=$(gettext "Invalid '%s' directory within the zone")
e_badfile=$(gettext "Invalid '%s' file within the zone")
e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
e_not_found=$(gettext "%s: error: file or directory not found.")
e_install_abort=$(gettext "Installation aborted.")
e_not_readable=$(gettext "Cannot read directory '%s'")
e_not_dir=$(gettext "Error: must be a directory")
e_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.")
e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).")
e_tmpfile=$(gettext "Unable to create temporary file")
e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
f_mkdir=$(gettext "Unable to create directory %s.")
f_chmod=$(gettext "Unable to chmod directory %s.")
f_chown=$(gettext "Unable to chown directory %s.")
m_analyse_archive=$(gettext "Analysing the archive")
not_readable=$(gettext "Cannot read file '%s'")
not_flar=$(gettext "Input is not a flash archive")
bad_flar=$(gettext "Flash archive is a corrupt")
bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.")
f_unpack_failed=$(gettext "Unpacking the archive failed")
unknown_archiver=$(gettext "Archiver %s is not supported")
cmd_not_exec=$(gettext "Required command '%s' not executable!")
#
# Exit values used by the script, as #defined in <sys/zone.h>
#
# ZONE_SUBPROC_OK
# ===============
# Installation was successful
#
# ZONE_SUBPROC_USAGE
# ==================
# Improper arguments were passed, so print a usage message before exiting
#
# ZONE_SUBPROC_NOTCOMPLETE
# ========================
# Installation did not complete, but another installation attempt can be
# made without an uninstall
#
# ZONE_SUBPROC_FATAL
# ==================
# Installation failed and an uninstall will be required before another
# install can be attempted
#
ZONE_SUBPROC_OK=0
ZONE_SUBPROC_USAGE=253
ZONE_SUBPROC_NOTCOMPLETE=254
ZONE_SUBPROC_FATAL=255