Mercurial > illumos > illumos-gate
changeset 8759:8436cd998603
PSARC 2008/766 native zones p2v
6667924 physical to virtual utility for native zones
line wrap: on
line diff
--- a/usr/src/Targetdirs Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/Targetdirs Wed Feb 11 09:33:05 2009 -0700 @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -78,6 +78,8 @@ /devices \ /devices/pseudo \ /etc \ + /etc/brand \ + /etc/brand/native \ /etc/certs \ /etc/cron.d \ /etc/crypto \ @@ -259,6 +261,7 @@ /usr/lib/abi \ /usr/lib/brand \ /usr/lib/brand/native \ + /usr/lib/brand/shared \ /usr/lib/brand/sn1 \ /usr/lib/class \ /usr/lib/class/FSS \
--- a/usr/src/cmd/zoneadm/zoneadm.c Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/cmd/zoneadm/zoneadm.c Wed Feb 11 09:33:05 2009 -0700 @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -102,7 +102,6 @@ static zone_entry_t *zents; static size_t nzents; -static boolean_t is_native_zone = B_TRUE; #define LOOPBACK_IF "lo0" #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af)) @@ -1087,10 +1086,6 @@ return (Z_ERR); } if ((res = stat(rootpath, &stbuf)) == 0) { - struct dirent *dp; - DIR *dirp; - boolean_t empty = B_TRUE; - if (zonecfg_detached(rpath)) { (void) fprintf(stderr, gettext("Cannot %s detached " @@ -1119,32 +1114,6 @@ "0755.\n"), rootpath); return (Z_ERR); } - - if ((dirp = opendir(rootpath)) == NULL) { - (void) fprintf(stderr, gettext("Could not " - "open rootpath %s\n"), rootpath); - return (Z_ERR); - } - - /* Verify that the dir is empty. */ - while ((dp = readdir(dirp)) != NULL) { - if (strcmp(dp->d_name, ".") == 0 || - strcmp(dp->d_name, "..") == 0) - continue; - - empty = B_FALSE; - break; - } - (void) closedir(dirp); - - if (!empty) { - (void) fprintf(stderr, gettext("Rootpath %s " - "exists and contains data; remove or move " - "aside prior to %s.\n"), rootpath, - cmd_to_str(cmd_num)); - return (Z_ERR); - } - } } @@ -1713,6 +1682,17 @@ } break; case CMD_ATTACH: + if (state == ZONE_STATE_INSTALLED) { + zerror(gettext("is already %s."), + zone_state_str(ZONE_STATE_INSTALLED)); + return (Z_ERR); + } else if (state == ZONE_STATE_INCOMPLETE && !force) { + zerror(gettext("zone is %s; %s required."), + zone_state_str(ZONE_STATE_INCOMPLETE), + cmd_to_str(CMD_UNINSTALL)); + return (Z_ERR); + } + break; case CMD_CLONE: case CMD_INSTALL: if (state == ZONE_STATE_INSTALLED) { @@ -1735,15 +1715,11 @@ if ((cmd_num == CMD_BOOT || cmd_num == CMD_MOUNT) && force) min_state = ZONE_STATE_INCOMPLETE; + else if (cmd_num == CMD_MARK) + min_state = ZONE_STATE_CONFIGURED; else min_state = ZONE_STATE_INSTALLED; - if (force && cmd_num == CMD_BOOT && is_native_zone) { - zerror(gettext("Only branded zones may be " - "force-booted.")); - return (Z_ERR); - } - if (state < min_state) { zerror(gettext("must be %s before %s."), zone_state_str(min_state), @@ -4625,6 +4601,10 @@ int manifest_pos; brand_handle_t bh = NULL; int status; + int last_index = 0; + int offset; + char *up; + boolean_t forced_update = B_FALSE; if (zonecfg_in_alt_root()) { zerror(gettext("cannot attach zone in alternate root")); @@ -4634,7 +4614,7 @@ /* Check the argv string for args we handle internally */ optind = 0; opterr = 0; - while ((arg = getopt(argc, argv, "?Fn:")) != EOF) { + while ((arg = getopt(argc, argv, "?Fn:U")) != EOF) { switch (arg) { case '?': if (optopt == '?') { @@ -4651,10 +4631,25 @@ manifest_path = optarg; manifest_pos = optind - 1; break; + case 'U': + /* + * Undocumented 'force update' option for p2v update on + * attach when zone is in the incomplete state. Change + * the option back to 'u' and set forced_update flag. + */ + if (optind == last_index) + offset = optind; + else + offset = optind - 1; + if ((up = index(argv[offset], 'U')) != NULL) + *up = 'u'; + forced_update = B_TRUE; + break; default: /* Ignore unknown options - may be brand specific. */ break; } + last_index = optind; } if (brand_help) { @@ -4676,7 +4671,7 @@ if (execute) { if (!brand_help) { if (sanity_check(target_zone, CMD_ATTACH, B_FALSE, - B_TRUE, B_FALSE) != Z_OK) + B_TRUE, forced_update) != Z_OK) return (Z_ERR); if (verify_details(CMD_ATTACH, argv) != Z_OK) return (Z_ERR); @@ -4749,14 +4744,14 @@ */ if (cmdbuf[0] != '\0') { /* Run the attach hook */ - status = do_subproc_interactive(cmdbuf); + status = do_subproc(cmdbuf); if ((status = subproc_status(gettext("brand-specific " "attach"), status, B_FALSE)) != ZONE_SUBPROC_OK) { if (status == ZONE_SUBPROC_USAGE && !brand_help) sub_usage(SHELP_ATTACH, CMD_ATTACH); if (execute && !brand_help) { - assert(lockfd >= 0); + assert(zonecfg_lock_file_held(&lockfd)); zonecfg_release_lock_file(target_zone, lockfd); lockfd = -1; @@ -4799,7 +4794,7 @@ zperror(gettext("could not reset state"), B_TRUE); } - assert(lockfd >= 0); + assert(zonecfg_lock_file_held(&lockfd)); zonecfg_release_lock_file(target_zone, lockfd); lockfd = -1; @@ -5118,10 +5113,38 @@ mark_func(int argc, char *argv[]) { int err, lockfd; - - if (argc != 1 || strcmp(argv[0], "incomplete") != 0) + int arg; + boolean_t force = B_FALSE; + int state; + + optind = 0; + opterr = 0; + while ((arg = getopt(argc, argv, "F")) != EOF) { + switch (arg) { + case 'F': + force = B_TRUE; + break; + default: + return (Z_USAGE); + } + } + + if (argc != (optind + 1)) return (Z_USAGE); - if (sanity_check(target_zone, CMD_MARK, B_FALSE, B_FALSE, B_FALSE) + + if (strcmp(argv[optind], "configured") == 0) + state = ZONE_STATE_CONFIGURED; + else if (strcmp(argv[optind], "incomplete") == 0) + state = ZONE_STATE_INCOMPLETE; + else if (strcmp(argv[optind], "installed") == 0) + state = ZONE_STATE_INSTALLED; + else + return (Z_USAGE); + + if (state != ZONE_STATE_INCOMPLETE && !force) + return (Z_USAGE); + + if (sanity_check(target_zone, CMD_MARK, B_FALSE, B_TRUE, B_FALSE) != Z_OK) return (Z_ERR); @@ -5137,7 +5160,7 @@ return (Z_ERR); } - err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE); + err = zone_set_state(target_zone, state); if (err != Z_OK) { errno = err; zperror2(target_zone, gettext("could not set state")); @@ -5592,7 +5615,6 @@ zerror(gettext("missing or invalid brand")); exit(Z_ERR); } - is_native_zone = (strcmp(target_brand, NATIVE_BRAND_NAME) == 0); } err = parse_and_run(argc - optind, &argv[optind]);
--- a/usr/src/head/libzonecfg.h Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/head/libzonecfg.h Wed Feb 11 09:33:05 2009 -0700 @@ -558,6 +558,7 @@ extern void zonecfg_init_lock_file(const char *, char **); extern void zonecfg_release_lock_file(const char *, int); extern int zonecfg_grab_lock_file(const char *, int *); +extern boolean_t zonecfg_lock_file_held(int *); extern int zonecfg_ping_zoneadmd(const char *); extern int zonecfg_call_zoneadmd(const char *, zone_cmd_arg_t *, char *, boolean_t);
--- a/usr/src/lib/brand/Makefile.brand Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/brand/Makefile.brand Wed Feb 11 09:33:05 2009 -0700 @@ -19,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" include $(SRC)/Makefile.master @@ -30,10 +29,12 @@ ROOTTEMPLATEDIR= $(ROOT)/etc/zones ROOTBRANDDIR= $(ROOTDIR)/$(BRAND) ROOTBRANDDIR64= $(ROOTDIR)/$(BRAND)/$(MACH64) +ROOTSHAREDDIR= $(ROOTDIR)/shared ROOTPROGS= $(PROGS:%=$(ROOTBRANDDIR)/%) ROOTTXTS= $(TXTS:%=$(ROOTBRANDDIR)/%) ROOTXMLDOCS= $(XMLDOCS:%=$(ROOTBRANDDIR)/%) +ROOTSHARED= $(SHARED:%=$(ROOTSHAREDDIR)/%) ROOTTEMPLATES= $(TEMPLATES:%=$(ROOTTEMPLATEDIR)/%) @@ -45,6 +46,10 @@ $(ROOTXMLDOCS) := OWNER = root $(ROOTXMLDOCS) := GROUP = bin +$(ROOTSHARED) := FILEMODE = 444 +$(ROOTSHARED) := OWNER = root +$(ROOTSHARED) := GROUP = bin + $(ROOTTEMPLATEDIR) := FILEMODE = 755 $(ROOTTEMPLATEDIR) := OWNER = root $(ROOTTEMPLATEDIR) := GROUP = sys @@ -61,7 +66,7 @@ $(ROOTPROGS) := OWNER = root $(ROOTPROGS) := GROUP = bin -$(ROOTBRANDDIR)/% $(ROOTBRANDDIR64)/% $(ROOTTEMPLATEDIR)/%: % +$(ROOTBRANDDIR)/% $(ROOTBRANDDIR64)/% $(ROOTTEMPLATEDIR)/% $(ROOTSHAREDDIR)/%: % $(INS.file) .SUFFIXES: .ksh
--- a/usr/src/lib/brand/lx/zone/lx_install.ksh Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/brand/lx/zone/lx_install.ksh Wed Feb 11 09:33:05 2009 -0700 @@ -85,6 +85,8 @@ no_log=$(gettext "Could not create log directory '%s'") no_logfile=$(gettext "Could not create log file '%s'") +root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.") + install_zone=$(gettext "Installing zone '%s' at root directory '%s'") install_from=$(gettext "from archive '%s'") @@ -457,6 +459,15 @@ fi fi +# +# Check for a non-empty root. +# +cnt=`ls $install_root | wc -l` +if [ $cnt -ne 0 ]; then + screenlog "$root_full" "$install_root" + exit $int_code +fi + if [[ ! -d "$logdir" ]] then if ! mkdir -p "$logdir" 2>/dev/null; then
--- a/usr/src/lib/brand/native/zone/Makefile Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/brand/native/zone/Makefile Wed Feb 11 09:33:05 2009 -0700 @@ -20,18 +20,28 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# + +ETCBRANDDIR= $(ROOT)/etc/brand/native +ETCUSER= $(USERFILES:%=$(ETCBRANDDIR)/%) +$(ETCUSER) := FILEMODE = 644 +$(ETCUSER) := OWNER = root +$(ETCUSER) := GROUP = sys + +$(ETCBRANDDIR)/%: % + $(INS.file) PROG= sw_support BRAND= native -PROGS= attach_update $(PROG) -XMLDOCS= config.xml platform.xml +PROGS= attach_update image_install p2v $(PROG) +XMLDOCS= config.xml platform.xml smf_disable.lst pkgrm.lst +USERFILES= smf_disable.conf pkgrm.conf +SHARED= common.ksh TEMPLATES= SUNWdefault.xml SUNWblank.xml -CLOBBERFILES= $(ROOTPROGS) $(ROOTXMLDOCS) $(ROOTTEMPLATES) +CLOBBERFILES= $(ROOTPROGS) $(ROOTXMLDOCS) $(ROOTTEMPLATES) $(ROOTSHARED) \ + $(ETCUSER) all: $(PROGS) @@ -52,7 +62,8 @@ lint: lint_PROG -install: $(PROGS) $(ROOTPROGS) $(ROOTXMLDOCS) $(ROOTTEMPLATES) +install: $(PROGS) $(ROOTPROGS) $(ROOTXMLDOCS) $(ROOTTEMPLATES) $(ROOTSHARED) \ + $(ETCUSER) clean: -$(RM) $(PROGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/common.ksh Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,516 @@ +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# 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 +} + +# +# 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. +safe_dir() +{ + typeset dir="$1" + + 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 +} + +# +# Read zonecfg ipd and fs entries and save the relevant data, one entry per +# line. +# This assumes the properties from the zonecfg output, e.g.: +# inherit-pkg-dir: +# dir: /usr +# 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. This also saves the +# inherit-pkg-dir patterns into the ipd.{cpio|pax} temporary files for +# filtering while extracting the image into the zonepath. We have to save the +# IPD patterns in the appropriate format for filtering with the different +# archivers and we don't know what format we'll get until after the flash +# archive is unpacked. +# +get_fs_info() +{ + zonecfg -z $zonename info inherit-pkg-dir | \ + nawk -v ipdcpiof=$ipdcpiofile -v ipdpaxf=$ipdpaxfile '{ + if ($1 == "dir:") { + dir=$2; + printf("%s lofs %s ro\n", dir, dir); + + if (substr(dir, 1, 1) == "/") { + printf("%s\n", substr(dir, 2)) >> ipdcpiof + printf("%s/*\n", substr(dir, 2)) >> ipdcpiof + } else { + printf("%s\n", dir) >> ipdcpiof + printf("%s/*\n", dir) >> ipdcpiof + } + + if (substr(dir, 1, 1) == "/") { + printf("%s ", substr(dir, 2)) >> ipdpaxf + } else { + printf("%s ", dir) >> ipdpaxf + } + } + }' >> $fstmpfile + + 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 +} + +# +# 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 && do_flar < \"$install_archive\"" + + # 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 + + # 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 $ipdpaxfile ]]; then + archiver_arguments="-r -p e -c \ + $(/usr/bin/cat $ipdpaxfile)" + 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 $ipdcpiofile" + 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 | ppriv -e -s A=all,-sys_devices \ + $archiver_command $archiver_arguments 2>/dev/null + else + ppriv -e -s A=all,-sys_devices \ + $archiver_command $archiver_arguments 2>/dev/null + fi + result=$? + + (( $result != 0 )) && return 1 + + return 0 +} + +# +# Unpack cpio archive into zoneroot. +# +install_cpio() +{ + stage1=$1 + archive=$2 + + cpioopts="-idmfE $ipdcpiofile" + + vlog "cd \"$ZONEROOT\" && $stage1 \"$archive\" | " + vlog "ppriv -e -s A=all,-sys_devices cpio $cpioopts" + + ( cd "$ZONEROOT" && $stage1 "$archive" | \ + ppriv -e -s A=all,-sys_devices cpio $cpioopts ) +} + +# +# Unpack pax archive into zoneroot. +# +install_pax() +{ + archive=$1 + + if [[ -s $ipdpaxfile ]]; then + filtopt="-c $(/usr/bin/cat $ipdpaxfile)" + fi + + vlog "cd \"$ZONEROOT\" && " + vlog "ppriv -e -s A=all,-sys_devices pax -r -f \"$archive\" $filtopt" + + ( cd "$ZONEROOT" && ppriv -e -s A=all,-sys_devices \ + pax -r -f "$archive" $filtopt ) +} + +# +# Unpack UFS dump into zoneroot. +# +install_ufsdump() +{ + archive=$1 + + vlog "cd \"$ZONEROOT\" && " + vlog "ppriv -e -s A=all,-sys_devices ufsrestore rf \"$archive\"" + + # + # ufsrestore goes interactive if you ^C it. To prevent that, + # we make sure its stdin is not a terminal. + # Note that there is no way to filter inherit-pkg-dirs for a full + # restore so there will be warnings in the log file. + # + ( cd "$ZONEROOT" && ppriv -e -s A=all,-sys_devices \ + ufsrestore rf "$archive" < /dev/null ) +} + +# +# Copy directory hierarchy into zoneroot. +# +install_dir() +{ + source_dir=$1 + + cpioopts="-pdm" + + first=1 + filt=$(for i in $(cat $ipdpaxfile) + 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 "ppriv -e -s A=all,-sys_devices cpio $cpioopts \"$ZONEROOT\"" + + ( cd "$source_dir" && find $flist $findopts | \ + ppriv -e -s A=all,-sys_devices cpio $cpioopts "$ZONEROOT" ) +} + +# Setup i18n output +TEXTDOMAIN="SUNW_OST_OSCMD" +export TEXTDOMAIN + +e_baddir=$(gettext "Invalid '%s' directory within the zone") +e_badfile=$(gettext "Invalid '%s' file within the zone") + +# +# 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 +
--- a/usr/src/lib/brand/native/zone/config.xml Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/brand/native/zone/config.xml Wed Feb 11 09:33:05 2009 -0700 @@ -20,7 +20,7 @@ CDDL HEADER END - Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. DO NOT EDIT THIS FILE. @@ -37,6 +37,7 @@ <user_cmd>/usr/bin/getent passwd %u</user_cmd> <install>/usr/lib/brand/native/sw_support install %z %R</install> + <installopts>a:b:d:psuv</installopts> <verify_cfg></verify_cfg> <verify_adm></verify_adm> <postclone>/usr/lib/brand/native/sw_support postclone %z %R</postclone>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/image_install.ksh Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,517 @@ +#!/bin/ksh -p +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. /usr/lib/brand/shared/common.ksh + +# Restrict executables to /bin, /usr/bin and /usr/sfw/bin +PATH=/bin:/usr/bin:/usr/sbin:/usr/sfw/bin +export PATH + +cmd_not_found=$(gettext "Required command '%s' cannot be found!") +cmd_not_exec=$(gettext "Required command '%s' not executable!") +zone_initfail=$(gettext "Attempt to initialize zone '%s' FAILED.") +path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.") + +e_tmpfile=$(gettext "Unable to create temporary file") + +both_modes=$(gettext "%s: cannot select both silent and verbose modes") + +both_choices=$(gettext "%s: cannot select both preserve and unconfigure options") + +both_kinds=$(gettext "%s: cannot specify both archive and directory") + +not_found=$(gettext "%s: error: file or directory not found.") + +wrong_dir_type=$(gettext "error: must be a directory") + +not_readable=$(gettext "Cannot read file '%s'") + +no_install=$(gettext "Could not create install directory '%s'") +no_log=$(gettext "Could not create log directory '%s'") + +media_taste=$(gettext " Media Type: %s") +bad_archive=$(gettext "ERROR: must be a flash archive, a cpio archive (can also +be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.") + +product_vers=$(gettext " Product: %s") +install_vers=$(gettext " Installer: %s") +install_zone=$(gettext " Zone: %s") +install_path=$(gettext " Path: %s") +install_from=$(gettext " Source: %s") +installing=$(gettext " Installing: This may take several minutes...") +no_installing=$(gettext " Installing: Using pre-existing data in zonepath") +install_prog=$(gettext " Installing: %s") + +install_fail=$(gettext " Result: *** Installation FAILED ***") +install_log=$(gettext " Log File: %s") + +install_abort=$(gettext " Result: Installation aborted.") +install_good=$(gettext " Result: Installation completed successfully.") + +not_native_image=$(gettext " Sanity Check: %s doesn't look like a native image.") +sanity_ok=$(gettext " Sanity Check: Passed. Looks like a native system.") +sanity_fail_detail=$(gettext " Sanity Check: Missing %s at %s") +sanity_fail_vers=$(gettext " Sanity Check: image release version %s does not match system release version %s, the zone is not usable on this system.") +sanity_fail=$(gettext " Sanity Check: FAILED (see log for details).") + + +p2ving=$(gettext "Postprocessing: This may take a while...") +p2v_prog=$(gettext " Postprocess: ") +p2v_done=$(gettext " Result: Postprocessing complete.") +p2v_fail=$(gettext " Result: Postprocessing failed.") + +root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.") + +media_missing=\ +$(gettext "%s: you must specify an installation source using '-a' or '-d'.") + +cfgchoice_missing=\ +$(gettext "%s: you must specify -u (sys-unconfig) or -p (preserve identity).") + +mount_failed=$(gettext "ERROR: zonecfg(1M) 'fs' mount failed") + +not_flar=$(gettext "Input is not a flash archive") +bad_flar=$(gettext "Flash archive is a corrupt") +unknown_archiver=$(gettext "Archiver %s is not supported") + +e_baddir=$(gettext "Invalid '%s' directory within the zone") + +# Clean up on interrupt +trap_cleanup() +{ + msg=$(gettext "Installation cancelled due to interrupt.") + log "$msg" + + # umount IPDs + umnt_fs + + exit $EXIT_CODE +} + +sanity_check() +{ + typeset dir="$1" + shift + ret=0 + + # These checks must work with a sparse zone. + checks="etc etc/svc usr sbin lib var var/svc" + for x in $checks; do + if [[ ! -e $dir/$x ]]; then + vlog "$sanity_fail_detail" "$x" "$dir" + ret=1 + fi + done + + # + # Check image release against system release. We only work on the + # same minor release as the system is running. + # + sys_vers=0 + image_vers=-1 + if [[ -f /var/sadm/system/admin/INST_RELEASE ]]; then + sys_vers=$(nawk -F= '{if ($1 == "VERSION") print $2}' \ + /var/sadm/system/admin/INST_RELEASE) + fi + + if [[ -f $dir/var/sadm/system/admin/INST_RELEASE ]]; then + image_vers=$(nawk -F= '{if ($1 == "VERSION") print $2}' \ + $dir/var/sadm/system/admin/INST_RELEASE) + fi + + if (( $sys_vers != $image_vers )); then + vlog "$sanity_fail_vers" "$image_vers" "$sys_vers" + ret=1 + fi + + return $ret +} + +# +# The main body of the script starts here. +# +# This script should never be called directly by a user but rather should +# only be called by zoneadm to install a native system image into a zone. +# + +# +# Exit code to return if install is interrupted or exit code is otherwise +# unspecified. +# +EXIT_CODE=$ZONE_SUBPROC_USAGE + +trap trap_cleanup INT + +# If we weren't passed at least two arguments, exit now. +(( $# < 2 )) && exit $ZONE_SUBPROC_USAGE + +zonename="$1" +zonepath="$2" + +ZONEROOT="$zonepath/root" +logdir="$ZONEROOT/var/log" + +shift; shift # remove zonename and zonepath from arguments array + +unset backout +unset install_archive +unset source_dir +unset msg +unset silent_mode +unset OPT_V + +# +# It is worth noting here that we require the end user to pick one of +# -u (sys-unconfig) or -p (preserve config). This is because we can't +# really know in advance which option makes a better default. Forcing +# the user to pick one or the other means that they will consider their +# choice and hopefully not be surprised or disappointed with the result. +# +unset unconfig_zone +unset preserve_zone + +while getopts "a:b:d:psuv" opt +do + case "$opt" in + a) install_archive="$OPTARG" ; install_media="$OPTARG";; + b) if [[ -n "$backout" ]]; then + backout="$backout -b $OPTARG" + else + backout="-b $OPTARG" + fi + ;; + d) source_dir="$OPTARG" ; install_media="$OPTARG";; + p) preserve_zone="-p";; + s) silent_mode=1;; + u) unconfig_zone="-u";; + v) OPT_V="-v";; + *) exit $ZONE_SUBPROC_USAGE;; + esac +done +shift OPTIND-1 + +# The install can't be both verbose AND silent... +if [[ -n $silent_mode && -n $OPT_V ]]; then + fatal "$both_modes" "zoneadm install" +fi + +if [[ -z $install_media ]]; then + fatal "$media_missing" "zoneadm install" +fi + +if [[ -n $install_archive && -n $source_dir ]]; then + fatal "$both_kinds" "zoneadm install" +fi + +# The install can't both preserve and unconfigure +if [[ -n $unconfig_zone && -n $preserve_zone ]]; then + fatal "$both_choices" "zoneadm install" +fi + +# Must pick one or the other. +if [[ -z $unconfig_zone && -z $preserve_zone ]]; then + fatal "$cfgchoice_missing" "zoneadm install" +fi + +# +# Handle "-d -" option to use whatever is already installed into the zonepath. +# +if [ "$source_dir" != "-" ]; then + # + # Validate $install_media (things common to archive/dir) + # + if [[ "$(echo $install_media | cut -c 1)" != "/" ]]; then + fatal "$path_abs" "$install_media" + fi + + if [[ ! -e "$install_media" ]]; then + log "$not_found" "$install_media" + fatal "$install_abort" "$zonename" + fi + + if [[ ! -r "$install_media" ]]; then + log "$not_readable" "$install_media" + fatal "$install_abort" "$zonename" + fi + + if [[ -n $install_archive ]]; then + if [[ ! -f "$install_archive" ]]; then + log "$media_taste" "$bad_archive" + fatal "$install_abort" "$zonename" + fi + fi + + if [[ -n $source_dir ]]; then + if [[ ! -d "$source_dir" ]]; then + log "$media_taste" "$wrong_dir_type" + fatal "$install_abort" "$zonename" + fi + fi +fi + +LOGFILE=$(/usr/bin/mktemp -t -p /var/tmp $zonename.install_log.XXXXXX) +if [[ -z "$LOGFILE" ]]; then + fatal "$e_tmpfile" +fi +zone_logfile="${logdir}/$zonename.install$$.log" +exec 2>>"$LOGFILE" +log "$install_log" "$LOGFILE" + +vlog "Starting pre-installation tasks." + +if [[ -z $install_archive && -n $source_dir ]]; then + # + # Minimal check to make sure that the user is passing + # us something that at least seems to be a native image. + # + if [[ "$source_dir" == "-" ]]; then + filetype="existing" + filetypename="existing" + else + sanity_check $source_dir + if (( $? != 0 )); then + fatal "$not_native_image" "$source_dir" + fi + + filetype="directory" + filetypename="directory" + fi +else + ftype="$(LC_ALL=C file $install_archive | cut -d: -f 2)" + 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" + ;; + *Flash\ Archive*) filetype="flar" + filetypename="flash archive" + ;; + *USTAR\ tar\ archive\ extended\ format*) filetype="xustar" + filetypename="pax (xustar) archive" + ;; + *) log "$media_taste" "$bad_archive" + fatal "$install_abort" "$zonename" + ;; + esac +fi + +# +# From here on out, an unspecified exit or interrupt should exit with +# ZONE_SUBPROC_NOTCOMPLETE, meaning a user will need to do an uninstall before +# attempting another install, as we've modified the directories we were going +# to install to in some way. +# +EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE + +if [[ ! -d "$ZONEROOT" ]] +then + if ! mkdir -p "$ZONEROOT" 2>/dev/null; then + fatal "$no_install" "$ZONEROOT" + fi +fi + +# +# Check for a non-empty root if no '-d -' option. +# +if [[ "$filetype" != "existing" ]]; then + cnt=$(ls $ZONEROOT | wc -l) + if (( $cnt != 0 )); then + fatal "$root_full" "$ZONEROOT" + fi +fi + +vlog "Installation started for zone \"$zonename\"" + +log "$install_from" "$install_media" +vlog "$media_taste" "$filetypename" + +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 IPDs to these +# files in get_fs_info(). +ipdcpiofile=$(/usr/bin/mktemp -t -p /var/tmp ipd.cpio.XXXXXX) +if [[ -z "$ipdcpiofile" ]]; then + rm -f $fstmpfile + fatal "$e_tmpfile" +fi + +# In addition to the IPDs, also filter out these directories. +echo 'dev/*' >>$ipdcpiofile +echo 'devices/*' >>$ipdcpiofile +echo 'devices' >>$ipdcpiofile +echo 'proc/*' >>$ipdcpiofile +echo 'tmp/*' >>$ipdcpiofile +echo 'var/run/*' >>$ipdcpiofile +echo 'system/contract/*' >>$ipdcpiofile +echo 'system/object/*' >>$ipdcpiofile + +ipdpaxfile=$(/usr/bin/mktemp -t -p /var/tmp ipd.pax.XXXXXX) +if [[ -z "$ipdpaxfile" ]]; then + rm -f $fstmpfile $ipdcpiofile + fatal "$e_tmpfile" +fi + +printf "%s " "dev devices proc tmp var/run system/contract system/object" \ + >>$ipdpaxfile + +# 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 $ipdcpiofile $ipdpaxfile + fatal "$mount_failed" +fi + +if [[ "$filetype" == "existing" ]]; then + log "$no_installing" +else + log "$installing" +fi + +unpack_result=0 +stage1="cat" +if [[ "$filetype" == "gzip" ]]; then + stage1="gzcat" + filetype="cpio" +fi + +if [[ "$filetype" == "bzip2" ]]; then + stage1="bzcat" + filetype="cpio" +fi + +if [[ "$filetype" == "cpio" ]]; then + install_cpio "$stage1" "$install_archive" + unpack_result=$? + +elif [[ "$filetype" == "flar" ]]; then + ( cd "$ZONEROOT" && install_flar < "$install_archive" ) + unpack_result=$? + +elif [[ "$filetype" == "xustar" ]]; then + install_pax "$install_archive" + unpack_result=$? + +elif [[ "$filetype" == "ufsdump" ]]; then + install_ufsdump "$install_archive" + unpack_result=$? + +elif [[ "$filetype" == "directory" ]]; then + install_dir "$source_dir" + unpack_result=$? +fi + +# Clean up any fs mounts used during unpacking. +umnt_fs +rm -f $fstmpfile $ipdcpiofile $ipdpaxfile + +# +# Do a sanity check to see if various things we think should be present +# are present. If not, the user might have supplied a cpio archive which was +# not created properly. +# +if (( $unpack_result == 0 )); then + sanity_check $ZONEROOT + if (( $? != 0 )); then + log "$sanity_fail" + log "" + log "$install_log" "$LOGFILE" + fatal "$install_fail" "$zonename" + else + vlog "$sanity_ok" + fi +fi + +chmod 700 $zonepath + +log "$p2ving" +vlog "running: p2v $OPT_V $unconfig_zone $backout $zonename $zonepath" + +# +# Run p2v. +# +# Getting the output to the right places is a little tricky because what +# we want is for p2v to output in the same way the installer does: verbose +# messages to the log file always, and verbose messages printed to the +# user if the user passes -v. This rules out simple redirection. And +# we can't use tee or other tricks because they cause us to lose the +# return value from the p2v script due to the way shell pipelines work. +# +# The simplest way to do this seems to be to hand off the management of +# the log file to the p2v script. So we run p2v with -l to tell it where +# to find the log file and then reopen the log (O_APPEND) when p2v is done. +# +/usr/lib/brand/native/p2v -l "$LOGFILE" -m "$p2v_prog" \ + $OPT_V $unconfig_zone $backout $zonename $zonepath +p2v_result=$? +exec 2>>$LOGFILE + +if (( $p2v_result == 0 )); then + vlog "$p2v_done" +else + log "$p2v_fail" + log "" + log "$install_fail" + log "$install_log" "$LOGFILE" + exit $ZONE_SUBPROC_FATAL +fi + +EXIT_CODE=$ZONE_SUBPROC_OK + +log "" +log "$install_good" "$zonename" + +if [[ -h $ZONEROOT/var || ! -d $ZONEROOT/var || -h $ZONEROOT/var/log ]]; then + log "$e_baddir" "/var/log" + exit $ZONE_SUBPROC_FATAL +fi + +# Just in case the log directory isn't present... +if [[ ! -d "$logdir" ]]; then + if ! mkdir -p "$logdir" 2>/dev/null; then + log "$no_log" "$logdir" + fi +fi + +if [[ ! -h $zone_logfile && ! -d $zone_logfile ]]; then + cp $LOGFILE $zone_logfile +fi +log "$install_log" "$zone_logfile" +rm -f $LOGFILE + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/p2v.ksh Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,680 @@ +#!/bin/ksh -p +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# NOTE: this script runs in the global zone and touches the non-global +# zone, so care should be taken to validate any modifications so that they +# are safe. + +. /usr/lib/brand/shared/common.ksh + +LOGFILE= +MSG_PREFIX="p2v: " +EXIT_CODE=1 + +usage() +{ + echo "$0 [-s] [-m msgprefix] [-u] [-v] [-b patchid]* zonename" >&2 + exit $EXIT_CODE +} + +# Clean up on interrupt +trap_cleanup() +{ + msg=$(gettext "Postprocessing cancelled due to interrupt.") + error "$msg" + + if (( $zone_is_running != 0 )); then + error "$e_shutdown" "$ZONENAME" + /usr/sbin/zoneadm -z $ZONENAME halt + fi + + exit $EXIT_CODE +} + +# +# For an exclusive stack zone, fix up the network configuration files. +# We need to do this even if unconfiguring the zone so sys-unconfig works +# correctly. +# +fix_net() +{ + [[ "$STACK_TYPE" == "shared" ]] && return + + NETIF_CNT=$(/usr/bin/ls $ZONEROOT/etc/hostname.* 2>/dev/null | \ + /usr/bin/wc -l) + if (( $NETIF_CNT != 1 )); then + vlog "$v_nonetfix" + return + fi + + NET=$(LC_ALL=C /usr/sbin/zonecfg -z $ZONENAME info net) + if (( $? != 0 )); then + error "$e_badinfo" "net" + return + fi + + NETIF=$(echo $NET | /usr/bin/nawk '{ + for (i = 1; i < NF; i++) { + if ($i == "physical:") { + if (length(net) == 0) { + i++ + net = $i + } else { + multiple=1 + } + } + } + } + END { if (!multiple) + print net + }') + + if [[ -z "$NETIF" ]]; then + vlog "$v_nonetfix" + return + fi + + OLD_HOSTNET=$(/usr/bin/ls $ZONEROOT/etc/hostname.*) + if [[ "$OLD_HOSTNET" != "$ZONEROOT/etc/hostname.$NETIF" ]]; then + safe_move $OLD_HOSTNET $ZONEROOT/etc/hostname.$NETIF + fi +} + +# +# Disable all of the shares since the zone cannot be an NFS server. +# Note that we disable the various instances of the svc:/network/shares/group +# SMF service in the fix_smf function. +# +fix_nfs() +{ + zonedfs=$ZONEROOT/etc/dfs + + if [[ -h $zonedfs/dfstab || ! -f $zonedfs/dfstab ]]; then + error "$e_badfile" "/etc/dfs/dfstab" + return + fi + + tmpfile=$(/usr/bin/mktemp -t -p /var/tmp) + if [[ -z "$tmpfile" ]]; then + error "$e_tmpfile" + return + fi + + /usr/bin/nawk '{ + if (substr($1, 0, 1) == "#") { + print $0 + } else { + print "#", $0 + modified=1 + } + } + END { + if (modified == 1) { + printf("# Modified by p2v ") + system("/usr/bin/date") + exit 0 + } + exit 1 + }' $zonedfs/dfstab >>$tmpfile + + if (( $? == 0 )); then + if [[ ! -f $zonedfs/dfstab.pre_p2v ]]; then + safe_copy $zonedfs/dfstab $zonedfs/dfstab.pre_p2v + fi + safe_copy $tmpfile $zonedfs/dfstab + fi + /usr/bin/rm -f $tmpfile +} + +# +# Comment out most of the old mounts since they are either unneeded or +# likely incorrect within a zone. Specific mounts can be manually +# reenabled if the corresponding device is added to the zone. +# +fix_vfstab() +{ + if [[ -h $ZONEROOT/etc/vfstab || ! -f $ZONEROOT/etc/vfstab ]]; then + error "$e_badfile" "/etc/vfstab" + return + fi + + tmpfile=$(/usr/bin/mktemp -t -p /var/tmp) + if [[ -z "$tmpfile" ]]; then + error "$e_tmpfile" + return + fi + + /usr/bin/nawk '{ + if (substr($1, 0, 1) == "#") { + print $0 + } else if ($1 == "fd" || $1 == "/proc" || $1 == "swap" || + $1 == "ctfs" || $1 == "objfs" || $1 == "sharefs" || + $4 == "nfs" || $4 == "lofs") { + print $0 + } else { + print "#", $0 + modified=1 + } + } + END { + if (modified == 1) { + printf("# Modified by p2v ") + system("/usr/bin/date") + exit 0 + } + exit 1 + }' $ZONEROOT/etc/vfstab >>$tmpfile + + if (( $? == 0 )); then + if [[ ! -f $ZONEROOT/etc/vfstab.pre_p2v ]]; then + safe_copy $ZONEROOT/etc/vfstab \ + $ZONEROOT/etc/vfstab.pre_p2v + fi + safe_copy $tmpfile $ZONEROOT/etc/vfstab + fi + /usr/bin/rm -f $tmpfile +} + +# +# Delete or disable SMF services. +# Zone is booted to milestone=none when this function is called. +# +fix_smf() +{ + # + # Delete services that are delivered in hollow pkgs. + # + # Start by getting the svc manifests that are delivered by hollow + # pkgs then use 'svccfg inventory' to get the names of the svcs + # delivered by those manifests. The svc names are saved into a + # temporary file. We then login to the zone and delete them from SMF + # so that the various dependencies also get cleaned up properly. + # + + smftmpfile=$(/usr/bin/mktemp -t -p /var/tmp smf.XXXXXX) + if [[ -z "$smftmpfile" ]]; then + error "$e_tmpfile" + return + fi + + for i in /var/sadm/pkg/* + do + pkg=$(/usr/bin/basename $i) + [[ ! -f /var/sadm/pkg/$pkg/save/pspool/$pkg/pkgmap ]] && \ + continue + + manifests=$(/usr/bin/nawk '{if ($2 == "f" && + substr($4, 1, 17) == "var/svc/manifest/") print $4}' \ + /var/sadm/pkg/$pkg/save/pspool/$pkg/pkgmap) + + if [[ -n "$manifests" ]]; then + /usr/bin/egrep -s "SUNW_PKG_HOLLOW=true" \ + /var/sadm/pkg/$pkg/pkginfo || continue + + for j in $manifests + do + svcs=$(SVCCFG_NOVALIDATE=1 /usr/sbin/svccfg \ + inventory /$j) + for k in $svcs + do + case $k in + *:default) + # ignore default instance + ;; + *) + echo $k >> $smftmpfile + ;; + esac + done + done + fi + done + + # + # Zone was already booted to milestone=none, wait until SMF door exists. + # + for i in 0 1 2 3 4 5 6 7 8 9 + do + [[ -r $ZONEROOT/etc/svc/volatile/repository_door ]] && break + sleep 5 + done + + if [[ $i -eq 9 && ! -r $ZONEROOT/etc/svc/volatile/repository_door ]]; + then + error "$e_nosmf" + /usr/bin/rm -f $smftmpfile + return + fi + + insttmpfile=$(/usr/bin/mktemp -t -p /var/tmp instsmf.XXXXXX) + if [[ -z "$insttmpfile" ]]; then + error "$e_tmpfile" + /usr/bin/rm -f $smftmpfile + return + fi + + # Get a list of the svcs that exist in the zone. + /usr/sbin/zlogin -S $ZONENAME /usr/bin/svcs -aH | \ + /usr/bin/nawk '{print $3}' >>$insttmpfile + + [[ -n $LOGFILE ]] && \ + printf "[$(date)] ${MSG_PREFIX}${v_svcsinzone}\n" >&2 + [[ -n $LOGFILE ]] && cat $insttmpfile >&2 + + vlog "$v_rmhollowsvcs" + for i in $(cat $smftmpfile) + do + # Skip svcs not installed in the zone. + /usr/bin/egrep -s "$i:" $insttmpfile || continue + + # Delete the svc. + vlog "$v_delsvc" "$i" + /usr/sbin/zlogin -S $ZONENAME /usr/sbin/svccfg delete $i >&2 \ + || error "$e_delsvc" $i + done + + /usr/bin/rm -f $smftmpfile + + # + # Fix network services if shared stack. + # + if [[ "$STACK_TYPE" == "shared" ]]; then + vlog "$v_fixnetsvcs" + + NETPHYSDEF="svc:/network/physical:default" + NETPHYSNWAM="svc:/network/physical:nwam" + + /usr/bin/egrep -s "$NETPHYSDEF" $insttmpfile + if (( $? == 0 )); then + vlog "$v_enblsvc" "$NETPHYSDEF" + /usr/sbin/zlogin -S $ZONENAME \ + /usr/sbin/svcadm enable $NETPHYSDEF || \ + error "$e_dissvc" "$NETPHYSDEF" + fi + + /usr/bin/egrep -s "$NETPHYSNWAM" $insttmpfile + if (( $? == 0 )); then + vlog "$v_dissvc" "$NETPHYSNWAM" + /usr/sbin/zlogin -S $ZONENAME \ + /usr/sbin/svcadm disable $NETPHYSNWAM || \ + error "$e_enblsvc" "$NETPHYSNWAM" + fi + + for i in $(/usr/bin/egrep network/routing $insttmpfile) + do + # Disable the svc. + vlog "$v_dissvc" "$i" + /usr/sbin/zlogin -S $ZONENAME \ + /usr/sbin/svcadm disable $i || \ + error "$e_dissvc" $i + done + fi + + # + # Disable well-known services that don't run in a zone. + # + vlog "$v_rminvalidsvcs" + for i in $(/usr/bin/egrep -hv "^#" \ + /usr/lib/brand/native/smf_disable.lst \ + /etc/brand/native/smf_disable.conf) + do + # Skip svcs not installed in the zone. + /usr/bin/egrep -s "$i:" $insttmpfile || continue + + # Disable the svc. + vlog "$v_dissvc" "$i" + /usr/sbin/zlogin -S $ZONENAME /usr/sbin/svcadm disable $i || \ + error "$e_dissvc" $i + done + + # + # Since zones can't be NFS servers, disable all of the instances of + # the shares svc. + # + for i in $(/usr/bin/egrep network/shares/group $insttmpfile) + do + vlog "$v_dissvc" "$i" + /usr/sbin/zlogin -S $ZONENAME /usr/sbin/svcadm disable $i || \ + error "$e_dissvc" $i + done + + /usr/bin/rm -f $insttmpfile +} + +# +# Remove well-known pkgs that do not work inside a zone. +# +rm_pkgs() +{ + /usr/bin/cat <<-EOF > $ZONEROOT/tmp/admin || fatal "$e_adminf" + mail= + instance=overwrite + partial=nocheck + runlevel=nocheck + idepend=nocheck + rdepend=nocheck + space=nocheck + setuid=nocheck + conflict=nocheck + action=nocheck + basedir=default + EOF + + for i in $(/usr/bin/egrep -hv "^#" /usr/lib/brand/native/pkgrm.lst \ + /etc/brand/native/pkgrm.conf) + do + [[ ! -d $ZONEROOT/var/sadm/pkg/$i ]] && continue + + vlog "$v_rmpkg" "$i" + /usr/sbin/zlogin -S $ZONENAME \ + /usr/sbin/pkgrm -na /tmp/admin $i >&2 || error "$e_rmpkg" $i + done +} + +# +# Zoneadmd writes a one-line index file into the zone when the zone boots, +# so any information about installed zones from the original system will +# be lost at that time. Here we'll warn the sysadmin about any pre-existing +# zones that they might want to clean up by hand, but we'll leave the zonepaths +# in place in case they're on shared storage and will be migrated to +# a new host. +# +warn_zones() +{ + zoneconfig=$ZONEROOT/etc/zones + + if [[ -h $zoneconfig/index || ! -f $zoneconfig/index ]]; then + error "$e_badfile" "/etc/zones/index" + return + fi + + NGZ=$(/usr/bin/nawk -F: '{ + if (substr($1, 0, 1) == "#" || $1 == "global") + continue + + if ($2 == "installed") + printf("%s ", $1) + }' $zoneconfig/index) + + # Return if there are no installed zones to warn about. + [[ -z "$NGZ" ]] && return + + log "$v_rmzones" "$NGZ" + + NGZP=$(/usr/bin/nawk -F: '{ + if (substr($1, 0, 1) == "#" || $1 == "global") + continue + + if ($2 == "installed") + printf("%s ", $3) + }' $zoneconfig/index) + + log "$v_rmzonepaths" + + for i in $NGZP + do + log " %s" "$i" + done +} + +unset LD_LIBRARY_PATH +PATH=/usr/sbin:/usr/bin +export PATH + +# +# ^C Should cleanup; if the zone is running, it should try to halt it. +# +zone_is_running=0 +trap trap_cleanup INT + +# +# Parse the command line options. +# +unset backout +OPT_U= +OPT_V= +OPT_M= +OPT_L= +while getopts "b:uvm:l:" opt +do + case "$opt" in + b) if [[ -n "$backout" ]]; then + backout="$backout -b $OPTARG" + else + backout="-b $OPTARG" + fi + ;; + u) OPT_U="-u";; + v) OPT_V="-v";; + m) MSG_PREFIX="$OPTARG"; OPT_M="-m \"$OPTARG\"";; + l) LOGFILE="$OPTARG"; OPT_L="-l \"$OPTARG\"";; + *) usage;; + esac +done +shift OPTIND-1 + +(( $# < 1 )) && usage + +(( $# > 2 )) && usage + +[[ -n $LOGFILE ]] && exec 2>>$LOGFILE + +ZONENAME=$1 +ZONEPATH=$2 +ZONEROOT=$ZONEPATH/root + +e_badinfo=$(gettext "Failed to get '%s' zone resource") +e_badfile=$(gettext "Invalid '%s' file within the zone") +e_tmpfile=$(gettext "Unable to create temporary file") +v_mkdirs=$(gettext "Creating mount points") +v_nonetfix=$(gettext "Cannot update /etc/hostname.{net} file") +v_update=$(gettext "Updating the zone software to match the global zone...") +v_updatedone=$(gettext "Zone software update complete") +e_badupdate=$(gettext "Updating the Zone software failed") +v_adjust=$(gettext "Updating the image to run within a zone") +v_stacktype=$(gettext "Stack type '%s'") +v_booting=$(gettext "Booting zone to single user mode") +e_badboot=$(gettext "Zone boot failed") +e_nosmf=$(gettext "ERROR: SMF repository unavailable.") +e_nosingleuser=$(gettext "ERROR: zone did not finish booting to single-user.") +v_svcsinzone=$(gettext "The following SMF services are installed:") +v_rmhollowsvcs=$(gettext "Deleting SMF services from hollow packages") +v_fixnetsvcs=$(gettext "Adjusting network SMF services") +v_rminvalidsvcs=$(gettext "Disabling invalid SMF services") +v_delsvc=$(gettext "Delete SMF svc '%s'") +e_delsvc=$(gettext "deleting SMF svc '%s'") +v_enblsvc=$(gettext "Enable SMF svc '%s'") +e_enblsvc=$(gettext "enabling SMF svc '%s'") +v_dissvc=$(gettext "Disable SMF svc '%s'") +e_dissvc=$(gettext "disabling SMF svc '%s'") +e_adminf=$(gettext "Unable to create admin file") +v_rmpkg=$(gettext "Remove package '%s'") +e_rmpkg=$(gettext "removing package '%s'") +v_rmzones=$(gettext "The following zones in this image will be unusable: %s") +v_rmzonepaths=$(gettext "These zonepaths could be removed from this image:") +v_unconfig=$(gettext "Performing zone sys-unconfig") +e_unconfig=$(gettext "sys-unconfig failed") +v_halting=$(gettext "Halting zone") +e_shutdown=$(gettext "Shutting down zone %s...") +e_badhalt=$(gettext "Zone halt failed") +v_exitgood=$(gettext "Postprocessing successful.") +e_exitfail=$(gettext "Postprocessing failed.") + +# +# Do some validation on the paths we'll be accessing +# +safe_dir etc +safe_dir etc/dfs +safe_dir etc/zones +safe_dir var + +# Now do the work to update the zone. + +# Before booting the zone we may need to create a few mnt points, just in +# case they don't exist for some reason. +# +# Whenever we reach into the zone while running in the global zone we +# need to validate that none of the interim directories are symlinks +# that could cause us to inadvertently modify the global zone. +vlog "$v_mkdirs" +if [[ ! -f $ZONEROOT/tmp && ! -d $ZONEROOT/tmp ]]; then + mkdir -m 1777 -p $ZONEROOT/tmp || exit $EXIT_CODE +fi +if [[ ! -f $ZONEROOT/var/run && ! -d $ZONEROOT/var/run ]]; then + mkdir -m 1755 -p $ZONEROOT/var/run || exit $EXIT_CODE +fi +if [[ ! -h $ZONEROOT/etc && ! -f $ZONEROOT/etc/mnttab ]]; then + /usr/bin/touch $ZONEROOT/etc/mnttab || exit $EXIT_CODE + /usr/bin/chmod 444 $ZONEROOT/etc/mnttab || exit $EXIT_CODE +fi +if [[ ! -f $ZONEROOT/proc && ! -d $ZONEROOT/proc ]]; then + mkdir -m 755 -p $ZONEROOT/proc || exit $EXIT_CODE +fi +if [[ ! -f $ZONEROOT/dev && ! -d $ZONEROOT/dev ]]; then + mkdir -m 755 -p $ZONEROOT/dev || exit $EXIT_CODE +fi +if [[ ! -h $ZONEROOT/etc && ! -h $ZONEROOT/etc/svc && ! -d $ZONEROOT/etc/svc ]] +then + mkdir -m 755 -p $ZONEROOT/etc/svc/volatile || exit $EXIT_CODE +fi + +# Check for zones inside of image. +warn_zones + +# +# Run update on attach. State is currently 'incomplete' so use the private +# force-update option. +# +log "$v_update" +/usr/sbin/zoneadm -z $ZONENAME attach -U $backout >&2 +res=$? +if (( $? != 0 )); then + fatal "$e_badupdate" +else + log "$v_updatedone" +fi + +log "$v_adjust" + +# +# Any errors in these functions are not considered fatal. The zone can be +# be fixed up manually afterwards and it may need some additional manual +# cleanup in any case. +# + +STACK_TYPE=$(/usr/sbin/zoneadm -z $ZONENAME list -p | \ + /usr/bin/nawk -F: '{print $7}') +if (( $? != 0 )); then + error "$e_badinfo" "stacktype" +fi +vlog "$v_stacktype" "$STACK_TYPE" + +fix_net +fix_nfs +fix_vfstab + +vlog "$v_booting" + +# +# Boot the zone so that we can do all of the SMF updates needed on the zone's +# repository. +# + +zone_is_running=1 + +# The 'update on attach' left the zone installed. +/usr/sbin/zoneadm -z $ZONENAME boot -f -- -m milestone=none +if (( $? != 0 )); then + error "$e_badboot" + fatal "$e_exitfail" +fi + +# cleanup SMF services +fix_smf + +# remove invalid pkgs +rm_pkgs + +vlog "$v_halting" +/usr/sbin/zoneadm -z $ZONENAME halt +if (( $? != 0 )); then + error "$e_badhalt" + failed=1 +fi +zone_is_running=0 + +if [[ -z $failed && -n $OPT_U ]]; then + # + # We're sys-unconfiging the zone. This will halt the zone, however + # there are problems with sys-unconfig and it usually hangs when the + # zone is booted to milestone=none. This is why we previously halted + # the zone. We now boot to milestone=single-user. Again, the + # sys-unconfig can hang if the zone is still in the process of + # booting when we try to run sys-unconfig. Wait until the boot is + # done, which we do by checking for sulogin, or waiting 30 seconds, + # whichever comes first. + # + + vlog "$v_unconfig" + + zone_is_running=1 + /usr/sbin/zoneadm -z $ZONENAME boot -- -m milestone=single-user + if (( $? != 0 )); then + error "$e_badboot" + fatal "$e_exitfail" + fi + + for i in 0 1 2 3 4 5 6 7 8 9 + do + sleep 10 + /usr/sbin/zlogin $ZONENAME \ + /usr/bin/svcs -H svc:/milestone/single-user:default 2>&1 | + /usr/bin/nawk '{ + if ($1 == "online") + exit 0 + else + exit 1 + }' && break + done + + if (( $i == 9 )); then + vlog "$e_nosingleuser" + fi + + echo "yes" | /usr/sbin/zlogin -S $ZONENAME \ + /usr/sbin/sys-unconfig >/dev/null 2>&1 + if (( $? != 0 )); then + error "$e_unconfig" + failed=1 + fi +fi + + +if [[ -n $failed ]]; then + fatal "$e_exitfail" +fi + +vlog "$v_exitgood" +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/pkgrm.conf Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,29 @@ +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This is a list of SVr4 packages which should be removed when installing +# a zone from an image of a physical system (that is, only when installing +# with the zoneadm -d or -a option). Site-specific packages which must be +# removed should be listed in this file. During the zone installation, the +# packages will be removed if they existed on the original physical system. +#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/pkgrm.lst Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,31 @@ +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This is a list of SVr4 packages which should be removed when installing +# a zone from an image of a physical system (that is, only when installing +# with the zoneadm -d or -a option). Do not edit this file. Site-specific +# packages which must be removed should be listed in the +# /etc/brand/native/pkgrm.conf file. During the zone installation, the +# packages will be removed if they existed on the original physical system. +# +VRTSvxvm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/smf_disable.conf Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,29 @@ +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This is a list of SMF services which should be disabled when installing +# a zone from an image of a physical system (that is, only when installing +# with the zoneadm -d or -a option). Site-specific services which must be +# disabled should be listed in this file. During the zone installation, the +# services will be disabled if they existed on the original physical system. +#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/brand/native/zone/smf_disable.lst Wed Feb 11 09:33:05 2009 -0700 @@ -0,0 +1,32 @@ +# +# 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 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# This is a list of SMF services which should be disabled when installing +# a zone from an image of a physical system (that is, only when installing +# with the zoneadm -d or -a option). Do not edit this file. Site-specific +# services which must be disabled should be listed in the +# /etc/brand/native/smf_disable.conf file. During the zone installation, the +# services will be disabled if they existed on the original physical system. +# +svc:/network/smb/server +svc:/system/virtualbox/vboxservice
--- a/usr/src/lib/brand/native/zone/sw_support.c Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/brand/native/zone/sw_support.c Wed Feb 11 09:33:05 2009 -0700 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * sw_support does install, detach and attach processing for svr4 pkgs. */ @@ -3646,23 +3644,62 @@ return (res); } +static boolean_t +add_opts(char *buf, int bsize, char opt, char *arg) +{ + char argbuf[MAXPATHLEN]; + + if (snprintf(argbuf, sizeof (argbuf), " -%c '%s'", opt, arg) + > sizeof (argbuf) || strlcat(buf, argbuf, bsize) >= bsize) { + (void) fprintf(stderr, gettext("Command line too long")); + return (B_TRUE); + } + + return (B_FALSE); +} + +static boolean_t +add_opt(char *buf, int bsize, char opt) +{ + char argbuf[4]; + + (void) snprintf(argbuf, sizeof (argbuf), " -%c", opt); + if (strlcat(buf, argbuf, bsize) >= bsize) { + (void) fprintf(stderr, gettext("Command line too long")); + return (B_TRUE); + } + + return (B_FALSE); +} + static void install_usage() { - (void) fprintf(stderr, gettext("usage:\t%s brand options: none\n"), + (void) fprintf(stderr, gettext("usage:\t%s brand options:\n" + "\tWith no options the zone is freshly installed:\n" + "\t\tinstall\n" + "\tAlternatively, the zone may be installed using an existing\n" + "\tsystem image from an archive or a directory:\n" + "\t\tinstall -a archive (-u | -p) [-v | -s] [-b patchid]*\n" + "\t\tinstall -d directory (-u | -p) [-v | -s] [-b patchid]*\n"), MY_BRAND_NAME); } static int install_func(int argc, char *argv[]) { - char cmdbuf[MAXPATHLEN]; + char cmdbuf[NCARGS]; + char argbuf[NCARGS]; int arg; int status; + boolean_t image_install = B_FALSE; + char image_install_arg = '\0'; + + argbuf[0] = '\0'; opterr = 0; optind = 0; - while ((arg = getopt(argc, argv, "?x:")) != EOF) { + while ((arg = getopt(argc, argv, "?a:b:d:psuvx:")) != EOF) { switch (arg) { case '?': if (optopt != '?') { @@ -3672,6 +3709,50 @@ } install_usage(); return (optopt == '?' ? Z_OK : ZONE_SUBPROC_USAGE); + + case 'a': + if (image_install) { + install_usage(); + return (ZONE_SUBPROC_USAGE); + } + image_install = B_TRUE; + if (add_opts(argbuf, sizeof (argbuf), arg, optarg)) + return (Z_ERR); + break; + case 'b': + image_install_arg = optopt; + if (add_opts(argbuf, sizeof (argbuf), arg, optarg)) + return (Z_ERR); + break; + case 'd': + if (image_install) { + install_usage(); + return (ZONE_SUBPROC_USAGE); + } + image_install = B_TRUE; + if (add_opts(argbuf, sizeof (argbuf), arg, optarg)) + return (Z_ERR); + break; + case 'p': + image_install_arg = optopt; + if (add_opt(argbuf, sizeof (argbuf), arg)) + return (Z_ERR); + break; + case 's': + image_install_arg = optopt; + if (add_opt(argbuf, sizeof (argbuf), arg)) + return (Z_ERR); + break; + case 'u': + image_install_arg = optopt; + if (add_opt(argbuf, sizeof (argbuf), arg)) + return (Z_ERR); + break; + case 'v': + image_install_arg = optopt; + if (add_opt(argbuf, sizeof (argbuf), arg)) + return (Z_ERR); + break; case 'x': if (strcmp(optarg, "nodataset") != 0) { (void) fprintf(stderr, gettext("%s brand: " @@ -3693,9 +3774,70 @@ return (ZONE_SUBPROC_USAGE); } - if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/lu/lucreatezone -z %s", - zonename) >= sizeof (cmdbuf)) - return (Z_ERR); + /* + * Either install the zone using a system image or using the + * traditional lu support. + */ + if (image_install) { + if (snprintf(cmdbuf, sizeof (cmdbuf), + "/usr/lib/brand/native/image_install %s %s %s", zonename, + zonepath, argbuf) >= sizeof (cmdbuf)) + return (Z_ERR); + + } else { + struct stat stbuf; + char rootpath[MAXPATHLEN]; /* zone root path */ + + if (snprintf(rootpath, sizeof (rootpath), "%s/root", zonepath) + >= sizeof (rootpath)) { + (void) fprintf(stderr, + gettext("Zonepath %s is too long.\n"), zonepath); + return (Z_ERR); + } + + if (stat(rootpath, &stbuf) == 0) { + struct dirent *dp; + DIR *dirp; + boolean_t empty = B_TRUE; + + if ((dirp = opendir(rootpath)) == NULL) { + (void) fprintf(stderr, gettext("Could not " + "open rootpath %s\n"), rootpath); + return (Z_ERR); + } + + /* Verify that the dir is empty. */ + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + empty = B_FALSE; + break; + } + (void) closedir(dirp); + + if (!empty) { + (void) fprintf(stderr, gettext("Zonepath root " + "%s exists and contains data; remove or " + "move aside prior to install.\n"), + rootpath); + return (Z_ERR); + } + } + + if (image_install_arg != '\0') { + (void) fprintf(stderr, gettext("%s brand: option: %c " + "is only valid with -a or -d\n"), MY_BRAND_NAME, + image_install_arg); + return (ZONE_SUBPROC_USAGE); + } + + if (snprintf(cmdbuf, sizeof (cmdbuf), + "/usr/lib/lu/lucreatezone -z %s", zonename) >= + sizeof (cmdbuf)) + return (Z_ERR); + } /* * According to the Application Packaging Developer's Guide, a
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/libzonecfg/common/libzonecfg.c Wed Feb 11 09:33:05 2009 -0700 @@ -7161,6 +7161,14 @@ return (Z_OK); } +boolean_t +zonecfg_lock_file_held(int *lockfd) +{ + if (*lockfd >= 0 || zone_lock_cnt > 0) + return (B_TRUE); + return (B_FALSE); +} + static boolean_t get_doorname(const char *zone_name, char *buffer) {
--- a/usr/src/lib/libzonecfg/common/mapfile-vers Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/lib/libzonecfg/common/mapfile-vers Wed Feb 11 09:33:05 2009 -0700 @@ -146,6 +146,7 @@ zonecfg_init_lock_file; zonecfg_is_rctl; zonecfg_is_scratch; + zonecfg_lock_file_held; zonecfg_lock_scratch; zonecfg_lookup_attr; zonecfg_lookup_dev;
--- a/usr/src/pkgdefs/SUNWzoner/prototype_com Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/pkgdefs/SUNWzoner/prototype_com Wed Feb 11 09:33:05 2009 -0700 @@ -19,11 +19,9 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package # and their location on the development machine when building the package. @@ -49,6 +47,10 @@ # SUNWzoner # d none etc 755 root sys +d none etc/brand 755 root sys +d none etc/brand/native 755 root sys +e none etc/brand/native/pkgrm.conf 644 root sys +e none etc/brand/native/smf_disable.conf 644 root sys d none etc/zones 755 root sys e preserve etc/zones/index 644 root sys f none etc/zones/SUNWdefault.xml 444 root bin
--- a/usr/src/pkgdefs/SUNWzoneu/prototype_com Wed Feb 11 09:51:50 2009 -0600 +++ b/usr/src/pkgdefs/SUNWzoneu/prototype_com Wed Feb 11 09:33:05 2009 -0700 @@ -19,11 +19,9 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package # and their location on the development machine when building the package. @@ -54,8 +52,14 @@ d none usr/lib/brand/native 755 root sys f none usr/lib/brand/native/attach_update 755 root bin f none usr/lib/brand/native/config.xml 444 root bin +f none usr/lib/brand/native/image_install 755 root bin +f none usr/lib/brand/native/p2v 755 root bin +f none usr/lib/brand/native/pkgrm.lst 444 root bin f none usr/lib/brand/native/platform.xml 444 root bin +f none usr/lib/brand/native/smf_disable.lst 444 root bin f none usr/lib/brand/native/sw_support 755 root bin +d none usr/lib/brand/shared 755 root sys +f none usr/lib/brand/shared/common.ksh 444 root bin f none usr/lib/libbrand.so.1 755 root bin f none usr/lib/libzonecfg.so.1 755 root bin d none usr/lib/zones 755 root bin