#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos72X src/bos/usr/lib/nim/methods/c_mksavevg.sh 1.15.3.6 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 2002,2021 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)10 1.15.3.6 src/bos/usr/lib/nim/methods/c_mksavevg.sh, cmdnim, bos72X, x2021_05A0 1/28/21 11:33:45 # # COMPONENT_NAME: CMDNIM # # FUNCTIONS: ./usr/lib/nim/methods/c_mksavevg.sh # # ORIGINS: 27 # # # (C) COPYRIGHT International Business Machines Corp. 2002 # All Rights Reserved # Licensed Materials - Property of IBM # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # include common NIM shell defines/functions NIMPATH=${0%/*} NIMPATH=${NIMPATH%/*} [[ ${NIMPATH} = ${0} ]] && NIMPATH=/usr/lpp/bos.sysmgt/nim NIM_METHODS="${NIMPATH}/methods" . ${NIM_METHODS}/c_sh_lib #---------------------------- local defines -------------------------------- EXCLUDE_VG="" EXCLUDE_PACKVG="" SAVEVG=/usr/bin/savevg savevg_mnt_dir="" #---------------------------- module globals -------------------------------- REQUIRED_ATTRS="location" OPTIONAL_ATTRS="server comments exclude_files group mk_image savevg_flags size_preview source verbose volume_group force" location="" server="" comments="" exclude_files="" group="" mk_image="" savevg_flags="" size_preview="" source="" verbose="" volume_group="" #------------------------------- check_space ----------------------------------- # # NAME: check_space # # FUNCTION: Calculate the maximum amount of space required for # the savevg image along with the free space available # in the target location. If the maximum required is # greater than the space available, give an error and # exit. Otherwise, show the user the space # requirements and continue. # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # NOTE: The savevg image is packed, so the maximum amount # of space required will probably never be completely # used. The compression rate varies widely depending # on the type of data that is being backed up. # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function check_space { typeset MAX_SPACE_REQ=0 typeset FREE_SPACE=0 typeset USE_EXCLUDE_FILE=0 #default does not use exclude files # get the free space in the target filesystem # (in 1024-byte blocks) FREE_SPACE=`${DF} -k \`${DIRNAME} ${location_access}\` | ${AWK} 'NR==2{print $3}'` [[ -z "${FREE_SPACE}" ]] && err_from_cmd ${DF} # if "e" in flags, use exclude files USE_EXCLUDE_FILE=$(expr "${savevg_flags}" : ".*e") # counts occurences of "e" => exclude MAX_SPACE_REQ=$(calculate_vg_space ${volume_group:-rootvg} ${USE_EXCLUDE_FILE}) (( REQ_MEG = ${MAX_SPACE_REQ} / 1024 + 1 )) (( FREE_MEG = ${FREE_SPACE} / 1024 + 1 )) # print the space information ${C_ERRMSG} ${MSG_SPACE_MKSYSB} ${C_ERRMSG_MSG} $MAX_SPACE_REQ \ $REQ_MEG $FREE_SPACE $FREE_MEG > ${TMPDIR}/msg 2>&1 if [[ `expr "${savevg_flags}" : ".*p"` -eq 0 ]] then cat ${TMPDIR}/msg else head -8 ${TMPDIR}/msg fi # if just previewing space then exit if [ "${size_preview}" = "yes" ] then exit 0 fi # is there enough space for the savevg? if (( MAX_SPACE_REQ > FREE_SPACE )) then # if force ignore space requirements if [ "${force}" != "yes" ] then error ${ERR_SPACE_MKSYSB} fi fi } # end check_space #--------------------------- calculate_vg_space -------------------------------- # # NAME: calculate_vg_space # # FUNCTION: Calculate space ${VG} takes up excluding files if asked # # EXECUTION ENVIRONMENT: # # NOTES: # VG = $1 name of volume group # EF = $2 0 => do not exclude files (default) # >0 => exclude files # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function calculate_vg_space { typeset VG=$1 EF=${2:-0} typeset lv fs LVLIST typeset BUF # command output buffer typeset TEF=$TMPDIR/ef.nim.$$ # temporary exclude file typeset LSVG=/usr/sbin/lsvg typeset LSVG=/usr/sbin/lsvg cd / BUF=$(${LSVG} -l ${VG} | ${AWK} '$6 ~ "^open" && ($2 == "jfs2" || $2 == "jfs") {print $1,$7}') if [[ ${EF} == 0 ]] ; then echo "${BUF}" | while read lv fs; do typeset LVLIST="/dev/${lv} ${LVLIST}" done ${DF} -kIM ${LVLIST} | ${AWK} 'NR > 1 {tot = tot + $4} END {printf "%d",tot+1}' else echo "${BUF}" | while read lv fs; do # this seems ugly but we really need to match how mksysb/savevg works, so... # the long pipeline follows the logic: # - find command to get the files and sizes per FS # - awk to reorder in a manner egrep and we can use (eg, $11=filename first, $2=size) # - egrep out based on the exclude file # - awk to calculate total and buffer by 512K for the header # setup a temporary exclude_file > ${TEF} # process the same as savevg if [[ -f ${EXCLUDE_VG} ]]; then ${CAT} ${EXCLUDE_VG} | ${SED} 's/ //g;s/^ *//g;s/ *$//g;/^$/d' > ${TEF} fi ${FIND} .$fs ! -type s \( -fstype jfs -o -fstype jfs2 \) -xdev -ls | ${AWK} '{print $11,$2}' | ${EGREP} -v -f ${TEF} | ${AWK} -v fs=".$fs" '{tot=tot+$2} END {printf ("%s\t%d\n",fs,tot)}' done | ${AWK} '{tot=tot+$2} END {printf ("%.0d",tot+512)}' # cleanup the temporary exclude file [[ -r ${TEF} ]] && rm -f ${TEF} fi return 0 } #---------------------------- process_exclude_file ---------------------------- # # NAME: process_exclude_file # # FUNCTION: Sets up access to the exclude file that we are # using and copies it to /etc/exclude.${volume_group:-rootvg} so # that the savevg command will use it when backing # up the system. If a previous exclude file exists # it will be saved and restored after the backup. # # Updated to process packing exclude file. # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # # RETURNS: (int) # 0 = success # # OUTPUT: #------------------------------------------------------------------------------- function process_exclude_file { # save the old exclude file if [[ -f ${EXCLUDE_VG} ]]; then ${CP} ${EXCLUDE_VG} ${EXCLUDE_VG}.nim_save.$$ || err_from_cmd "${CP} ${EXCLUDE_VG} ${EXCLUDE_VG}.nim_save.$$" fi # save the old exclude file if [[ -f ${EXCLUDE_PACKVG} ]]; then ${CP} ${EXCLUDE_PACKVG} ${EXCLUDE_PACKVG}.nim_save.$$ || err_from_cmd "${CP} ${EXCLUDE_PACKVG} ${EXCLUDE_PACKVG}.nim_save.$$" fi # set up access to the exclude file if [[ ${exclude_files} = ?*:?* ]]; then # mount remote exclude file nim_mount ${exclude_files} exclude_access=${access_pnt} else # exclude file is local exclude_access=${exclude_files} fi # just to be extra safe, in the case that the exclude_files # resource is local AND already meets the name/location that # savevg would use if [[ "${exclude_access}" != "${EXCLUDE_VG}" ]] then echo ${exclude_files} > /tmp/.nim_pack LANG=C ${EGREP} exclude_packing /tmp/.nim_pack RC=$? if [ "$RC" -ne 0 ] then # put the exclude file in /etc/exclude.${VG} # so that the savevg command will read it ${CP} ${exclude_access} ${EXCLUDE_VG} || err_from_cmd "${CP} ${exclude_access} ${EXCLUDE_ROOTVG}" else ${CP} ${exclude_access} ${EXCLUDE_PACKVG} || err_from_cmd "${CP} ${exclude_access} ${EXCLUDE_PACKVG}" fi ${RM} /tmp/.nim_pack fi nim_unmount ${access_pnt} # add the -e flag since we have successfully copied the exclude_files resource savevg_flags=e${savevg_flags} } # end process_exclude_file #---------------------------- format_savevg_flags ---------------------------- # # NAME: format_savevg_flags # # FUNCTION: The options to savevg_flags are "AVXab:ePimpvZ". This function # makes sure that the flags are in the correct format to # pass to savevg no matter what order they are entered # by the user. # # EXECUTION ENVIRONMENT: # # NOTES: # The -b option to savevg takes a numeric argument. # Make sure that there is a space after the -b flag # and it's argument. If not, savevg will take everything # after the -b flag as the block_size argument. # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # # RETURNS: # # OUTPUT: #------------------------------------------------------------------------------- function format_savevg_flags { in_flags=${1} fmt_flags="" i=1 # get number of characters in flags num_flags=`${ECHO} ${in_flags} | ${WC} -c | ${AWK} '{print $1}'` # Loop through the flags and make sure that there is # a space after the -b flag and it's argument. while [[ $i -lt $num_flags ]]; do flag=`${ECHO} ${in_flags} | ${CUT} -c $i` # if digit print and set digit flag if [[ "${flag}" = +([0-9]) ]]; then fmt_flags=${fmt_flags}`${ECHO} "${flag}\c"` isdigit=true # if not digit print savevg flag elif [ ! "$isdigit" ]; then fmt_flags=${fmt_flags}`${ECHO} "${flag}\c"` else # last thing printed was a digit so # print space before next savevg flag isdigit= # if space just print it if [[ "${flag}" = " " ]]; then fmt_flags=${fmt_flags}`${ECHO} " \c"` # if flag print with hyphen else fmt_flags=${fmt_flags}`${ECHO} " -${flag}\c"` fi fi let i=i+1 done ${ECHO} ${fmt_flags} } # end format_savevg_flags #---------------------------- c_mksavevg_cleanup ---------------------------- # # NAME: c_mksavevg_cleanup # # FUNCTION: Replace the exclude file as it was before we ran # and call the generic cleanup function to make sure # everything gets unmounted. # # EXECUTION ENVIRONMENT: # # NOTES: # calls error on failure # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # # RETURNS: # # OUTPUT: #------------------------------------------------------------------------------- function c_mksavevg_cleanup { # copy the old exclude file back if [[ -f ${EXCLUDE_VG}.nim_save.$$ ]]; then ${MV} ${EXCLUDE_VG}.nim_save.$$ ${EXCLUDE_VG} > /dev/null 2>&1 || err_from_cmd "${MV} ${EXCLUDE_VG}.nim_save.$$ ${EXCLUDE_VG}" else # remove the exclude file we installed if [ -n "${exclude_files}" ] && [ -f "${EXCLUDE_VG}" ]; then ${RM} ${EXCLUDE_VG} || warning_from_cmd "${RM} ${EXCLUDE_VG}" fi fi # copy the old exclude packing file back if [ -f ${EXCLUDE_PACKVG}.nim_save.$$ ] then ${MV} ${EXCLUDE_PACKVG}.nim_save.$$ ${EXCLUDE_PACKVG} > /dev/null 2>&1 || err_from_cmd "${MV} ${EXCLUDE_PACKVG}.nim_save.$$ ${EXCLUDE_PACKVG}" else # remove the exclude file we installed if [ -n "${exclude_files}" ] && [ -f "${EXCLUDE_PACKVG}" ] then ${RM} ${EXCLUDE_PACKVG} || warning_from_cmd "${RM} ${EXCLUDE_PACKVG}" fi fi # clean up the mount point if we mounted the savevg write directory over. # we need to do this here since if the unmount fails the entire directory # might get erased. if [[ -n "${savevg_mnt_dir}" ]]; then nim_unmount ${savevg_mnt_dir} # Check to see if the unmount failed. If it failed then # leave the temporary directory there. We don't want to # inadvertently erase extra files. ${MOUNT} | ${EGREP} -q ${savevg_mnt_dir} if [[ $? -ne 0 ]]; then ${RM} -r ${savevg_mnt_dir} fi fi cleanup } # end c_mksavevg_cleanup #------------------------------- MAIN --------------------------------------- # signal processing trap c_mksavevg_cleanup 0 trap err_signal 1 2 11 15 # NIM initialization nim_init # set parameters from command line while getopts :a:qv c do case ${c} in a) # validate the attr ass parse_attr_ass "${OPTARG}" # include the assignment for use in this environment eval ${variable}=\"${value}\" ;; q) # show attr info cmd_what exit 0 ;; v) # verbose mode (for debugging) set -x for i in $(typeset +f) do typeset -ft $i done ;; \?) # unknown option error ${ERR_BAD_OPT} ${OPTARG} ;; esac done # check for missing attrs ck_attrs # check that bos.sysmgt.sysbr (System Backup and BOS Install Utilities) is installed STATE=`${LSLPP} -qcIL bos.sysmgt.sysbr 2>/dev/null | ${CUT} -d":" -f6` if [[ "${STATE}" != "C" ]]; then nim_name=`${GREP} NIM_NAME ${NIMINFO} | ${CUT} -d"=" -f2` error ${ERR_NO_SYSBR} ${nim_name} fi # handle exclude file resource EXCLUDE_VG=/etc/exclude.${volume_group:-rootvg} EXCLUDE_PACKVG=/etc/exclude_packing.${volume_group:-rootvg} [ -n "${exclude_files}" ] && process_exclude_file # is this machine the image server? if [[ -n "${server}" ]]; then # mount the remote location # going to create a tmp directory at "/tmp/$$.mnt" # look for lowest, unused seqno typeset -i idx=0 while (( ${idx} < ${MAX_MNT} )) do savevg_mnt_dir="/tmp/$$.mnt${idx}" [[ ! -d ${savevg_mnt_dir} ]] && break let idx=idx+1 done (( ${idx} >= ${MAX_MNT} )) && error ${ERR_GEN_SEQNO} /tmp/$$.mnt ${MKDIR} ${savevg_mnt_dir} 2>${ERR} || err_from_cmd ${MKDIR} nim_mount ${server}:`${DIRNAME} ${location}` ${savevg_mnt_dir} location_access=${access_pnt}/`${BASENAME} ${location}` else # location is local to this machine location_access=${location} fi # check savevg_flags format and content if [[ -n "${savevg_flags}" ]]; then # put hyphens in front of all flags savevg_flags=$( ck_installp_flags "${savevg_flags}" ) # make sure all flags are valid /usr/bin/getopt "AVXab:ePimpvZTr" ${savevg_flags} > /dev/null 2>&1 || error ${ERR_BAD_SAVEVG_FLAG} # verify that flags are in correct format savevg_flags=$( format_savevg_flags "${savevg_flags}" ) fi # do space checking only for savevg image if [[ `expr "${savevg_flags}" : ".*r"` -eq 0 ]]; then check_space else # if just previewing space for -r then exit if [ "${size_preview}" = "yes" ] then exit 0 fi fi # call savevg to create the image ${SAVEVG} -f ${location_access} ${savevg_flags} ${volume_group:-rootvg} # exit with return code from savevg RC=$? # all done exit $RC