Mercurial > illumos > illumos-gate
changeset 10378:bca9668e9ba5
6869648 zone v2v normalization should handle delegated zfs root dataset
author | Gerald Jelinek <Gerald.Jelinek@Sun.COM> |
---|---|
date | Tue, 25 Aug 2009 11:08:24 -0700 |
parents | 596c39d50e2a |
children | 77c6e44298ee |
files | usr/src/lib/brand/native/zone/common.ksh |
diffstat | 1 files changed, 114 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/brand/native/zone/common.ksh Tue Aug 25 08:25:56 2009 -0700 +++ b/usr/src/lib/brand/native/zone/common.ksh Tue Aug 25 11:08:24 2009 -0700 @@ -402,6 +402,111 @@ } # +# 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() @@ -409,20 +514,13 @@ stage1=$1 archive=$2 - # Check the first few members of the archive for an absolute path. - for i in `$stage1 "$archive" | cpio -it | head | cut -b1` - do - if [[ "$i" == "/" ]]; then - umnt_fs - fatal "$e_absolute_archive" - fi - done + get_archive_base "$stage1" "$archive" "cpio -it" cpioopts="-idmfE $ipdcpiofile" - vlog "cd \"$ZONEROOT\" && $stage1 \"$archive\" | cpio $cpioopts" + vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts" - ( cd "$ZONEROOT" && $stage1 "$archive" | cpio $cpioopts ) + ( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts ) result=$? post_unpack @@ -437,22 +535,15 @@ { archive=$1 - # Check the first few members of the archive for an absolute path. - for i in `pax -f "$archive" | head | cut -b1` - do - if [[ "$i" == "/" ]]; then - umnt_fs - fatal "$e_absolute_archive" - fi - done + get_archive_base "cat" "$archive" "pax" if [[ -s $ipdpaxfile ]]; then filtopt="-c $(/usr/bin/cat $ipdpaxfile)" fi - vlog "cd \"$ZONEROOT\" && pax -r -f \"$archive\" $filtopt" + vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt" - ( cd "$ZONEROOT" && pax -r -f "$archive" $filtopt ) + ( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt ) result=$? post_unpack @@ -778,47 +869,6 @@ umnt_fs rm -f $fstmpfile $ipdcpiofile $ipdpaxfile - # - # If the archive was of a zone then the archive might have been made - # of the zonepath (single dir), inside the zonepath (dev, root, etc., - # or just even just root) or inside the zonepath root (all the top - # level dirs). Try to normalize these possibilities. - # - dirsize=$(ls $ZONEROOT | wc -l) - if [[ -d $ZONEROOT/root && -d $ZONEROOT/root/etc && \ - -d $ZONEROOT/root/var ]]; then - # The archive was made of the zoneroot. - mkdir -m 0755 $ZONEPATH/.attach_root - mv $ZONEROOT/root/* $ZONEPATH/.attach_root - mv $ZONEROOT/root/.[a-zA-Z]* $ZONEPATH/.attach_root \ - >/dev/null 2>&1 - rm -rf $ZONEROOT - mv $ZONEPATH/.attach_root $ZONEROOT - - elif (( $dirsize == 1 )); then - # The archive was made of the the zonepath. - - dir=$(ls $ZONEROOT) - - if [[ -d $ZONEROOT/$dir/root ]]; then - mkdir -m 0755 $ZONEPATH/.attach_root - mv $ZONEROOT/$dir/root/* $ZONEPATH/.attach_root - mv $ZONEROOT/$dir/root/.[a-zA-Z]* \ - $ZONEPATH/.attach_root >/dev/null 2>&1 - rm -rf $ZONEROOT - mv $ZONEPATH/.attach_root $ZONEROOT - else - # We don't know where this archive was made. - fatal "$e_bad_zone_layout" - fi - - elif [[ ! -d $ZONEROOT/etc ]]; then - # We were expecting that the archive was made inside the - # zoneroot but there's no etc dir, so we don't know where - # this archive was made. - fatal "$e_bad_zone_layout" - fi - chmod 700 $zonepath # Verify this is a valid image. @@ -833,7 +883,6 @@ e_baddir=$(gettext "Invalid '%s' directory within the zone") e_badfile=$(gettext "Invalid '%s' file within the zone") -e_bad_zone_layout=$(gettext "Unexpected zone layout.") 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.") @@ -841,10 +890,13 @@ 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.") +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")