#!/bin/bash ########################################################################### # # # DO NOT CHANGE THIS FILE - IT WILL BE OVERWRITTEN !!! # # # ########################################################################### # NAME # mfgbkup - Backup all databases and related files # # DESCRIPTION # mfgbkup is a backup script for Progress OpenEdge databases. Besides # the databases is also backup .lg, .st, .*properties and # .ks files if applicable # # SYNTAX # mfgbkup [-D dir] [-a dir] [-d dir] [-e email] [-h] [-s dir] [-v] [-z] [-E environment] [dblist] # -D dir : Progress "$DLC" directory (default: /${qcLOC}/apps/dlc). # -a dir : Progress AI archive directory (default: /backup/${qcLOC}db/current). # -d dir : Destination directory (default: /backup/db/${qcLOC}db). # -e email : E-Mail Address to report status to (default: od-dba@qad.com). # -h : Display help. # -s dir : Source director (default: /${qcLOC}/db/${qcLOC}db). # -v : Be verbose and email results, even if no errors are encountered. Disabled by default. # -z : Use named pipe and gzip to compress backup. Disabled by default. # -E environment : Specify enviroment if server has multiple environments. # dblist : Specify which database(s) must be backed up. # # AUTHOR # Written by Jim McConnell # # REVISION HISTORY # 1.0 08/18/08 joz - Initial Creation # 1.2 04/16/09 mcp - Added options -x, -y # 1.3 04/17/09 ddc - changed primary,secondary to previous,oldest # removed time/date stamp from backup name # 1.4 09/29/09 ips - Changed success mail subject to facilitate filtering. # 1.5 07/25/10 ips - Use FIFO pipe # 1.6 11/30/10 mcp - redirect stderr to $LOG # 1.7 06/01/11 ips - CA827797: Add backup/zip of DB log files # 1.8 07/16/12 rjb - Cleanup and remove "Oldest" backup copy # 1.9 08/23/12 rjb - fix issue w ai management # 2.0 05/11/17 j6b - Use standard libraries # Backup also structure-, properties- and keystorefiles # 2.1 10/02/17 j6b - CLDBA-1973 - Support different codepages per db # --------------------------------------------------------------------------- # vim:ts=4 VERS=2.1 # Version of this script. ##----------------## ## Load Libraries ## ##----------------## _me=${0} _libdir=$(dirname ${_me})/lib typeset -i _libcount=0 if [[ -d ${_libdir} ]] then # Load standard libraries for i in $(ls ${_libdir}/*std.LIB 2> /dev/null) do source ${i} _libcount=$((_libcount + 1)) done # Load customized libraries - if applicable for i in $(ls ${_libdir}/*cst.LIB 2> /dev/null) do source ${i} done else echo "Library ${_libdir} not found" exit 99 fi if [[ ${_libcount} = 0 ]] then echo "No libraries loaded from ${LIB}" exit 99 fi if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]] then dispHelp; exit 0 fi ##----------------------## ## Variable definitions ## ##----------------------## ME=$(basename $0 .sh) OUTDIR=/tmp/${ME}.$$ LOCK=/tmp/.${ME}.lk ##-----------## ## Functions ## ##-----------## stamp() { local DIR=${1} local TDSTAMP=`/bin/date +%Y%m%d.%H%M%S` [[ ! -d ${DIR} ]] && /bin/mkdir -p ${DIR} /bin/echo ${TDSTAMP} > ${DIR}/BUNDLE_STAMP } die() { /bin/echo "$1" >&2 exit ${2:-0} } cleanUp() { # Called by signal handler [[ -f ${LOCK} ]] && /bin/rm -f ${LOCK} [[ -d ${OUTDIR} ]] && /bin/rm -rf ${OUTDIR} exit ${1:--1} } function checkUser() { # checkUser will verify the user who's running the script # if the user is 'root' is set the variable qcCMD to execute a sudo # This function will overide the standard checkUser() function! # Only root is allowed to execute this script _user=$(id | cut -d'(' -f2 | cut -d')' -f1) if [[ ${_user} == "root" ]] then if [[ ${_user} == "root" ]] then # Only switch to mfg if user exists grep "mfg" /etc/passwd > /dev/null 2>&1 [[ ${?} == 0 ]] && qcCMD="/usr/bin/sudo -u mfg" else qcCMD="" fi return 0 else return 1 fi export qcCMD } # Signal Handler trap "logMsg ERR 'received signal; cleaning up and exiting'; cleanUp -1" SIGINT SIGTERM # Cleanup output dir & create, as necessary. [[ -d ${OUTDIR} ]] && /bin/rm -f ${OUTDIR} [[ ! -d ${OUTDIR} ]] && /bin/mkdir -p ${OUTDIR} # Parse command line options while getopts "D:a:d:e:h:s:vzE:" opts do case "$opts" in D) DLC=${OPTARG};; a) AIARCDIR=${OPTARG};; d) DEST=${OPTARG};; e) EMAIL=${OPTARG};; h) dispHelp; exit 0;; s) SRC=${OPTARG};; E) QCENV=${OPTARG};; v) VERBOSE=1;; z) COMPRESS=1;; \?) dispHelp; exit 99;; esac done shift $(( $OPTIND - 1 )) SINGLEDB=${@} ##----------------## ## M A I N ## ##----------------## getEnv ${QCENV} checkUser errorHandler ${?} ERR "Only root is allowed to run this script" if [[ -f ${qcLOGFILE} ]] then _cmd="${qcCMD} /bin/mv -f ${qcLOGFILE} ${qcLOGFILE}.$(date '+%d')" eval ${_cmd} fi # Create logfile with right permissions _cmd="${qcCMD} touch ${qcLOGFILE}" eval ${_cmd} logMsg INF "Script starts. (v=${VERS}) (PID=$$)" # Set command line options to default values if not specified. DLC=${DLC:-"/${qcLOC}/apps/dlc"}; export DLC DEST=${DEST:-"/backup/${qcLOC}db"} EMAIL=${EMAIL:-"od-dba@qad.com"} SRC=${SRC:-"/${qcLOC}/db/${qcLOC}db"} QADSCRIPTS=${QADSCRIPTS:-"/${qcLOC}/apps/mfgpro/scripts"} VERBOSE=${VERBOSE:-0} COMPRESS=${COMPRESS:-0} AIARCDIR=${AIARCDIR:-"/backup/${qcLOC}db/current"} if [[ -e "${LOCK}" ]]; then logMsg WRN "Previous backup running; exiting" else /bin/touch "${LOCK}" logMsg INF "Backup started" cd ${OUTDIR} # Create DBLIST if [[ -z ${SINGLEDB} ]] ; then DBLIST=$(/bin/ls -1 ${SRC}/*.db | sed "s/\.db//") else # verify if file exists and build DBLIST for db in ${SINGLEDB}; do if [[ -f ${SRC}/${db}.db ]] ; then DBLIST="${SRC}/${db} ${DBLIST}" else logMsg ERR "${SRC}/${db}.db cannot be found - exit 1" cleanUp 1 fi done fi LOG=${OUTDIR}/mfgbkup.log TDSTAMP=`/bin/date +%Y%m%d.%H%M%S` PREVIOUS=${DEST}/previous OLDEST=${DEST}/oldest stamp ${PREVIOUS} stamp ${OLDEST} # Remove the oldest dir as were not using it. if [[ -d ${OLDEST} ]] ; then /bin/rm -r ${OLDEST} fi # Run previous backups for DB in ${DBLIST} do DBNAME=$(basename ${DB}) LG=${DB}.lg KS=${DB}.ks # CLDBA-1973 - Support different codepages per database chkDbCp ${DB} logMsg INF "Start backup for ${DBNAME} - compression: ${COMPRESS}" if [[ "${COMPRESS}" = 1 ]] ; then FIFO=/tmp/FIFO-${DBNAME} # Remove and recreate FIFO-Pipe file [[ -p $FIFO ]] && rm -f ${FIFO} [[ -f $FIFO ]] && rm -f ${FIFO} mkfifo ${FIFO} # Start backup to FIFO-Pipe file in background if [[ -f ${DB}.lk ]] ; then ${DLC}/bin/probkup online ${DB} ${FIFO} >> ${LOG} 2>> ${LOG} & else ${DLC}/bin/probkup ${DB} ${FIFO} >> ${LOG} 2>> ${LOG} & fi # Get PID of probkup command BKPID=${!} # Start gzip of FIFO-Pipe file gzip -cf < ${FIFO} > ${PREVIOUS}/${DBNAME}.bak.gz & GZPID=${!} # Wait for probkup to finish if [[ ! -z ${BKPID} ]] ; then wait ${BKPID} logMsg INF "\"wait\" completed ... continuing" while : ; do kill -0 ${BKPID} > /dev/null 2>&1 if [[ "x$?" != x0 ]]; then # Backup process has finished break fi if [[ "x${switch}" == x ]]; then logMsg ERR "It looks like the wait command gaveup too early!" switch=set fi sleep 5 done fi #kill ${GZPID} >/dev/null 2>&1 # Delete FIFO-Pipe file [[ -p ${FIFO} ]] && rm -f ${FIFO} [[ -f ${FIFO} ]] && rm -f ${FIFO} else # Start backup to file if [[ -f ${DB}.lk ]] ; then ${DLC}/bin/probkup online ${DB} ${PREVIOUS}/${DBNAME}.bak >> ${LOG} 2>> ${LOG} else ${DLC}/bin/probkup ${DB} ${PREVIOUS}/${DBNAME}.bak >> ${LOG} 2>> ${LOG} fi fi # Backup database related files in ${PREVIOUS}/${DBNAME}_files DBFILES=${PREVIOUS}/${DBNAME}_files [[ ! -d ${DBFILES} ]] && /bin/mkdir -p ${DBFILES} if [[ -f ${LG} ]] ; then logMsg INF "Backup ${DBNAME} logfile" cp -p ${LG} ${DBFILES}/${DBNAME}.lg gzip -f ${DBFILES}/${DBNAME}.lg & fi if [[ -f ${KS} ]] ; then if [[ ! -d ${DBFILES}/.ks ]] ; then /bin/mkdir -p ${DBFILES}/.ks chmod 700 ${DBFILES}/.ks fi logMsg INF "Backup ${DBNAME} keystore" cp -p ${KS} ${DBFILES}/.ks/${DBNAME}.ks fi for i in $(ls ${DB}*.properties 2> /dev/null); do logMsg INF "Backup ${DBNAME} properties file $(basename ${i})" cp -p ${i} ${DBFILES}/$(basename ${i}) done for i in $(ls ${DB}*.pf 2> /dev/null); do logMsg INF "Backup ${DBNAME} parameter file $(basename ${i})" cp -p ${i} ${DBFILES}/$(basename ${i}) done logMsg INF "Create structure file" ${DLC}/bin/prostrct list ${DB} ${DBFILES}/${DBNAME}.st > /dev/null 2>&1 logMsg INF "Backup of ${DBNAME} is finished" done # if $AIARCDIR exists then prune all files over 72 hours if [[ -d ${AIARCDIR} ]] ; then logMsg INF "Deleting old saved AI files" /usr/sbin/tmpwatch --nodirs --mtime 72 ${AIARCDIR} fi logMsg INF "Backup completed" # Report status if cat ${qcLOGFILE} ${LOG} | grep -iE "ERR|error" > /dev/null 2>&1 ; then # Always for errors. /bin/mail -s "WARNING: Database backup for $(hostname):${SRC} had ERRORS @ $(date)" ${EMAIL} <<< "$(cat ${qcLOGFILE} ${LOG})" else # Only if verbose! [ $VERBOSE -eq 1 ] && /bin/mail -s "SUCCESS: Database backup for $(hostname):${SRC} complete @ $(date)" ${EMAIL} <<< "$(cat ${qcLOGFILE} ${LOG})" fi /bin/mv ${LOG} ${PREVIOUS} 2>> ${LOG} cd - > /dev/null /bin/rm -f "${LOCK}" fi logMsg INF "Script ends." # Cleanup output dir cleanUp 0