#!/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