#!/bin/ksh
#
# hot_bck_1ts.sh
# ==============
#
# This script is provided by Database Specialists, Inc. 
# (http://www.dbspecialists.com) for individual use and not for sale. 
# Database Specialists, Inc. does not warrant the script in any way 
# and will not be responsible for any loss arising out of its use.
#
# Your feedback is welcome! Please send your comments about this script
# to scriptfeedback@dbspecialists.com
#
# This script backs up one tablespace of an Oracle database to a
# backup directory on the filesystem. The script should be called
# by the hot_bck.sh script while the specified database is open. When 
# the SYSTEM tablespace is backed up, the control file and parameter
# file (init.ora or spfile.ora) are also backed up.
# 
# This script is called by the hot_bck.sh script, and should not be 
# called directly.
#
# Usage: hot_bck_1ts.sh -t tablespace -b backup_directory
#
# Version 06-16-2005
#

#
# Parse and validate the command line arguments.
#

TABLESPACE=""
BCK_DIR=""
USAGE="Usage: `basename $0` -t tablespace -b backup_directory"

while getopts :t:b: opt
do
  case "$opt" in
    "t") TABLESPACE="$OPTARG" ;;
    "b") BCK_DIR="$OPTARG"
         if [ ! -d "$BCK_DIR" -o ! -w "$BCK_DIR" ]
         then
	   echo "Backup directory must be a directory writable by you" 1>&2
           exit 1 
         fi ;;
    ":"|"?") echo "$USAGE" 1>&2 ; exit 1 ;;
  esac
done

let i=$#+1
if [ "$i" != "$OPTIND" ]
then
  echo "$USAGE" 1>&2
  exit 1
fi

if [ -z "$TABLESPACE" -o -z "$BCK_DIR" ]
then
  echo "$USAGE" 1>&2
  exit 1
fi

#
# Set up the environment.
#

TMPSQLFILE="/tmp/bck$$.sql"
TMPSHFILE="/tmp/bck$$.sh"
CONTROLFILE="/tmp/control.bck"
CONTROLFILE_TRACE="/tmp/control.trc"

rm -f $TMPSQLFILE $TMPSHFILE $CONTROLFILE $CONTROLFILE_TRACE

#
# If the tablespace to be backed up is the SYSTEM tablespace, then first 
# backup the control file, a trace of the control file, and the parameter
# file.
#

if [ "$TABLESPACE" = "SYSTEM" ]
then

  echo "$ORACLE_LOGIN" > $TMPSQLFILE
  chmod 700 $TMPSQLFILE

  cat <<EOF >> $TMPSQLFILE
WHENEVER SQLERROR EXIT 1
WHENEVER OSERROR  EXIT 2
SET FEEDBACK OFF

ALTER DATABASE BACKUP CONTROLFILE TO '$CONTROLFILE' REUSE;
ALTER DATABASE BACKUP CONTROLFILE TO TRACE;

ALTER SESSION SET /* $UNIQUE_STRING */ sql_trace = TRUE;

EXIT 7
EOF

  sqlplus -s @$TMPSQLFILE < /dev/null 1>&2
  RETCODE="$?"
  rm -f $TMPSQLFILE 

  case "$RETCODE" in
    "7") ;;
    "0") echo "`date +%H:%M:%S`  Unable to access database $ORACLE_SID"  1>&2 
         exit 1 ;;
      *) echo "`date +%H:%M:%S`  SQL*Plus exited with status $RETCODE when backing up controlfile." 1>&2 
         exit 1 ;;
  esac

  ./hot_bck_1f.sh "$CONTROLFILE" "$BCK_DIR"
  RETCODE="$?"
  rm -f "$CONTROLFILE"
  [ "$RETCODE" != "0" ] && exit $RETCODE

  TRACE_FILE="`grep -l $UNIQUE_STRING $UDUMP/* 2> /dev/null | head -1 2> /dev/null`"
  if [ -f "$TRACE_FILE" ]
  then
    LAST_LINE=`grep -n $UNIQUE_STRING "$TRACE_FILE" | head -1 | cut -f 1 -d :`
    ((LAST_LINE=LAST_LINE-3))
    if [ "$LAST_LINE" -gt "20" ]
    then
      head -$LAST_LINE "$TRACE_FILE" > "$CONTROLFILE_TRACE"
      ./hot_bck_1f.sh "$CONTROLFILE_TRACE" "$BCK_DIR"
      RETCODE="$?"
      rm -f "$CONTROLFILE_TRACE"
      [ "$RETCODE" != "0" ] && exit $RETCODE
    fi
  fi

  if [ -f "$PARAMFILE" ]
  then
    ./hot_bck_1f.sh "$PARAMFILE" "$BCK_DIR"
    RETCODE="$?"
    [ "$RETCODE" != "0" ] && exit $RETCODE
  fi
fi

#
# Create a SQL*Plus script to put the tablespace in backup mode
# and prepare a shell script to backup the data files.
#

echo "`date +%H:%M:%S`  Putting tablespace $TABLESPACE in backup mode"

echo "$ORACLE_LOGIN" > $TMPSQLFILE
chmod 700 $TMPSQLFILE

cat <<EOF >> $TMPSQLFILE
WHENEVER SQLERROR EXIT 1
WHENEVER OSERROR  EXIT 2
SET FEEDBACK OFF

DECLARE 
  c NUMBER;
  t VARCHAR2(20);
BEGIN
  SELECT COUNT(*) INTO c
  FROM   SYS.dba_data_files
  WHERE  tablespace_name = '$TABLESPACE';
  IF c < 1 THEN
    RAISE_APPLICATION_ERROR (-20000,'Tablespace $TABLESPACE'
      || ' has no data files');
  END IF;
  SELECT MIN (status) INTO t
  FROM   SYS.dba_data_files
  WHERE  tablespace_name = '$TABLESPACE'
  AND    status != 'AVAILABLE';
  IF t IS NOT NULL THEN
    RAISE_APPLICATION_ERROR (-20000,'Tablespace $TABLESPACE'
      || ' has data files with status "' || t || '"');
  END IF;
  SELECT MAX (LENGTH (file_name)) INTO c
  FROM   SYS.dba_data_files
  WHERE  tablespace_name = '$TABLESPACE';
  IF c > 80 THEN
    RAISE_APPLICATION_ERROR (-20000,'Tablespace $TABLESPACE'
      || ' has data files with names longer than 80 characters');
  END IF;
END;
/

ALTER TABLESPACE "$TABLESPACE" BEGIN BACKUP;

SET TERMOUT   OFF
SET HEADING   OFF
SET TRIMSPOOL ON
SET PAGESIZE  0
SET LINESIZE  200

SPOOL $TMPSHFILE

SELECT   './hot_bck_1f.sh ' || file_name || ' "$BCK_DIR" || exit 1'
FROM     SYS.dba_data_files
WHERE    tablespace_name = '$TABLESPACE'
ORDER BY file_name;

SPOOL OFF
EXIT 7
EOF

#
# Now run the SQL*Plus script.
#

sqlplus -s @$TMPSQLFILE < /dev/null 1>&2
RETCODE="$?"
rm -f $TMPSQLFILE

case "$RETCODE" in
  "7") ;;
  "0") echo "`date +%H:%M:%S`  Unable to access database $ORACLE_SID"  1>&2 
       exit 1 ;;
    *) echo "`date +%H:%M:%S`  SQL*Plus exited with status $RETCODE when beginning tablespace backup." 1>&2 
       rm -f "$TMPSHFILE"
       exit 1 ;;
esac

#
# Run the generated shell script.
#

chmod 700 $TMPSHFILE
$TMPSHFILE
RETCODE="$?"
rm -f $TMPSHFILE

if [ "$RETCODE" != "0" ]
then
  echo "`date +%H:%M:%S`  hot_bck_1f.sh exited with unexpected status $RETCODE." 1>&2
  exit 1
fi

#
# Create a SQL*Plus script to take the tablespace out of backup mode.
#

echo "`date +%H:%M:%S`  Returning tablespace $TABLESPACE to normal mode"

echo "$ORACLE_LOGIN" > $TMPSQLFILE
chmod 700 $TMPSQLFILE

cat <<EOF >> $TMPSQLFILE
WHENEVER SQLERROR EXIT 1
WHENEVER OSERROR  EXIT 2
SET FEEDBACK OFF

ALTER TABLESPACE "$TABLESPACE" END BACKUP;

EXIT 7
EOF

#
# Now run the SQL*Plus script.
#

sqlplus -s @$TMPSQLFILE < /dev/null 1>&2
RETCODE="$?"
rm -f $TMPSQLFILE

case "$RETCODE" in
  "7") ;;
  "0") echo "`date +%H:%M:%S`  Unable to access database $ORACLE_SID"  1>&2 
       exit 1 ;;
    *) echo "`date +%H:%M:%S`  SQL*Plus exited with status $RETCODE when ending tablespace backup." 1>&2 
       exit 1 ;;
esac

#
# Clean up.
#

echo "`date +%H:%M:%S`  Tablespace backup completed successfully"

exit 0


