#!/bin/ksh -p # # # # # # # # # # # # # # # # # # # # # # Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. # . /usr/lib/brand/solaris10/common.ksh # Allows developer to override some things like PATH and PYTHONPATH . /usr/lib/brand/solaris/developerenv.ksh m_usage=$(gettext "solaris10 brand usage:\n\tinstall -u | -p [-v | -s] -a archive | -d directory [-c sysidcfg].\n\tThe -a archive option specifies an archive name which can be a flar,\n\ttar, pax or cpio archive.\n\tThe -d directory option specifies an existing directory.\n\tThe -u option unconfigures the zone, -p preserves the configuration.\n\tThe -c option gives a sysidcfg file and causes an unconfiguration of the zone.") no_install=$(gettext "Could not create install directory '%s'") install_log=$(gettext " Log File: %s") install_good=$(gettext " Result: Installation completed successfully.") install_fail=$(gettext " Result: *** Installation FAILED ***") p2ving=$(gettext "Postprocessing: This may take a while...") p2v_prog=$(gettext " Postprocess: ") p2v_done=$(gettext " Result: Postprocessing complete.") p2v_fail=$(gettext " Result: Postprocessing failed.") media_missing=\ $(gettext "you must specify an installation source using '-a', '-d' or '-r'.\n%s") cfgchoice_missing=\ $(gettext "you must specify -u (sys-unconfig) or -p (preserve identity).\n%s") # Clean up on interrupt trap_cleanup() { log "$m_interrupt" trap_exit } # If the install failed then clean up the ZFS datasets we created. trap_exit() { # trap_cleanup calls trap_exit. Don't make multiple passes. trap - INT EXIT if [[ -n $BRAND_SKIP_CLEANUP ]]; then vlog "Exiting with exit code $EXIT_CODE (skipping cleanup)" finish_log zone exit $EXIT_CODE fi # umount any mounted file systems [[ -n "$fstmpfile" ]] && umnt_fs if (( $EXIT_CODE != $ZONE_SUBPROC_OK )); then delete_unpinned_datasets "${zone.path.ds}" # # If cleanup completed, don't force the use of zoneadm # uninstall, as it will have no work to do. # if (( $? == 0 && $EXIT_CODE == $ZONE_SUBPROC_FATAL )); then EXIT_CODE=$ZONE_SUBPROC_TRYAGAIN fi unpin_datasets "${zone.path.ds}" || error "$f_unpin" fi vlog "Exiting with exit code $EXIT_CODE" finish_log zone exit $EXIT_CODE } # # 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 s10 system image into a zone. # # # Exit code to return if install is interrupted or exit code is otherwise # unspecified. # EXIT_CODE=$ZONE_SUBPROC_USAGE # Used by start_log set -A save_args "$0" "$@" # If we weren't passed at least two arguments, exit now. (( $# < 2 )) && exit $ZONE_SUBPROC_USAGE init_zone zone "$1" "$2" eval $(bind_legacy_zone_globals zone) shift; shift # remove zonename and zonepath from arguments array unset inst_type unset msg unset silent_mode OPT_V= OPT_C= # This lists the valid -x options typeset -A zone.xopts=([cert]= [ca-cert]= [key]=) # # 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 unset archived_zone unset SANITY_SKIP while getopts "a:c:d:Fpr:sux:vz:" opt do case "$opt" in a) if [[ -n "$inst_type" ]]; then fatal "$incompat_options" "$m_usage" fi if [[ $OPTARG != @(http|https|file)://* ]]; then OPTARG=$(mk_abs_path $OPTARG) # [[ -f ... ]] does not trigger the automounter ls "$OPTARG" >/dev/null 2>&1 [[ -f $OPTARG ]] || fatal "$f_arg_not_file" "$OPTARG" fi inst_type="archive" install_media="$OPTARG" ;; c) OPT_C="-c `mk_abs_path $OPTARG`" ;; d) if [[ -n "$inst_type" ]]; then fatal "$incompat_options" "$m_usage" fi inst_type="directory" install_media="$(mk_abs_path $OPTARG)" ;; F) SANITY_SKIP=1;; p) preserve_zone="-p";; r) if [[ -n "$inst_type" ]]; then fatal "$incompat_options" "$m_usage" fi inst_type="stdin" install_media="$OPTARG" ;; s) silent_mode=1;; u) unconfig_zone="-u";; v) OPT_V="-v";; x) # May call fail_usage process_xopt zone.xopts "$OPTARG" ;; z) archived_zone=$OPTARG ;; *) fail_usage "" ;; esac done shift OPTIND-1 # Check whether the zone has any BE. If so, it probably means it's already # installed and has been detached. In that case we suggest either trying to # re-attach the zone or marking it incomplete and uninstalling it first. zfs list -H "${zone.active_ds}" >/dev/null 2>&1 if (( $? == 0 )); then log "$f_reattach_or_uninstall" "(re)install" EXIT_CODE=$ZONE_SUBPROC_TRYAGAIN exit $EXIT_CODE fi # The install can't be both verbose AND silent... [[ -n $silent_mode && -n $verbose_mode ]] && fail_usage "$f_incompat_options" "-s" "-v" # Cannot preserve the config and apply a config. [[ -n $preserve_zone && -n $sc_config ]] && fail_usage "$f_incompat_options" "-p" "-c" [[ -z $install_media ]] && fail_usage "$media_missing" "zoneadm install" # The install can't both preserve and unconfigure [[ -n $unconfig_zone && -n $preserve_zone ]] && fail_usage "$f_incompat_options" "-u" "-p" # Must pick one or the other, unless it is a unified archive. if [[ -z $unconfig_zone && -z $preserve_zone ]]; then # If it's not an archive, it's not a unified archive. [[ $inst_type == archive ]] || fail_usage "$cfgchoice_missing" # If this fails, it must be a legacy archive. typeset -A uar_props read_uar_info "$install_media" zone.xopts uar_props >/dev/null 2>&1 || fail_usage "$cfgchoice_missing" # Recovery archives default to -p, others default to -u. key=${!uar_props[archive][*]} if [[ ${uar_props[archive][$key][recovery]} == Yes ]]; then preserve_zone=-p else unconfig_zone=-u fi fi # Check to restrict the install operation with "-a" # or "-d" option if [[ $inst_type == @(archive|directory) ]]; then # If rpool dataset exists terminate the process /usr/sbin/zfs list "${zone.path.ds}/rpool" >/dev/null 2>&1 if (( $? == 0 )); then fail_tryagain "$op_abort_msg" "${zone.path.ds}/rpool" fi fi # # From here on out, an unspecified exit or interrupt should exit with # ZONE_SUBPROC_FATAL, 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. Note, however, that this is influenced by # pin_datasets() and trap_exit(). # start_log zone install "${save_args[@]}" vlog "Starting pre-installation tasks." pin_datasets "${zone.path.ds}" || fatal "$f_pin" trap trap_cleanup INT trap trap_exit EXIT EXIT_CODE=$ZONE_SUBPROC_FATAL zone.ua_archived_zone=${archived_zone:-} vlog "Installation started for zone \"${zone.name}\"" install_image zone "$inst_type" "$install_media" [[ "$SANITY_SKIP" == "1" ]] && touch "${zone.root}/.sanity_skip" # # 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. # log "$p2ving" vlog "running: p2v $OPT_V $unconfig_zone $OPT_C ${zone.name} ${zone.path}" /usr/lib/brand/solaris10/p2v -m "$p2v_prog" \ $OPT_V $unconfig_zone $OPT_C "${zone.name}" "${zone.path}" p2v_result=$? if (( $p2v_result == 0 )); then vlog "$p2v_done" EXIT_CODE=$ZONE_SUBPROC_UNAVAILABLE else log "$p2v_fail" log "\n$install_fail" log "$install_log" "$LOGFILE" exit $ZONE_SUBPROC_FATAL fi # Add a service tag for this zone. add_svc_tag "${zone.name}" "install $inst_type $(basename $install_media)" log "\n$install_good" "${zone.name}" mount_active_be -c zone || fatal "$f_mount_active_be" unpin_datasets "${zone.path.ds}" || error "$f_unpin" finish_log zone logfile trap - EXIT # This needs to be set since the exit trap handler is going run. EXIT_CODE=$ZONE_SUBPROC_OK exit $ZONE_SUBPROC_OK