#!/bin/ksh #$ERR } #---------------------------- cleanup -------------------------------- # # NAME: cleanup # # FUNCTION: # delete temporary files, unmount file systems # # EXECUTION ENVIRONMENT: # # NOTES: # handler for signal 'zero' - called when we exit # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # none # global: # mounts = list of mounted file systems # TMPDIR = temporary directory for bootpkg # DATA = temporary directory that contains contents of the tar archive # location_mnt= directory that will contain the boot package # # RETURNS: (int) # 0 = success # # # OUTPUT: #------------------------------------------------------------------------------- function cleanup { if [[ $unmounted != "yes" ]] then unmount_chroot_libs let unmount_retries=10 while [[ -n ${mounts} ]] && (( unmount_retries > 0 )) do unmount_dir all 2>/dev/null if [[ -n ${mounts} ]] then let unmount_retries=unmount_retries-1 ${SLEEP} 1 fi done [[ -n ${mounts} ]] && unmount_dir all force #only unmount once unmounted="yes" fi cd /tmp [[ -d $DATA ]] && [[ $1 != "mounts" ]] && $RM -rf $DATA >/dev/null 2>&1 [[ $1 = "mounts" ]] && return 0 #cd into a safe directory cd /tmp $RM -rf $TMPDIR >/dev/null 2>&1 [[ $rc != "0" && $new_location = "yes" ]] && $RM -rf $location_mnt >/dev/null 2>&1 [[ $took_mksysb = "yes" && $nim_resources = "yes" ]] && $RM -f $FILE_LIST >/dev/null 2>&1 } #---------------------------- err_signal -------------------------------- # # NAME: err_signal # # FUNCTION: # exits if a signal is received- which calls cleanup # # EXECUTION ENVIRONMENT: # # NOTES: # # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # # global: # # # # OUTPUT: #------------------------------------------------------------------------------- function err_signal { rc=99 exit $rc } #---------------------------- error -------------------------------- # # NAME: error # # FUNCTION: # set rc, exit- which calls cleanup # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # # global: # # OUTPUT: #------------------------------------------------------------------------------- function error { rc=$1 case "$rc" in 13 ) echo "\nBackup device or file name must be an absolute path." >&2 ;; esac exit $rc } #---------------------------- err_from_cmd -------------------------------- # # NAME: err_from_cmd # # FUNCTION: # displays error output of a failed command, exits # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # # global: # ERR = contains the error output of failed commands # # RETURNS: (int) # 0 = success # # # OUTPUT: #------------------------------------------------------------------------------- function err_from_cmd { typeset err_fs=$($DF -P $ERR | $TAIL -1 | $AWK '{print $6}') typeset -i err_fs_free_space=$($DF $err_fs | $TAIL -1 | $AWK '{print $3}') if [[ ! -s $ERR && $err_fs_free_space -eq 0 ]]; then if [[ -n $1 ]]; then echo "An error occurred with the $1 command. The $err_fs filesystem is filled up. Unable to display the stderr of the $1 command." >&2 else # Should never get here, since all calls within this file send the name of the failing command as a parameter. # Just in case... echo "An error occurred. The $err_fs filesystem is filled up. Unable to display the stderr of the failing command." >&2 fi fi $CAT $ERR >&2 error 20 } #---------------------------- warning_from_cmd -------------------------------- # # NAME: warning_from_cmd # # FUNCTION: # displays error output of a failed command without exiting # # DATA STRUCTURES: # parameters: # # global: # ERR = contains the error output of failed commands # # OUTPUT: #------------------------------------------------------------------------------- function warning_from_cmd { $CAT $ERR >&2 } #---------------------------- check_input -------------------------------- # # NAME: check_input # # FUNCTION: # validate input to bootpkg # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # # global: # nim_resources = produce a tarball of NIM installation resources? # bi_only = only produce boot image? # location = where to put the image/tarball # device = device for which boot image will be created # bosinst_data = NIM installation resource # resolv_conf = NIM installation resource # cust_script = NIM installation resource # # RETURNS: (int) # 0 = success # # # OUTPUT: #------------------------------------------------------------------------------- function check_input { #N and O are mutually exclusive, b, r, and c only make sense with N [[ $nim_resources = "yes" && $bi_only = "yes" ]] && error 1 #ERROR [[ $bosinst_data = "yes" || $resolv_conf = "yes" || $cust_script = "yes" ]] && [[ $nim_resources != "yes" ]] && error 2 #ERROR #location and device are required, device must be "ent", "disk", "tape", or "cd" [[ -z $location ]] && error 3 #ERROR [[ -z $device ]] && error 4 #ERROR [[ $device = "ent" || $device = "disk" || $device = "tape" || $device = "cd" ]] || error 5 #ERROR [[ $nim_resources = "yes" && $device != "ent" ]] && error 11 [[ $nim_resources != "yes" && $no_tar = "yes" ]] && error 12 [[ $location != ?*:?* ]] && [[ $location != /* ]] && no_abs="yes" [[ -n $mksysb ]] && [[ $mksysb != ?*:?* ]] && [[ $mksysb != /?* ]] && no_abs="yes" [[ -n $bosinst_data ]] && [[ $bosinst_data != ?*:?* ]] && [[ $bosinst_data != /?* ]] && no_abs="yes" [[ -n $resolv_conf ]] && [[ $resolv_conf != ?*:?* ]] && [[ $resolv_conf != /?* ]] && no_abs="yes" [[ -n $cust_script ]] && [[ $cust_script != ?*:?* ]] && [[ $cust_script != /?* ]] && no_abs="yes" [[ $no_abs = "yes" ]] && error 13 #set the device to pass to bootpkg case $device in ent) device_param=$ENT_DEV ;; tape) device_param=$TAPE_DEV ;; disk) device_param=$DISK_DEV ;; cd) device_param=$CD_DEV ;; esac } #---------------------------- mount_dir -------------------------------- # # NAME: mount_dir # # FUNCTION: # mounts the specified "object" over the specified local mount point; when # no local mount points are specified, this function will create one # "object"s may be on of the following: # 1) local directory # 2) remote directory (in the form of "host:dir") # 3) local CDROM # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # 1 = object to mount # 2 = local mount point (optional) # global: # access_pnt = set to local access point # mounts = list of mounts performed by mount_dir # disable_cdumount = if cdrom is already mounted by cdromd, don't cdumount # # RETURNS: (int) # 0 = success; local mount pnt returned via access_pnt # # OUTPUT: #------------------------------------------------------------------------------- function mount_dir { typeset object=${1} typeset -i i=0 typeset mnt_params="" typeset access_pnt_inode="" typeset automount_flag="" # NOTE that access_pnt is a global, not a local variable access_pnt=${2:-""} [[ -z "${object}" ]] && return 0 # check for unnecessary mounts if [[ ${object} != ?*:?* ]] && \ [[ ${object} != /dev/cd[0-9]* ]] && \ [[ -z "${access_pnt}" ]] then # object is local directory and no specific mount point requested # therefore, no reason to mount it - return current path access_pnt=${object} return 0 fi # need a local mount point? if [[ -z "${access_pnt}" ]] then # going to create a tmp directory in TMPDIR with a prefix of "mnt" # look for lowest, unused seqno while (( ${i} < ${MAX_MNT} )) do access_pnt=${TMPDIR}/mnt${i} [[ ! -d ${access_pnt} ]] && break let i=i+1 done (( ${i} >= ${MAX_MNT} )) && error 6 fi # need to create the local mount point? if [[ ! -r ${access_pnt} ]] then # yes - doesn't already exist ${MKDIR} ${access_pnt} 2>${ERR} || err_from_cmd ${MKDIR} # get the inode of this directory. This way when we attempt # to remove it later we know we are removing the same directory. access_pnt_inode=`${LS} -i -d ${access_pnt} 2>/dev/null | ${AWK} '{print ":"$1}'` fi # mount the "object" (either local CDROM, remote dir, or local dir) case ${object} in /dev/cd[0-9]*) # CDROM # check if the device is manage by the cdromd ${CDCHECK} -aq ${object} 2>/dev/null 1>&2 # If cdromd is running and we chroot to do a spot copy, cdromd will # not be detected in the chroot environment. We use AUTOMOUNT_DISABLE_FLAG to # disable all cd automount calls. # AUTOMOUNT_DISABLE_FLAG is set by c_instspot.c if [[ $? -eq 0 ]] && [[ $AUTOMOUNT_DISABLE_FLAG != "true" ]] then # cdrom is managed by cdromd automount_flag="true" ${CDCHECK} -mq ${object} 2>/dev/null 1>&2 #check if cdrom is mounted if [[ $? -eq 0 ]]; then disable_cdumount="true" access_pnt=`${CDCHECK} -mq ${object} 2>/dev/null` else if ${CDMOUNT} -q ${object} 2>${ERR} #mount the cdrom then access_pnt=`${CDCHECK} -mq ${object} 2>/dev/null` # get its mount point else warning_from_cmd ${CDMOUNT} err_from_cmd ${CDMOUNT} fi fi else mnt_params="-r -vcdrfs" fi ;; ?*:?*) # remote dir mnt_params="-ohard,intr -vnfs" ;; *) ;; # local dir esac # if cdromd is not running, run the mount command if [[ $automount_flag != "true" ]]; then # if mount_opts is set, lets try them # if the mount fails, try removing the mount_opts if ${MOUNT} ${mnt_params} ${mount_opts} ${object} ${access_pnt} 2>${ERR} then : else warning_from_cmd ${MOUNT} ${MOUNT} ${mnt_params} ${object} ${access_pnt} 2>${ERR} || \ err_from_cmd ${MOUNT} fi fi # remember that we've got something mounted # NOTE that we're pushing this onto a stack - it is important that we do # the unmounts in reverse order mounts="${object}:${access_pnt} ${mounts}" } # end of mount_dir #---------------------------- unmount_dir -------------------------------- # # NAME: unmount_dir # # FUNCTION: # unmounts anything which has been mounted by mount_dir # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # 1 = either the keyword "all" or local mount pnt # global: # mounts = list of mounts performed by mount_dir # # RETURNS: (int) # 0 = success # 1 = failure # # OUTPUT: #------------------------------------------------------------------------------- function unmount_dir { typeset dir=${1:-all} typeset force=${2} typeset i="" typeset mnt_pnt="" typeset tmp="" # cd to neutral dir if cd /tmp 2>${ERR} then : else warning_from_cmd cd return 1 fi # look for the specified for i in ${mounts} do # separate stanza mnt_pnt=${i##*:} # this the one we're looking for? if [[ ${dir} = ${mnt_pnt} ]] || [[ ${dir} = all ]] then # unmount it, but first perform a sync and an slibclean to make # sure that nothing in the mount is still thought to be busy. ${SYNC} ${SLIBCLEAN} # If unmounting libraries that we set up for a chroot # environment, reset the libpath to make sure that # the mount will succeed. if [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS1} ]] || [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS2} ]] then ${UNSET_CHROOT_LIBPATH} fi # check if the device is manage by the cdromd object=${i%%:*} ${CDCHECK} -aq ${object} 2>/dev/null 1>&2 if [[ $? -eq 0 ]] && [[ $AUTOMOUNT_DISABLE_FLAG != "true" ]] then # cdrom is managed by cdromd ${CDCHECK} -mq ${object} 2>/dev/null 1>&2 # check if cdrom is mounted if [[ $? -eq 0 ]] && [[ $disable_cdumount != "true" ]]; then if ! ${CDUMOUNT} ${object} 1> /dev/null 2>${ERR} then warning_from_cmd ${CDUMOUNT} tmp="${i} ${tmp}" fi fi else if [[ -n ${force} ]] then # We were told to force unmount this directory. # Try to unmount without the force first. ${UNMOUNT} ${mnt_pnt} > /dev/null 2>&1 if [[ $? -ne 0 ]] then if ! ${UNMOUNT} -f ${mnt_pnt} 1> /dev/null 2>${ERR} then warning_from_cmd ${UNMOUNT} tmp="${i} ${tmp}" fi fi else if ! ${UNMOUNT} ${mnt_pnt} 2>${ERR} then warning_from_cmd ${UNMOUNT} tmp="${i} ${tmp}" fi fi fi else # not unmounting this dir - add it back to the list tmp="${i} ${tmp}" fi done # new list reflects the mounts that are still active mounts=${tmp} } # end of unmount_dir #---------------------------- mount_paths -------------------------------- # # NAME: # # FUNCTION: # # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # # global: # location = where to put the image/tarball # device = device for which boot image will be created # bosinst_data = NIM installation resource # resolv_conf = NIM installation resource # cust_script = NIM installation resource # *_mnt = mount point of the above listed paths # took_mksysb = was mksysb of this system taken? # # RETURNS: (int) # 0 = success # # # OUTPUT: #------------------------------------------------------------------------------- function mount_paths { #first check if location is supposed to be created- if not, mount it if [[ ! -d $location && $location != ?*:?* ]] then $MKDIR -p $location >$ERR 2>&1 || err_from_cmd mkdir location_mnt=$location new_location="yes" else mount_dir $location location_mnt=$access_pnt fi #check each path provided, if nfs-mountable- mount it #mksysb if [[ $took_mksysb != "yes" ]] then mount_dir $mksysb mksysb_mnt=$access_pnt fi #bosinst_data if [[ -n $bosinst_data ]] then mount_dir $bosinst_data bosinst_data_mnt=$access_pnt elif [[ $nim_resources = "yes" ]] then [[ -f "/var/adm/ras/bosinst.data" ]] && bosinst_data="/var/adm/ras/bosinst.data" fi #cust- this one has no default value if [[ -n $cust_script ]] then mount_dir $cust_script cust_script_mnt=$access_pnt fi #resolv_conf if [[ -n $resolv_conf ]] then mount_dir $resolv_conf resolv_conf_mnt=$access_pnt elif [[ $nim_resources = "yes" ]] then [[ -f "/etc/resolv.conf" ]] && resolv_conf="/etc/resolv.conf" fi #create data directory inside of location DATA=$location_mnt/data_$$ $MKDIR $DATA >$ERR 2>&1 || err_from_cmd mkdir } #---------------------------- get_newest_ver -------------------------------- # # NAME: get_newest_ver # # FUNCTION: # Given a version number in VRMF, and a list of versions in VRMF, # output the latest version in the list that is <= the given version # number # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: file with list of VRMFs # a version in VRMF # global: # # RETURNS: (int) # 0 = success # # OUTPUT: a VRMF version number #------------------------------------------------------------------------------- function get_newest_ver { typeset VERSION_FILE=$1 typeset MYVER=$2 typeset -i10 sver=0 srel=0 smod=0 sfix=0 typeset -i10 this_ver=0 this_rel=0 this_mod=0 this_fix=0 typeset final LINE [[ -f $VERSION_FILE ]] || error $ERR_FILE_MODE "open" $VERSION_FILE sver=`echo $MYVER | $CUT -d '.' -f 1` || err_from_cmd cut srel=`echo $MYVER | $CUT -d '.' -f 2` || err_from_cmd cut smod=`echo $MYVER | $CUT -d '.' -f 3` || err_from_cmd cut sfix=`echo $MYVER | $CUT -d '.' -f 4` || err_from_cmd cut while read LINE do if [[ $MYVER = $LINE ]] then final=$MYVER break fi this_ver=`echo $LINE | $CUT -d '.' -f 1` || err_from_cmd cut this_rel=`echo $LINE | $CUT -d '.' -f 2` || err_from_cmd cut this_mod=`echo $LINE | $CUT -d '.' -f 3` || err_from_cmd cut this_fix=`echo $LINE | $CUT -d '.' -f 4` || err_from_cmd cut if [[ $sver -gt $this_ver ]] then final=$LINE elif [[ $sver -eq $this_ver && $srel -gt $this_rel ]] then final=$LINE elif [[ $sver -eq $this_ver && $srel -eq $this_rel && $smod -gt $this_mod ]] then final=$LINE elif [[ $sver -eq $this_ver && $srel -eq $this_rel && $smod -eq $this_mod && $sfix -gt $this_fix ]] then final=$LINE fi done <$VERSION_FILE echo $final } #---------------------------- prep_mksysb -------------------------------- # # NAME: prep_mksysb # # FUNCTION: # when the source is a mksysb, mounts resources and prepares variables # to later execute mksysb_SPOT # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function prep_list { typeset ver_list tar_list ls_list tf # get the version/release/mod levels from the mksysb and locate the appropriate SPOT list cd $DATA $RESTORE $mksysb_mnt ./image.data >$ERR 2>&1 || err_from_cmd restore mksysb_ver=$($GREP "OSLEVEL=" ./image.data 2>/dev/null | $CUT -d ' ' -f 2) $RM -f ./image.data >$ERR 2>&1 || err_from_cmd rm this_list=$TMPDIR/list ver_list=$TMPDIR/ver_list tar_list=$TMPDIR/tar_list ls_list=$TMPDIR/ls_list tf=$TMPDIR/tmp_file # get the right list from the SPOT list file $EGREP '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:' $mspot_list >$tf || err_from_cmd egrep $SED 's/://g' $tf >$ver_list || err_from_cmd sed final=$(get_newest_ver $ver_list $mksysb_ver) || err_from_cmd get_newest_var ${AWK} -vver=$final 'BEGIN{this=0} /.*:$/ {this=0;if ($1 == ver ":") {this=1;next}} {if (this == 1 && NF > 0) print;}' $mspot_list > $this_list 2> $ERR || err_from_cmd awk # now find the right tar file (for the libnim.a.min) $LS /usr/lib/bootpkg/*-spotpkg.tar >$ls_list || err_from_cmd ls $AWK '{gsub("/usr/lib/bootpkg/", "", $0);gsub("-spotpkg.tar", "", $0); print}' $ls_list >$tar_list || err_from_cmd awk final=$(get_newest_ver $tar_list $mksysb_ver) || err_from_cmd get_newest_var tar_file=${BOOTPKG_LIBROOT}/${final}-spotpkg.tar #if the list is empty, error out [[ ! -s $this_list ]] && error 7 #${ERR_NO_LIST} #create the SPOT directory $MKDIR -p $DATA/SPOT >$ERR 2>&1 || err_from_cmd mkdir } #---------------------------- restore_symlinks -------------------------------- # # NAME: restore_symlinks # # FUNCTION: # Given a symlink and a backup file, this function will restore the file # linked to by the symbolic link and will continually follow successive # symlinks restored until a regular file is restored. # # EXECUTION ENVIRONMENT: # # NOTES: # makes recursive calls # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: relative path of symlink # path to backup file # boolean recursive value # global: # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function restore_symlinks { SYMLINK=$1 BACKUP_NAME=$2 ONE_MORE=$3 #restore the actual file $RESTORE $BACKUP_NAME $SYMLINK > /dev/null 2> ${ERR} || err_from_cmd restore #base case is that the current file is not a symlink if [[ $ONE_MORE = "0" ]] then #progress is made by following whatever is linked to next NEW_LINK=$($LS -l $SYMLINK | $AWK '{print $11}') #stop the recursion if the current file is not a symlink [[ -h $SYMLINK ]] || ONE_MORE=1 [[ $ONE_MORE = "0" ]] && restore_symlinks ".$NEW_LINK" $BACKUP_NAME $ONE_MORE fi } #end restore_symlinks #---------------------------- mksysb_SPOT -------------------------------- # # NAME: mksysb_SPOT # # FUNCTION: # Extracts necessary files from the source mksysb based on the SPOT lists and # the .proto files contained on the mksysb # # EXECUTION ENVIRONMENT: # # NOTES: # # # RECOVERY OPERATION: # calls error function # # DATA STRUCTURES: # parameters: mksysb path, spot path, list file path, lpp_source mount point # global: # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function mksysb_SPOT { MKSYSB=$1 SPOTDIR=$2 LISTFILE=$3 PKG=$4 TEMP1=$TMPDIR/$$.ong TEMP2=$TMPDIR/$$.tuk TEMP11=$TMPDIR/$$.ong.sym TEMP22=$TMPDIR/$$.tuk.sym TEMP111=$TMPDIR/$$.ong.sorted TEMP222=$TMPDIR/$$.tuk.sorted NEW_ROOT=$SPOTDIR/usr/lpp/bos/inst_root RESTORE_CMD="$SBIN/restore -xqf" no_proto= no_file= #determine which protofile to use from the device variable if [[ $device = "ent" ]] then PROTO_LIST=./usr/lib/boot/network/chrp.${device}.proto else PROTO_LIST=./usr/lib/boot/chrp.${device}.proto fi #we'll need the disk proto file for atm boot images PROTO_LIST="$PROTO_LIST ./usr/lib/boot/chrp.disk.proto" $GREP /usr/lpp/bos/inst_root $LISTFILE | $SED 's/\/usr\/lpp\/bos\/inst_root//' > $TEMP2 $GREP -v /usr/lpp/bos/inst_root $LISTFILE > $TEMP1 cd $SPOTDIR /usr/sbin/restore -xqdf $MKSYSB ./usr/bin/tee ./usr/lib/methods ./usr/lib/drivers ./usr/lib/microcode ./usr/lpp/bosinst/iscsi ./usr/lib/boot/network/*.proto ./usr/lib/boot/*.proto ./usr/lib/boot/protoext/* ./usr/lib/boot/unix ./usr/lib/boot/unix* ./usr/lpp/bosinst/BosMenus ./usr/lpp/bosinst/tape/tapefiles1 >> /tmp/restore.list 2> ${ERR} || err_from_cmd restore # Ensure relevant directories are created prior to extracting files. # This is a safety measure to prevent umask 077 issues occurring with # tar extractions "losing root ruid/euid". Root cause/resolution of # that issue does not negate this safety measure. for temp_dir in `$TAR -tvf $tar_file | $AWK '{print $NF}' | $AWK 'BEGIN {FS=OFS="/"} {$NF=""; NF--; print}' | /usr/bin/uniq` do $MKDIR -p $temp_dir done #untar the contents of the bos.sysmgt.nim.spot for this version $TAR -xf $tar_file 2>$ERR >> /tmp/restore.list || err_from_cmd tar if [[ $device = "tape" ]] then #move tapefiles1 to same location (directory) that #tape boot image is placed. $MV ./usr/lpp/bosinst/tape/tapefiles1 $location >$ERR 2>&1 || err_from_cmd mv fi #call parse_proto on each .proto file extracted for i in $PROTO_LIST do if [[ -f $SPOTDIR/$i ]] then #get the name of the boot device this proto file is for dev=$(echo ${i##*/} | $AWK -F. '{print $2}') #grab all the files needed in the /usr part of the SPOT # (they are the 6th field in the proto file, if we're looking at a regular file) $AWK '{if (length($6) > 0 && $2 == "----" && substr($6, 1, 4) == "/usr"){print "."$6}}' $SPOTDIR/$i >>$TEMP1 2>${ERR} || err_from_cmd awk $AWK '{if (length($6) > 0 && $2 == "----" && substr($6, 1, 4) == "/usr"){print "."$6}}' $SPOTDIR/$i >>$TEMP11 2>${ERR} || err_from_cmd awk #grab all the files needed in the root part of the SPOT (same rules as above) $AWK '{if (length($6) > 0 && $2 == "----" && substr($6, 1, 4) != "/usr"){print "."$6}}' $SPOTDIR/$i >>$TEMP2 2>${ERR} || err_from_cmd awk $AWK '{if (length($6) > 0 && $2 == "----" && substr($6, 1, 4) != "/usr"){print "."$6}}' $SPOTDIR/$i >>$TEMP22 2>${ERR} || err_from_cmd awk #add all files listed in this device's protoext files (there's only /usr files in there) $AWK '{if (length($6) > 0){print "."$6}}' $SPOTDIR/usr/lib/boot/protoext/${dev}.proto.ext.* >>$TEMP1 2>${ERR} || err_from_cmd awk $AWK '{if (length($6) > 0){print "."$6}}' $SPOTDIR/usr/lib/boot/protoext/${dev}.proto.ext.* >>$TEMP11 2>${ERR} || err_from_cmd awk #Some protoext files may refer to symbolic links even though it is not noted in the file #we still have to track down these links and restore them. This will be done through the #calls to restore_symlinks below. else no_proto=1 fi done #first restore all proto files and all protoext files, then restore the /usr file system of the SPOT #restore /usr part and then / part sort $TEMP1 > $TEMP111 [[ -s $TEMP1 ]] && ${XARGS} ${RESTORE} $MKSYSB < $TEMP111 >> /tmp/restore.list 2> ${ERR} || err_from_cmd restore #in /usr part, if a proto file is a symlink, restore the file(s) it links to # also, warn if proto files are missing for i in $($CAT $TEMP11) do [[ ! -e $i ]] && no_file=1 #check for missing files [[ -h $i ]] && restore_symlinks $i $MKSYSB 0 done #do the same for root part #restore the inst_root part of the SPOT $MKDIR -p $NEW_ROOT >/dev/null 2>${ERR} || err_from_cmd mkdir $MKDIR -p $NEW_ROOT/var/adm/nim > /dev/null 2>&1 $LN -fs $SPOTDIR/usr/bin $NEW_ROOT/bin >/dev/null 2>${ERR} || err_from_cmd ln $LN -fs $SPOTDIR/usr/lib $NEW_ROOT/lib >/dev/null 2>${ERR} || err_from_cmd ln cd $NEW_ROOT >/dev/null 2>${ERR} || err_from_cmd cd cat << END_HELP >> $TEMP2 ./etc/objrepos/Cu* ./etc/objrepos/Pd* ./sbin/helpers/* ./sbin/helpers/*/* END_HELP sort $TEMP2 > $TEMP222 [[ -s $TEMP2 ]] && ${XARGS} ${RESTORE_CMD} $MKSYSB < $TEMP222 >> /tmp/restore.list 2> ${ERR} || err_from_cmd restore for i in $($CAT $TEMP22) do [[ ! -e $i ]] && no_file=1 #check for missing files [[ -h $i ]] && restore_symlinks $i $MKSYSB 0 done $RM $TEMP1 $TEMP2 $TEMP11 $TEMP22 $TEMP111 $TEMP222 2>&1 > /dev/null #restore the symlinks in inst_root $LN -fs /usr/bin $NEW_ROOT/bin >/dev/null 2>${ERR} || err_from_cmd ln $LN -fs /usr/lib $NEW_ROOT/lib >/dev/null 2>${ERR} || err_from_cmd ln } #---------------------------- get_nfs_exp -------------------------------------- # # NAME: get_nfs_exp # # FUNCTION: # Checks whether the file system is remote or local if the file system is # remote file system then spot location is to be substitued with node # name and it's path. # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: spotlocation # global: # # RETURNS: (char) # spotlocation = success # # OUTPUT: #------------------------------------------------------------------------------- function get_nfs_exp { typeset ERROR='eval echo error in get_nfs_exp >&2 ; $RM -f $TF1 $TF2; return 1' typeset DIR=$1 typeset TF1=/tmp/tf1.$$ typeset TF2=/tmp/tf2.$$ typeset HOST MNT_PT FS_NAME JUNK typeset HIT="" typeset DIR_NFS $RM -f $TF1 $TF2 IS_NFS=$($FIND $DIR -prune -fstype nfs) || $ERROR if [[ -n $IS_NFS ]]; then $MOUNT > $TF1 || $ERROR $AWK '$4~/(^nfs*)/{print}' $TF1 > $TF2 || $ERROR while read HOST MNT_PT FS_NAME JUNK ; do if [[ ${DIR#${FS_NAME}} != ${DIR} ]]; then if [[ ${#HIT} -lt ${#FS_NAME} ]]; then HIT=${FS_NAME} DIR_NFS="$HOST:$MNT_PT"${DIR#$HIT} fi fi done < $TF2 [[ -z $HIT ]] && $ERROR echo $DIR_NFS else echo $DIR fi $RM -f $TF1 $TF2 } #---------------------------- setup_chroot_env -------------------------------- # # NAME: setup_chroot_env # # FUNCTION: # mounts the appropriate dirs in order to setup a chroot environment # within a SPOT # this kind of environment is required because we use installp to install # software into a SPOT, but it doesn't understand any pathnames other # than "/" and "/usr" # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # 1 = optional; when present, it is the pathname of the # inst_root directory to use # global: # location = SPOT pathname # new_root = pathname of new root (where we'll chroot to) # chroot = command to execute in order to chroot # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function setup_chroot_env { typeset ERROR='eval echo error in setup_chroot_env >&2' typeset root_sync="" typeset inr="" typeset inr_path="" typeset inr_ln="" typeset spot_fs="" typeset spot_fs_path="" typeset first_dir="" typeset dir_created="" typeset first_dir_inode="" typeset spot_location="$DATA/SPOT/usr" # initialize pathnames for the inst_root directory # this directory will become the root ("/") directory after we chroot if [[ -n "${1}" ]] then root_sync=TRUE inr=${1} inr_path=${inr}${inr%/*} inr_ln=${inr}${inr} else inr="${spot_location}/${INST_ROOT}" inr_path=${inr}/lpp/bos inr_ln=${inr_path}/inst_root fi # initialize pathnames for the SPOT's filesystem which will be created in # the inst_root spot_fs=${spot_location} [[ -n "${spot_fs%/*}" ]] && \ spot_fs_path=${inr}${spot_fs%/*} || \ spot_fs_path="" # make sure SPOT exists [[ ! -d ${spot_location} ]] && error 8 #${ERR_DIR_DNE} spot ${spot_location} [[ ! -d ${spot_location}/${INST_ROOT} ]] && \ error 9 #${ERR_DIR_DNE} inst_root "${spot_location}/${INST_ROOT}" # is this a non-/usr SPOT or are we going to root-sync a client? if [[ ${spot_location} != /usr ]] || [[ -n "${root_sync}" ]] then # not a /usr SPOT (or a root-sync), so we've got some things to do # we've got to construct an environment which we can chroot into in before # calling installp because installp only knows how to install into # the /usr filesystem new_root=${inr} # make sure no previous mounts have been left dangling ${UNMOUNT} ${new_root}/usr >/dev/null 2>&1 ${UNMOUNT} ${new_root}/tmp >/dev/null 2>&1 ${UNMOUNT} ${new_root}/tftpboot >/dev/null 2>&1 ${UNMOUNT} ${new_root}/images >/dev/null 2>&1 ${UNMOUNT} ${new_root}/opt >/dev/null 2>&1 ${UNMOUNT} ${new_root}/dev >/dev/null 2>&1 ${UNMOUNT} ${new_root}${NIM_CHROOT_LIBS1} >/dev/null 2>&1 ${UNMOUNT} ${new_root}${NIM_CHROOT_LIBS2} >/dev/null 2>&1 # create subdir in the root which corresponds to the filesystem # where the root resides if [[ ! -d ${inr_path} ]] then $MKDIR -p $inr_path >$ERR 2>&1 || err_from_cmd mkdir fi if [[ ${inr_ln} != / ]] then # make sure no previous links have been left around ${RM} -rf ${inr_ln} >/dev/null 2>&1 # create sym link (to fake out the filesystem) ${LN} -s / ${inr_ln} 2>${ERR} || err_from_cmd ${LN} tmp_files="${inr_ln} ${tmp_files}" fi # create subdir in the inst_root which corresponds to the filesystem # where the SPOT resides if [[ -n "${spot_fs_path}" ]] && [[ ! -d ${spot_fs_path} ]] then $MKDIR -p ${spot_fs_path} >$ERR 2>&1 || err_from_cmd mkdir fi if [[ ${spot_fs} != /usr ]] then # make sure no previous links have been left around ${RM} -rf ${inr}${spot_fs} >/dev/null 2>&1 # create sym links (to fake out the filesystem) ${LN} -s / ${inr}${spot_fs} 2>${ERR} || err_from_cmd ${LN} tmp_files="${inr}${spot_fs} ${tmp_files}" fi # mount the SPOT over the new_root /usr directory spot_location_nfs=$(get_nfs_exp $spot_location) || $ERROR mount_dir $spot_location_nfs $new_root/usr || $ERROR # mount the server's /tmp over the new_root /tmp directory mount_dir /tmp ${new_root}/tmp # mount the server's /dev over the new_root /dev directory mount_dir /dev ${new_root}/dev # initialize the chroot syntax chroot="${CHROOT} ${new_root}" # For a non-/usr SPOT, always make sure the server's libraries # are available to the chroot'd environment since we'll be # running the server's kernel when processing the SPOT. # Create the mount point for SPOTs that were defined prior # to 4.2.0 if [[ ${location} != /usr ]] then [[ ! -d ${new_root}${NIM_CHROOT_LIBS1} ]] && \ ${MKDIR} -p ${new_root}${NIM_CHROOT_LIBS1} mount_dir /usr/ccs/lib ${new_root}${NIM_CHROOT_LIBS1} [[ ! -d ${new_root}${NIM_CHROOT_LIBS2} ]] && \ ${MKDIR} -p ${new_root}${NIM_CHROOT_LIBS2} mount_dir /usr/lib ${new_root}${NIM_CHROOT_LIBS2} # We now have our system's /usr/ccs/lib and /usr/lib mounted within # our spot which we'll use in our LIBPATH instead of the spot's # /usr/ccs/lib and /usr/lib in the chroot environment. However, # these mounted directories still contain symbolic links to # /usr/ccs/lib and /usr/lib which resolve to the spot's # /usr/ccs/lib and /usr/lib in the chroot environment. Therefore we # need to create two new directories which contain these same links # except have them point to our mounted directories and also have # them take precedence in our LIBPATH. # iterate through the two library directories we've overmounted for lib in /usr/ccs/lib /usr/lib do # create directory hierarchy to hold symbolic links for dir in `$FIND $lib -type d` do [[ ! -d ${new_root}${NIM_CHROOT_LIBS_LINKS_BASE}${dir} ]] && \ $MKDIR -p ${new_root}${NIM_CHROOT_LIBS_LINKS_BASE}${dir} done # create symbolic links # 'linkFrom' is the pathname to an existing symbolic link # 'linkTo' is the pathname 'linkFrom' points to for linkFrom in `$FIND $lib -type l` do linkTo=`$LS -l $linkFrom | $AWK '{print $11}'` echo $linkTo | $EGREP '^(/usr/ccs/lib|/usr/lib)' > /dev/null 2>&1 && \ [[ ! -e ${new_root}${NIM_CHROOT_LIBS_LINKS_BASE}${linkFrom} ]] && \ $LN -s ${NIM_CHROOT_LIBS_BASE}${linkTo} ${new_root}${NIM_CHROOT_LIBS_LINKS_BASE}${linkFrom} done done fi else # /usr SPOT new_root="" chroot="" fi } # end of setup_chroot_env function unmount_chroot_libs { mnt_pnt="" found_mnt="" lib="" # Nothing to do if working with a /usr SPOT since we didn't mount # the libraries in the first place. [[ ${location} = /usr ]] && return 0 # Look for the mounted libraries in the mount table. Then look through # the mount list if it appears we need to unmount the libraries. ${MOUNT} | ${EGREP} -q "(${NIM_CHROOT_LIBS1}|${NIM_CHROOT_LIBS2})" if [[ $? -eq 0 ]] then for i in ${mounts} do # separate stanza mnt_pnt=${i##*:} # is this one of the 2 we're looking for? if [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS1} ]] then unmount_dir ${mnt_pnt} force found_mnt=${mnt_pnt} lib=${NIM_CHROOT_LIBS1} elif [[ ${mnt_pnt} = *${NIM_CHROOT_LIBS2} ]] then unmount_dir ${mnt_pnt} force found_mnt=${mnt_pnt} lib=${NIM_CHROOT_LIBS2} fi done fi # If we found a mount point above, unmount the SPOT from the chroot # environment. This may also need force unmounting because we force # unmounted the libraries which were mounted in the SPOT's subdirs. if [[ -n ${found_mnt} ]] then # Get the SPOT mount point by stripping off the end of the # library's mount point (matching the library location in the # chroot environment), then adding /usr back on. mnt_pnt=${found_mnt%%${lib}}/usr unmount_dir ${mnt_pnt} force fi # remove temporary LIBPATH links directores for chroot environment # (see setup_chroot_env function) [[ -d ${location}${NIM_CHROOT_LIBS_LINKS_BASE#/usr} ]] && \ $RM -rf ${location}${NIM_CHROOT_LIBS_LINKS_BASE#/usr} return 0 } #---------------------------- build_nim_resources -------------------------------- # # NAME: build_nim_resources # # FUNCTION: # create the tarball of NIM resources # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # none # global: # location_mnt = mount point where to put the image/tarball # bosinst_data = NIM installation resource # resolv_conf = NIM installation resource # cust_script = NIM installation resource # index = file that tells the filenames of NIM resources in the tarball # bi_name = name of boot image # took_mksysb = was mksysb of this system taken? # # RETURNS: (int) # 0 = success # # # OUTPUT: #------------------------------------------------------------------------------- function build_nim_resources { index=$DATA/index #touch the index file >$index #add the SPOT to the index echo "spot:./SPOT" >>$index #add the boot image to the index echo "boot:./$bi_name" >>$index #try to hard-link the mksysb file (time-saver), else just copy it over (and get yourself a cup of coffee) if [[ $took_mksysb != "yes" ]] then $LN $mksysb_mnt $DATA/${mksysb_mnt##*/} >/dev/null 2>&1 || $CP $mksysb_mnt $DATA/ fi echo "mksysb:./${mksysb_mnt##*/}" >>$index >$ERR if [[ -n $gen_bosinst_data ]] then $CAT >$DATA/bosinst.data <<__END__ CONSOLE = Default INSTALL_METHOD = overwrite PROMPT = no EXISTING_SYSTEM_OVERWRITE = yes INSTALL_X_IF_ADAPTER = yes RUN_STARTUP = no RM_INST_ROOTS = no ERROR_EXIT = CUSTOMIZATION_FILE = TCB = no INSTALL_TYPE = BUNDLES = RECOVER_DEVICES = Default BOSINST_DEBUG = no ACCEPT_LICENSES = yes DESKTOP = CDE INSTALL_DEVICES_AND_UPDATES = yes IMPORT_USER_VGS = ENABLE_64BIT_KERNEL = Default CREATE_JFS2_FS = Default ALL_DEVICES_KERNELS = yes GRAPHICS_BUNDLE = yes MOZILLA_BUNDLE = no KERBEROS_5_BUNDLE = no SERVER_BUNDLE = no REMOVE_JAVA_118 = no HARDWARE_DUMP = yes ADD_CDE = no ADD_GNOME = no ADD_KDE = no ERASE_ITERATIONS = 0 ERASE_PATTERNS = target_disk_data: LOCATION = SIZE_MB = HDISKNAME = locale: BOSINST_LANG = CULTURAL_CONVENTION = MESSAGES = KEYBOARD = __END__ elif [[ -n $bosinst_data_mnt ]] then $CP $bosinst_data_mnt $DATA/ >$ERR 2>&1 && echo "bosinst_data:./${bosinst_data_mnt##*/}" >>$index fi [[ -n $resolv_conf_mnt ]] && $CP $resolv_conf_mnt $DATA/ >$ERR 2>&1 && echo "resolv_conf:./${resolv_conf_mnt##*/}" >>$index [[ -n $cust_script_mnt ]] && $CP $cust_script_mnt $DATA/ >$ERR 2>&1 && echo "cust_script:./${cust_script_mnt##*/}" >>$index [[ -s $ERR ]] && err_from_cmd cp #unmount stuff from the SPOT so that we don't try to tar up /dev/* and stuff cleanup "mounts" #remount location (since it was unmounted above) mount_dir $location location_mnt=$access_pnt #reset DATA with the new mount point DATA=${location_mnt}/data_$$ if [[ $no_tar = "yes" ]] then $MV $DATA/* $location_mnt/ else ( cd $DATA $TAR -cf $location_mnt/nim_resources.tar ./* 2>$ERR >/dev/null ) || err_from_cmd tar fi cd /tmp $RM -rf $DATA >/dev/null 2>&1 unmount_dir $location_mnt force } # main #signals trap cleanup 0 trap err_signal 1 2 11 15 #initialization bootpkg_init while getopts :l:d:m:ONb:r:c:f:TB c do case $c in l) location=$OPTARG ;; d) device=$OPTARG ;; m) mksysb=$OPTARG ;; f) mksysb_flags=$OPTARG ;; N) nim_resources="yes" ;; O) bi_only="yes" ;; b) bosinst_data=$OPTARG ;; r) resolv_conf=$OPTARG ;; c) cust_script=$OPTARG ;; T) no_tar="yes" ;; B) gen_bosinst_data="yes" ;; *) error 14 ;; esac done check_input mount_paths if [[ -n $mksysb ]] then #check if the file is a mksysb, error out if not LANG=C $FILE $mksysb_mnt 2>/dev/null | $GREP "backup\/restore" >/dev/null 2>&1 || error 10 else #call mksysb and take a mksysb of this system mksysb_mnt=$DATA/`$OSLEVEL_R`"_mksysb" ${SAVEVG} -X -e -i -f $mksysb_mnt ${mksysb_flags} rootvg >$ERR 2>&1 || err_from_cmd savevg took_mksysb="yes" fi #step 1 : set up the spot lists depending on the mksysb's version prep_list #step 2 : call mksysb_SPOT to extract the SPOT if [[ $took_mksysb = "yes" && $nim_resources = "yes" ]] || [[ $took_mksysb != "yes" ]] then mksysb_SPOT $mksysb_mnt $DATA/SPOT $this_list fi bi_name=${device}.bi if [[ ${mksysb_ver%%\.*} -ge 6 ]] then KERNEL="-k /usr/lib/boot/unix_64" elif [[ -f $DATA/SPOT/usr/lib/boot/unix_mp ]] then KERNEL="-k /usr/lib/boot/unix_mp" else KERNEL="-k /usr/lib/boot/unix_up" fi if [[ $took_mksysb != "yes" ]] then #step 3 : set up the chroot environment setup_chroot_env # Now use the libraries in the chroot environment ${SET_CHROOT_LIBPATH} #step 4 : chroot into the SPOT and call bosboot cmd="$BOSBOOT -ad $device_param $KERNEL -b /tmp/$bi_name" $chroot $cmd >$ERR 2>&1 || err_from_cmd bosboot #put the boot image in location $MV /tmp/$bi_name $DATA/ >$ERR 2>&1 || err_from_cmd mv #if called for boot images only, copy it into location, then nothing more to do if [[ $bi_only = "yes" ]] then $CP $DATA/$bi_name $location_mnt/ >$ERR 2>&1 || err_from_cmd cp exit 0 fi else if [[ $device = "ent" ]] then ( cd / $TAR -xf $tar_file >$ERR 2>&1 ) || err_from_cmd tar fi #just call bosboot- no need to chroot $BOSBOOT -ad $device_param $KERNEL -b $DATA/$bi_name >$ERR 2>&1 || err_from_cmd bosboot fi #now that we have the boot images, check for nim resources provided, and other stuff #create the .tar package based on the input received from the command line. [[ $nim_resources = "yes" ]] && build_nim_resources #get around the savevg problem- make sure it works with savevg