#!/bin/sh
#
# For debug: add -x on the first line above.
#set -x
#
#------------------------------------------------------------------------------
#                                U&R Consultores                               
#                                www.uyr.com.ar 
# Archive  : saveit
# Creation : 19991016 - Francisco Mancardi - (FM)                      
# Revision : 
#
#
#            20010623  FM
#                      Version 2.4.8
#                      saveit -v gives info about settings
#                      in /etc/saveit.conf (if exists)
#
#
#            20010501  FM
#                      fixed minor bug (log file placement)
#
#            20010428  FM
#                      added new function display_not_empty
#                      added new messages
#                      added variable DISPLAY_CFG_INFO
#                      (see below)
#
#
#            20010426  FM
#                      added messages when using options from
#                      configuration file.
#
#            20010324  FM
#                      added option -v, show version and exit
#
#            20010219  FM
#                      show man page if runned without arg
#
#
#            20010212  FM
#                      Added configuration file
#
#            20010211  FM
#                      fixed problems with: 
#                                          saveit .
#                                          saveit ..
#
#            20010208  FM
#                      Added option -s (suffix_only) 
#                      Solaris version of test doesn't like negative
#                      numbers in -ne.
#
#            20010205  FM
#                      Added detection of readonly backup base dir
#
#            20001105  FM
#                      Adding init_messages
#                      Test the existence of traget to backup
#
#            20000729  FM
#                      Adding functions to improve code.
#                      Adding screen messages.   
#
#            20000710  FM
#                      Added option -c (Comment).
#                      You can add a comment line (why did I save this file)
#                      that will be added to the log file. 
#                            
#                      Added test:
#                      is $# -ne 0, AFTER processing options via getopt ?
#                            
#                      Added version string  
#
#                      Detected problems with 'who am i' and mc
# 
#                      Midnight Commander on Linux 6.0 if logged as root.                  
#
#            20000703    SB  (Sean Boran)
#                            english notes, tested on Sol2.7, OpenBSD 2.6
#                            If file has been save today already, save with time.
#                            (We need more testing after these changes)
#                            To Do: handle devices, links, etc.
#            20000403-01 FM
#            detecto el S.O. para saber que usar como awk
#
#            19991019-02 FM
#            Descubro el siguiente error:
#            save /etc/rc?.d/KAK -> el archivo KAK no existe, luego lo
#                                   que el shell expande y me manda como
#                                   DEST_DIR resulta ser la lista :
#                                   /etc/rc0.d /etc/rc1.d ... /etc/rcS.d 
#                                   Esto causaba la falla de un test.
#            Sin embargo si funcionaba bien:
#            save /etc/rc?.d/README ya que existen tres de estos archivos
#
#            19991019-01 FM
#            - voy a controlar antes de salvar algo, si existe.
#            - hago siempre append en el archivo de lista de operaciones
#            19991017 - FM 
#            1) agrego como argumeno opcional el directorio de base donde 
#               hacer el backup.
#            2) Se puede indicar el pathname de lo que se desea salvar
#            3) Se puede indicar que salve un directorio completo.
#               Atencion!: 
#                          en este caso se lleva TODOS los subdirectorios
#                          que tenga dentro. 
#------------------------------------------------------------------------------
#
#
# ********************************************************************************
# Configurable options
# *****************************************************************************
# 2001.04.28
# set it to 0 if you don't want the new on screen messages
# 1 => display.
#
DISPLAY_CFG_INFO=1; export DISPLAY_CFG_INFO

# Configuration file
SAVEIT_CFG="/etc/saveit.conf"; export SAVEIT_CFG

# Directory under which all backups will be stored
DIR_ROOT_BACKUP="/Backup.d"; export DIR_ROOT_BACKUP

#
FECHAHORA=`date '+%Y%m%d-%H:%M'`; export FECHAHORA
FECHA=`date '+%Y%m%d'`;          export FECHA
DD_MM_AAAA=`date '+%d-%m-%Y'`;   export DD_MM_AAAA
HH_MM=`date '+%H:%M'`;           export HH_MM

# Subdirectory format YYYYMMDD-HH:MM
TAG_BACKUP_PARANOIC=${FECHAHORA}; export TAG_BACKUP_PARANOIC

# format YYYYMMDD
TAG_BACKUP=$FECHA;                export TAG_BACKUP

# Prefix for log file in backup directory
LOG_PREFIX="log";              export LOG_PREFIX
# ***** End of configurable options *******************************************


WITH_DEBUG=0 #=> debug function do nothing
#WITH_DEBUG=1 #=> debug function print arg on screen
export WITH_DEBUG


# version number
VERSION=2.4.8; export VERSION

# general constants
CURRDIR=`pwd`;                   export CURRDIR
HOST=`hostname`;                 export HOST
PROGRAM_NAME=`basename $0`;      export PROGRAM_NAME

# Status codes
STAT_OK=0; export STAT_OK

STAT_KO=99; export STAT_KO
STAT_CONTINUE=98; export STAT_CONTINUE

# 20010324
STAT_VERSION_NUMBER_ASKED=97; export STAT_VERSION_NUMBER_ASKED


# Error codes
ERROR_CANT_CREATE_DIR=3; export ERROR_CANT_CREATE_DIR
ERROR_CANT_WRITE_ON=4; export ERROR_CANT_WRITE_ON 
ERROR_MAKE_COPY=8; export ERROR_MAKE_COPY



# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#                           Begin Auxiliary Functions
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#
# 
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# show_version_and_cfg 
# shows versioninfo plus settings in the std config file
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
show_version_and_cfg()
{

PROGNAME=`basename $0` 
printf "$PROGNAME - $MSG_VERSION $VERSION\n"

# -----------------------------------------------
# 2001.06.23
# show contents of /etc/saveit.conf if exists
if [ $cfg_exists -eq 1 ]
then
   printf "$MSG_STD_CFG_FILE_IS\n"

   # ------------------------------------------------------------
   if [ ! -z "$sv_save_plain" ]; then
      if [ $sv_save_plain = "1" ]; then
          Msg_opt1="$MSG_SAVE_PLAIN (option: -$OPT_SAVE_PLAIN)"
          _opt1=1
          msg_from_cfg=1
      fi
   fi
   # ------------------------------------------------------------

   # ------------------------------------------------------------
   if [ ! -z "$sv_save_over" ]; then
      if [ $sv_save_over = "1" ]; then
          Msg_opt2="$MSG_SAVE_OVER (option: -$OPT_SAVE_OVER)"
          _opt2=1
          msg_from_cfg=1
      fi
   fi
   # ------------------------------------------------------------

   # ------------------------------------------------------------
   if [ ! -z "$sv_save_inplace" ]; then
      if [ $sv_save_inplace = "1" ]; then
          Msg_opt3="$MSG_SAVE_INPLACE (option: -$OPT_SAVE_INPLACE)"
          _opt3=1
          msg_from_cfg=1
      fi
   fi
   # ------------------------------------------------------------

   # ------------------------------------------------------------
   if [ ! -z "$sv_suffix_only" ];then
      if [  $sv_suffix_only = "1" ]; then
          Msg_opt4="$MSG_SUFFIX_ONLY (option: -$OPT_SUFFIX_ONLY)"
          _opt4=1
          msg_from_cfg=1
      fi
   fi
   # ------------------------------------------------------------


   # ------------------------------------------------------------
   if [ ! -z "$sv_base_dir" ]; then
          # 2001.04.28
          Msg_opt5="$MSG_SAVE_DIR : $sv_base_dir (option: -$OPT_SAVE_DIR)"
          _opt5=1
          msg_from_cfg=1
   fi
   # ------------------------------------------------------------

   if [ $msg_from_cfg -eq 1 ]
   then
       printf "$MSG_CFG_FILE_SAYS\n"
       display_not_empty 
       printf "\n"
   fi

fi
# -----------------------------------------------
}


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# displat message number, if message is not empty
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
display_not_empty()
{

if [ $_opt1 -eq 1 ]
then
       echo "$Msg_opt1"
fi


if [ $_opt2 -eq 1 ]
then
       echo "$Msg_opt2"
fi


if [ $_opt3 -eq 1 ]
then
       echo "$Msg_opt3"
fi


if [ $_opt4 -eq 1 ]
then
       echo "$Msg_opt4"
fi



if [ $_opt5 -eq 1 ]
then
       echo "$Msg_opt5"
fi




}

# ........................................................................
# set the text of the messages
# ........................................................................
init_messages()
{

# Messages

# 2001.06.23
MSG_STD_CFG_FILE_IS="The default the configuration file exists: $SAVEIT_CFG"
export MSG_STD_CFG_FILE_IS


# 2001.04.28
MSG_YOUR_CFG_FILE_IS="You are using the configuration file: $SAVEIT_CFG"
export MSG_YOUR_CFG_FILE_IS

MSG_CFG_FILE_SAYS="The following options are set in $SAVEIT_CFG:"
export MSG_CFG_FILE_SAYS

# 20010324 - improved
MSG_SORRY="sorry no help - can't find `basename $0` man page"; export MSG_SORRY

# 20010324
MSG_VERSION="Version:"; export MSG_VERSION

MSG_NOT_FOUND="File/Dir doesn't exists - no backup made";
export MSG_NOT_FOUND

MSG_CANT_CREATE_DIR="Can't create directory: ";  export MSG_CANT_CREATE_DIR

MSG_CANT_COPY="Can't copy: ";           export MSG_CANT_COPY

MSG_CANT_WRITE_ON="Can't write on: (is read only ?)"
export MSG_CANT_WRITE_ON


MSG_COPYING="copying ";                 export MSG_COPYING
MSG_COPYING_FILE="copying file ";       export MSG_COPYING_FILE
MSG_COPYING_DIR="copying directory ";   export MSG_COPYING_DIR

MSG_I_D_NOT="options -i and -d not allowed together"; export MSG_I_D_NOT
MSG_I_O_NOT="options -i and -o not allowed together"; export MSG_I_D_NOT
MSG_NOT_TOGETHER="options not allowed together: "; export MSG_NOT_TOGETHER

MSG_DIR_LIST="Directory listing: ";     export MSG_DIR_LIST


}
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
debug()
{
if [ $WITH_DEBUG -eq 1 ]; then
    echo $1
fi
}

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Function: usage
#           shows usage instructions on screen
#
# Arguments: optional message
#
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
usage()
{

#temp_name=`basename $0`
#my_temp_file_in="/tmp/in-"$temp_name".$$"
#my_temp_file_out="/tmp/out-"$temp_name".$$"

#debug "my_temp_file_in $my_temp_file_in"
#debug "my_temp_file_out $my_temp_file_out"


#VERSION=2.4.4a

#cat >> $my_temp_file_in << EOF
# ------------------------------- POD START ------------------------------------
#
#=head1 NAME
#
#saveit  - simple backup utility  
#
#=head1 SYNOPSIS
#
#saveit [OPTION]... FILE...
#
#=head1 DESCRIPTION
#
# This command allows the creation of backup copies of files or 
# directories with the following advantages:
#
# * single repository (a common directory) for all the saved objects.
#
# * a log file with a listing of saved objects is written in the
#   the single repository.   
#
# * simple versioning scheme, using the date and time as a suffix
#   to the target object name.
#
#=head1 OPTIONS
#
#C<-a> plain
#   The file/directory to be saved is copied to
#   the Base Backup Directory  without creating the 
#   standard  YYYYMMDD directory and without creating 
#   the target fullpath. If target exists, a the target
#   is created and  renamed  appending C<.HH:MM>
#   to the original name.
#   Not allowed with options C<-s, -i>.
#
#C<-c> comments to write into the log file
#
#C<-d> Base Backup Directory
#   Is used instead of the default directory /Backup.d
#   Not allowed with option C<-i>.
#
#C<-i> backup in place
#   creates a file/directory copy in the directory where 
#   you are running saveit.  
#   The name of the saved file/directory is created 
#   appending C<.YYYYMMDD-HH:MM> to the original name.
#   Not allowed with option C<-d, -a, -s, -o>.
#
#C<-o> overwrite
#   The file/directory to be saved is copied to the 
#   Backup Directory without appending .HH:MM to the 
#   original name, then if the file exists in 
#   the backup area it will be overwritten.
#   Not allowed with option C<-i>.
#
#C<-s> suffix only
#   The file/directory to be saved is copied to the 
#   Base Backup Directory without creating the standard 
#   YYYYMMDD directory, always adding the suffix
#   C<.YYYYMMDD-HH:MM> to the original name.
#   Not allowed with options C<-a, -i, -o>.
#
#C<-v> print version number and exit.
#
#=cut
#
#=head1 EXAMPLES
#
#=head2 Save /etc/hosts in the default base backup directory
#
# [root@spock]# saveit /etc/hosts
# copying /etc/hosts ===> /Backup.d/20010221/etc/hosts
#
# In /Backup.d you will find the log file log-20010221
#
# [root@spock]# cat /Backup.d/log-20010221
# --------------------------------------------------------------
# Backup base directory /Backup.d
# Backup requested by   localhost.localdomain!root 
# Date (dd/mm/aaaa)     21-02-2001     Time 07:14
# -rw-r--r-- root/root /etc/hosts 
#
#=head2 Save using the suffix only option.
#
# [root@spocl]/saveit -s /etc/rmt  
# copying /etc/rmt ===> /Backup.d/etc/rmt.20010221-07:40
# [root@spock]# cat /Backup.d/log-20010221
# --------------------------------------------------------------
# Backup base directory /Backup.d
# Backup requested by   localhost.localdomain!root 
# Date (dd/mm/aaaa)     21-02-2001     Time 07:14
# -rw-r--r-- root/root /etc/hosts 
# --------------------------------------------------------------
# Backup base directory /Backup.d
# Backup requested by   localhost.localdomain!root 
# Date (dd/mm/aaaa)     21-02-2001     Time 07:40
# lrwxrwxrwx root/root /etc/rmt -> ../sbin/rmt
#
# The last line in the log file shows that the file we have
# saved is a link.
# Take a look to /Backup.d
#
# /Backup.d:
# drwxr-xr-x   3 root     root         1024 Feb 21 07:14 20010221
# drwxr-xr-x   2 root     root         1024 Feb 21 07:40 etc
# -rw-r--r--   1 root     root          464 Feb 21 07:40 log-20010221
#
# /Backup.d/20010221/etc/hosts
# /Backup.d/etc/rmt.20010221-07:40
#
# If we have requested a saveit without options, the file /etc/rmt 
# would be copied under the 20010221 subdirectory like /etc/hosts,
# but we asked suffix only, then the directory indicated the
# date is omited and the timestamp is added to the file.
# New saveit operations on /etc/hosts during 20010221 will be
# saved in  /Backup.d/20010221/etc/ directory , and the new
# versions will be identified adding the timestamp suffix.
#
#
#=head2 Save the file /SysAdmin.d/mypod in place
#
# [root@spock]#cd /SysAdmin.d/mypod
# [root@spock]#saveit -i mypod
# copying file /SysAdmin.d/mypod ===> /SysAdmin.d/mypod.20010221-07:28
# [root@spock]#ls -la log-*
# -rw-r--r--   1 root     root          259 Feb 21 07:28 log-20010221
#
#
#=head2 Another save in place example
#
# You want save in the current directory the file  ../miman.tar.gz
#
# [root@spock]# pwd
# [root@spock]# /SysAdmin.d/work
# [root@spock]# saveit -i ../miman.tar.gz
# copying /SysAdmin.d/miman.tar.gz ===> /SysAdmin.d/work/miman.tar.gz
#
#=cut
#
#=head1 FILES
#
#=head2 Configuration File
#
#You can set your preferences in the file F</etc/saveit.conf>.
# The precedence in option analysis is:
#
# If an option is set on the command line this is the value used.
#
# If an option is NOT set on the command line and is set in the
#    configuration file this value is used.
#
# If an option is NOT set either on the command line or in the
#    configuration file, the default built-in value is used. 
#
#=head2 Example of F</etc/saveit.conf>
#
# #
# # saveit configuration file
# # (/etc/saveit.conf)
# # 
# #
# # All lines beginning with '#' are ignored
# #
# # Where should be store backedup files?
# #sv_base_dir=; export sv_base_dir
# #
# # Boolean Options: 1 -> yes , 0 -> no
# # Suffix only:
# # append a date suffix to the backup file, but
# # do not create a subdirectory with today's date.
# #sv_suffix_only=1;     export sv_suffix_only
# #
# # Save all files in the current dir?
# #sv_save_inplace=1;   export sv_save_in_place
# #
# # Save plain ?
# #sv_save_plain=1;  export sv_save_plain
# #
# # Save with overwrite ?
# #sv_save_over=1;   export sv_save_over
#
#
#=head2 Log file
#
#In the Base Backup Directory used, a log file will be created
#if not found, or information will be appended into it.
#The file is named F<log-YYYYMMDD>.
#Every successful operation will write  the following information:
#
#The backup base directory used, it can change between saves.
#The Real User Name Who requested the save.
#Date and time
#A listing of all files saved, showing file permissions,
#owner/group and name.
#
#=head1 NOTES 
#
#=head2 Base backup directory ownership and permissions.
#
#   The standard Base Backup Directoy (F</Backup.d>) is owned by
#   the user that runs for the very first time saveit on the machine
#   and creted with the following permissions: drwxr-xr-x
#   Then if root is the "first user" and a non-privileged user
#   tries to save a file in the standard directory the operation
#   will fail.
#
#   If a different Base Backup Directory is choosen, and doesn't
#   exist, it will be created and owned by the user that requested
#   the operations.
#
#=head2 Relative path 
#
#   The only relative path combinations managed properly are C<../ and ./>.
#   Combinations like  ../xx/.., etc are not supported.
#
#=head1 AUTHOR
#
# Francisco Mancardi, U&R Consultores - Argentina -
# (fman@uyr.com.ar) , (www.uyr.com.ar)
#
#=head1 ACKNOWLEDGMENTS
#
# Testing and suggestions: Sean Boran, (sean@boran.com) Boran Consulting
#
#=cut
#




# ------------------------------- POD END --------------------------------------
#EOF

# delete the # from column 1
#sed 's/^#//g' $my_temp_file_in > $my_temp_file_out
#cat $my_temp_file_in | sed 's/^#//g' > $my_temp_file_out

#./pod2text $my_temp_file_out 
#rm $my_temp_file_out 
#rm $my_temp_file_in

man saveit 2>/dev/null
if [ $? -eq 1 ]
then
   echo $MSG_SORRY
fi
}
# ........................................................................


# ........................................................................
# makes the copy
# ........................................................................
# 20010207 - the Solaris version of test doesnt like negative numbers
#
# -----------------------------------------------------------------------
# Arguments:
#           SOURCE_FILENAME
#           ABS_SOURCE_PATHNAME
#           DEST_DIR
#
#
#
make_copy()
{

# get arguments
my_sf=$1
my_asp=$2
my_ddir=$3

# -----------------------------------------------------------------------
debug "make_copy $COUNT"
debug "my_sf, my_asp, my_ddir"
debug "$my_sf, $my_asp, $my_ddir"
# -----------------------------------------------------------------------

# -----------------------------------------------------------------------
# source exists ?
if [ -f $my_asp -o -d $my_asp ] 
then
   cmd_status=0
else
   cmd_status=$ERROR_MAKE_COPY
   return $cmd_status
fi
# -----------------------------------------------------------------------

DEST_FILE=$my_ddir/$my_sf

if test $save_over -eq 0
then
   # standard way, add the sufix
   DEST_FILE=$my_ddir/$my_sf.$SUFFIX
fi

# ****************************************************
# strip multiples /
#'s-/*/-/-g'
my_dir_destino=`echo $my_ddir | sed 's-/*/-/-g'`
my_target_file=`echo $my_sf | sed 's-/*/-/-g'`
my_tfile=`echo $my_asp | sed 's-/*/-/-g'`
my_dest_file=`echo $DEST_FILE | sed 's-/*/-/-g'`
my_test_arg=$my_ddir/$my_sf
my_test_arg=`echo $my_test_arg | sed 's-/*/-/-g'`
# ****************************************************


## Sean
## If target exists already, save to target.SUFFIX
if [ -f $my_test_arg ]; then

   # target is a FILE and exists, so add time to target
   echo $MSG_COPYING_FILE "$my_tfile ===> $my_dest_file"

   cp -Rp $my_tfile $my_dest_file 2>/dev/null

elif [ -d $my_test_arg ]; then
   # target is a Directory and exists, so add time to target
   echo $MSG_COPYING_DIR "$my_tfile ===> $my_dest_file"

   cp -Rp $my_tfile $my_dest_file 2>/dev/null

elif [ -f $my_tfile -a -f $my_test_arg ]; then

   # source is a directory/file construction and target already exists
   echo $MSG_COPYING_FILE "$my_tfile ===> $my_dest_file"

   cp -Rp $my_tfile $my_dest_file 2>/dev/null

elif [ $suffix_only -eq 1 ]; then

   # in this case always use prefix
   echo $MSG_COPYING "$my_tfile ===> $my_dest_file"
   cp -Rp $my_tfile $my_dest_file 2>/dev/null

else
    #if [ $my_sf = "." -o $my_sf = ".." ];then
   echo $MSG_COPYING "$my_tfile ===> $my_dir_destino/$my_target_file"

   # esta bien que el echo diga una cosa y el comando sea otro, por
   # problemas de copia con directorio ???
   #
   debug "cp -Rp $my_tfile $my_dir_destino 2>/dev/null"
   cp -Rp $my_tfile $my_dir_destino 2>/dev/null
fi

# we are returning cp status
cmd_status=$?
return $cmd_status
}
# ........................................................................

#
# 20001105
ls_2_log()
{
#get argument
TFILE=$1

`ls -la $TFILE | $AWKNAME  'BEGIN {RIGHTS=1; USER=3; GROUP=4; F_NAME=9; 
                                                  ARROW=10; LINK=11} 
{

if( ($1 != "total") && (length($1) != 0) && 
    ($F_NAME != ".") && ($F_NAME != "..") ){

  if( index($1,"l") != 0 ){
    printf "%s %s/%s %s %s %s\n", $RIGHTS, $USER, $GROUP, 
                                     $F_NAME, $ARROW, $LINK
  }
  else {
    printf "%s %s/%s %s \n", $RIGHTS, $USER, $GROUP, $F_NAME
  }
}
}' >> $LISTA`

}
# ........................................................................


# ........................................................................
# list_2_log:
# make a listing resembling tar -t
# ........................................................................
list_2_log()
{
#get argument
TFILE=$1

`ls -lAR $TFILE | $AWKNAME -v BASE_DIR=$TFILE 'BEGIN {RIGHTS=1; USER=3; GROUP=4; F_NAME=9; 
                                                  ARROW=10; LINK=11} 
{
if (NR == 1 ) {
   prefix=BASE_DIR
}

if( ($1 != "total") && (length($1) != 0) && 
    ($F_NAME != ".") && ($F_NAME != "..") ){

  if( index($1,":") != 0 ){
      no_colon=substr($1,1,(length($1)-1))
      prefix=""
      prefix=no_colon
  }
  else if( index($1,"l") != 0 ){
    printf "%s %s/%s %s/%s %s %s\n", $RIGHTS, $USER, $GROUP, prefix, 
                                     $F_NAME, $ARROW, $LINK
  }
  else if( index($1,"d") != 0 ){
    # Add final / to mark directory
    ### printf "%s/%s/\n", prefix, $F_NAME
  }
  else {
    printf "%s %s/%s %s/%s \n", $RIGHTS, $USER, $GROUP, prefix, $F_NAME
  }
}
}' >> $LISTA`

}
# ........................................................................


# ........................................................................
# strip ./ or ../ if the string begins with one of them.
# ........................................................................
strip_dot_slash()
{
_WHERE=$1

RET_dot_slash=`echo $_WHERE | 
               $AWKNAME '{ sub("^\./","",$0); sub("^\.\./","",$0); printf "%s", $0}'`

export RET_dot_slash 
}
# ........................................................................

# ........................................................................
# transform // in /
# ........................................................................
one_slash()
{

RET_one_slash=`echo $_WHERE | 
               $AWKNAME '{ sub("//","/",$0); printf "%s", $0}'`

export RET_one_slash 
}
# ........................................................................





# ........................................................................
my_dirname ()
{
_IN_ARG=`echo $1 | sed 's-/$--'`

RET_my_dirname=` echo $_IN_ARG |
                $AWKNAME 'BEGIN { FS="/" }
                { if( NF == 1 ){ 
                      if ( $1 == ".." ) { print ".." } else { print "." }
                  }
                  else if( NF == 2 ){ if( $1=="") { printf "/" } else { printf"%s",$1 }
                  }
                  else { for(idx=1; idx < (NF-1); idx++){ printf"%s/",$idx }
                         printf"%s", $(NF-1)
                  }
                }'`
export RET_my_dirname 
}
# ........................................................................

# ........................................................................
my_basename()
{
# suppress final / if exists 
_IN_ARG=`echo $1 | sed 's-/$--'`

RET_my_basename=`echo $_IN_ARG | $AWKNAME 'BEGIN {FS="/" } {print $NF}'`

export RET_my_basename 
}
# ........................................................................

# ........................................................................
#
# returns: .   if dir= .   or starts with ./
#          ..  if dir= ..  or starts with ../ 
#
is_relative()
{
#
#echo $1 > /tmp/saveit.2222

RET_is_relative=`echo $1 | $AWKNAME '{ if( index($1,"./")== 1 || $1==".") {
                                print "."
                           }
                           else if( index($1,"../") == 1 || $1=="..") {
                                print ".."
                           }
                           else {
                                print "*"
                           }
                           }'`

export RET_is_relative 
}
# ........................................................................

# ........................................................................
# put log header
# ........................................................................
put_log_header()
{

cat >> $LISTA << EOF
--------------------------------------------------------------
Backup base directory $DIR_ROOT_BACKUP
Backup requested by   $LOGIN_ID 
Date (dd/mm/aaaa)     $DD_MM_AAAA     Time $HH_MM
EOF

if [ $HAVE_COMMENT -eq 1 ] 
then
   echo "   "          >> $LISTA
   echo "Details               "$COMMENT_LINE  >> $LISTA
fi
# ------------------------------------------------------------
}

# ........................................................................
firstdir ()
{
# no que ni lo que hice !!!
_IN_ARG=`echo $1 | sed 's-/$--'`

RET_firstdir=` echo $_IN_ARG | $AWKNAME 'BEGIN {FS="/"} {printf"%s", $2}'`
export RET_firstdir 
}
# ........................................................................




# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#                            End  Auxiliary Functions
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#                              MAIN BODY
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
init_messages

# ------------------------------------------------------------------ 
# 2001.04.28
# added to handle new on screen info about the options set in
# the configuration file
#
Msg_opt1=""; export Msg_opt1
Msg_opt2=""; export Msg_opt2
Msg_opt3=""; export Msg_opt3
Msg_opt4=""; export Msg_opt4
Msg_opt5=""; export Msg_opt5
_opt1=0; export _opt1
_opt2=0; export _opt2
_opt3=0; export _opt3
_opt4=0; export _opt4
_opt5=0; export _opt5
msg_from_cfg=0
# ------------------------------------------------------------------ 

# ......................................
# read configuration file, is exists.
cfg_exists=0
if [ -f $SAVEIT_CFG ]
then
    . $SAVEIT_CFG
    cfg_exists=1
fi
# ......................................


# Detect os and set awk path accordingly
# 20000710 - Detected problems with 'who am i' and mc 
#            Midnight Commander on Linux 6.0 if logged 
#            as root.
#
if [ -z "$MC_CONTROL_FILE" ]
then
   # no mc
   WHOAMI="who am i" 
else
   WHOAMI="whoami" 
fi

OSNAME=`uname -s`;export OSNAME
if [ $OSNAME = "Linux" ] ; then
   AWKNAME="awk";export AWKNAME;

elif test $OSNAME = "SunOS" ; then 
   AWKNAME="nawk";export AWKNAME;

   if [ -z "$MC_CONTROL_FILE" ]
   then
     # no mc
     WHOAMI="/bin/who am i" 
   else
     WHOAMI="/usr/ucb/whoami" 
   fi
else
   # hope for the best
   AWKNAME="awk";export AWKNAME;
fi

COMMENT_LINE=""
HAVE_COMMENT=0
LOGIN_ID=`$WHOAMI | $AWKNAME '{ print $1 }'`; export LOGIN_ID 

# permisos
RWXR_XR_X=0755; export RWXR_XR_X

# suffix to add to identify different versions of the same file
SUFFIX=$HH_MM; export SUFFIX

# Control de argumentos.
# Si la cantidad es 0 => mostrar usage()
#
QTA_ARG=$#; export QTA_ARG
#
# -ne : solo para enteros
#
if test $QTA_ARG -eq 0 
then 
#
  usage " "
  exit 1
fi

# ----------------------------------------------------------------------
# parse command line
OPT_SAVE_OVER="o"
MSG_SAVE_OVER="save overwritting"

OPT_SAVE_PLAIN="a"
MSG_SAVE_PLAIN="save plain"

OPT_SAVE_INPLACE="i"
MSG_SAVE_INPLACE="save in place"

OPT_SAVE_DIR="d"
MSG_SAVE_DIR="default backup dir"

OPT_SUFFIX_ONLY="s"
MSG_SUFFIX_ONLY="suffix only"


OPT_COMMENT="c"
OPT_PRINT_VERSION="v"


#OPCIONES="d:c:aios";export OPCIONES
OP1=$OPT_SAVE_DIR":"$OPT_COMMENT":"$OPT_SAVE_INPLACE
OP2=$OPT_SAVE_OVER""$OPT_SAVE_PLAIN""$OPT_SUFFIX_ONLY

# 20010324
OP3=$OPT_PRINT_VERSION
OPCIONES=$OP1""$OP2""$OP3;export OPCIONES

# init
save_plain=0   ; export save_plain
save_inplace=0 ; export save_inplace
save_dir=0     ; export save_dir
save_over=0    ; export save_over
suffix_only=0  ; export suffix_only 

# 2001.04.28
# If the options are set if the configuration file
# we proceed in a different way, regarding mutual
# exclusion.
#
# We give priority to the command line options.
#
save_dir_in_cfg=0     ; export save_dir_in_cfg
suffix_only_in_cfg=0     ; export save_dir_in_cfg



while getopts $OPCIONES opt
do
  case $opt in

       v) show_version_and_cfg

          exit  $STAT_VERSION_NUMBER_ASKED
          ;;

       a) save_plain=1
          ;;

       i) save_inplace=1
          SUFFIX=$FECHAHORA; export SUFFIX
          ;;

       o) save_over=1
          ;;

       d) save_dir=1
          USER_ROOT_BACKUP=$OPTARG
          ;;

       c) COMMENT_LINE=$OPTARG
          HAVE_COMMENT=1
          ;;

       s) suffix_only=1
          SUFFIX=$FECHAHORA; export SUFFIX
          ;;

       # aqui llega si se le pasa una opcion que no esta declarada
       \?)      #sleep 2 
                usage " "
                exit 2;;
  esac
done


# 2001.04.28
if [ $cfg_exists -eq 1 ]
then
   printf "$MSG_YOUR_CFG_FILE_IS\n"
fi


# **************************************************************************
# if option not set, look for value set by the configuration file.
#
# **************************************************************************

 
 
if [ $save_plain -eq 0 ]; then
   if [ ! -z "$sv_save_plain" ]; then
      if [ $sv_save_plain = "1" ]; then
          save_plain=1
          # 2001.04.26
          Msg_opt1="$MSG_SAVE_PLAIN (option: -$OPT_SAVE_PLAIN)"
          _opt1=1
          msg_from_cfg=1

      fi
   fi
fi

if [ $save_over -eq 0 ]; then
   if [ ! -z "$sv_save_over" ]; then
      if [ $sv_save_over = "1" ]; then
          save_over=1
          Msg_opt2="$MSG_SAVE_OVER (option: -$OPT_SAVE_OVER)"
          _opt2=1
          msg_from_cfg=1
      fi
   fi
fi

if [ $save_inplace -eq 0 ]; then
   if [ ! -z "$sv_save_inplace" ]; then
      if [ $sv_save_inplace = "1" ]; then
          save_inplace=1
          SUFFIX=$FECHAHORA; export SUFFIX
          Msg_opt3="$MSG_SAVE_INPLACE (option: -$OPT_SAVE_INPLACE)"
          _opt3=1
          msg_from_cfg=1
      fi
   fi
fi


if [ $suffix_only -eq 0 ]; then
   if [ ! -z "$sv_suffix_only" ];then
      if [  $sv_suffix_only = "1" ]; then
          suffix_only=1
          SUFFIX=$FECHAHORA; export SUFFIX

          # 2001.04.28
          suffix_only_in_cfg=1
          Msg_opt4="$MSG_SUFFIX_ONLY (option: -$OPT_SUFFIX_ONLY)"
          _opt4=1
          msg_from_cfg=1
      fi
   fi
fi


if [ $save_dir -eq 0 ]; then
   if [ ! -z "$sv_base_dir" ]; then
          save_dir=1
          USER_ROOT_BACKUP=$sv_base_dir

          # 2001.04.28
          save_dir_in_cfg=1
          Msg_opt5="$MSG_SAVE_DIR : $sv_base_dir (option: -$OPT_SAVE_DIR)"
          _opt5=1
          msg_from_cfg=1
   fi
fi
# **************************************************************************

# 2001.04.28
# --------------------------------------------
# display options set in the config file
# --------------------------------------------
if [ $DISPLAY_CFG_INFO -eq 1 ]
then
   if [ $msg_from_cfg -eq 1 ]
   then
       printf "$MSG_CFG_FILE_SAYS\n"
       display_not_empty 
       printf "\n"
   fi
fi
# --------------------------------------------



# --------------------------------------------
# test options not allowed togheter
# 20000812
if test $save_inplace -eq 1
then

  DIR_ROOT_BACKUP=$CURRDIR

  if test $save_over -eq 1
  then
     echo "$MSG_NOT_TOGETHER $OPT_SAVE_INPLACE and $OPT_SAVE_OVER"
     exit
  fi

  if test $save_dir -eq 1
  then

     # 2001.04.28
     if [ $save_dir_in_cfg -eq 0 ]
     then
         echo "$MSG_NOT_TOGETHER $OPT_SAVE_INPLACE and $OPT_SAVE_DIR"
         exit
     fi
  fi

  if test $save_plain -eq 1
  then
     echo "$MSG_NOT_TOGETHER $OPT_SAVE_INPLACE and $OPT_SAVE_PLAIN"
     exit
  fi

  if test $suffix_only -eq 1
  then

     # 2001.04.28
     if [ $suffix_only_in_cfg -eq 0 ]
     then
        echo "$MSG_NOT_TOGETHER $OPT_SAVE_INPLACE and $OPT_SUFFIX_ONLY"
        exit
     fi
  fi

fi


if test $save_plain -eq 1; then
   if test $suffix_only -eq 1; then
      echo "$MSG_NOT_TOGETHER $OPT_SAVE_PLAIN and $OPT_SUFFIX_ONLY"
      exit
   fi
fi


if test $suffix_only -eq 1; then
   if test $save_over -eq 1; then
      echo "$MSG_NOT_TOGETHER $OPT_SAVE_OVER and $OPT_SUFFIX_ONLY"
      exit
   fi
fi


# 2001.05.01
# To solve the situation:
# user request save in place, but in cfg file there is a different
# default backup dir
#
# If not fixed the log file is sent to the directory indicated
# by cfg file, instead of dir where the saved file is.
#
if test $save_dir -eq 1
then
  # 2001.05.01
  if test $save_inplace -eq 0
  then
     DIR_ROOT_BACKUP=${USER_ROOT_BACKUP}
  fi
fi
# --------------------------------------------



# Archivo donde se deja la lista de los archivos que se resguardaron.
ARCHBKPED=$LOG_PREFIX"-"$TAG_BACKUP; export ARCHBKPED

# con esto va a parar a $1 el primer argumento luego de todas
# las opciones
#
shift `expr $OPTIND - 1`

# 20000710 - FM
# After processing all options, is there an argument ?
# if not -> K.O.

if test $# -eq 0 
then 
#
  usage " "
  exit 1
fi


# ----------------------------------------------------------------------
# me fijo si el directorio root de backup es relativo o absoluto.
# si es relativo trato de transformarlo en absoluto 
#
#
# returns: .   if dir= .   or starts with ./
#          ..  if dir= ..  or starts with ../ 
#
is_relative $DIR_ROOT_BACKUP

# throw away ./ and ../ if present
strip_dot_slash $DIR_ROOT_BACKUP 

case $RET_is_relative in

     .)DIR_ROOT_BACKUP=$CURRDIR"/"$RET_dot_slash;;

     ..) cd ..; DIR_ROOT_BACKUP=`pwd`"/"$RET_dot_slash; cd $CURRDIR;;

     *);;
esac
# ----------------------------------------------------------------------


# ----------------------------------------------------------------------
# Ahora tengo que tratar de crear el directorio donde hacer el resguardo
# Controlo si tengo exito
#
# N.B.!!: el uso de mkdir -p tiene las siguienets ventajas:
#         1) crea directorios padres si no existen
#         2) no grita si el directorio que quiero crear existe.
#
# Al resguardar creo toda la estructura de directorio hasta llegar al
# directorio donde reside el archivo a resguardar.
# DEBO IR HASTA DONDE ESTA EL ARCHIVO DESEADO ya que uso pwd para saber
# donde estoy.
#

DIR_BASE_BACKUP=$DIR_ROOT_BACKUP

if test $save_inplace -eq 1; then
    DIR_BASE_BACKUP=$CURRDIR

elif test $save_plain -eq 1; then
    DIR_BASE_BACKUP=$DIR_ROOT_BACKUP

elif test $suffix_only -eq 1; then
    DIR_BASE_BACKUP=$DIR_ROOT_BACKUP

else 
    DIR_BASE_BACKUP=$DIR_ROOT_BACKUP"/"$TAG_BACKUP
fi
export DIR_BASE_BACKUP


# Por ahora todo O.K.
#
# Armo el nombre del archivo donde dejar la lista de los que salve
#
LISTA=$DIR_ROOT_BACKUP"/"$ARCHBKPED; export LISTA

# check for backup dir existence and create it, if necessary
if [ ! -d ${DIR_ROOT_BACKUP} ]; then
   mkdir -m $RWXR_XR_X -p ${DIR_ROOT_BACKUP} 2> /dev/null

   # test the result of mkdir
   if [ $? -ne 0 ];then
      echo "757 - $MSG_CANT_CREATE_DIR $DIR_ROOT_BACKUP"
      exit $ERROR_CANT_CREATE_DIR
   fi

else
   # the directory exists.
   # test if you are trying to write in a read-only filesystem
   
   my_exe=`basename $0`
   my_touch_file=${DIR_ROOT_BACKUP}"/"$my_exe.$$

   touch $my_touch_file 2> /dev/null

   if [ $? -ne 0 ];then
      echo "$MSG_CANT_WRITE_ON $DIR_ROOT_BACKUP"
      exit $ERROR_CANT_WRITE_ON
   else
      rm $my_touch_file
   fi
fi


# ------------------------------------------------------------
# Ahora voy a verificar si todo lo que me piden que 
# guarde existe.
#
# Tiene que existir por lo menos 1 para que coloque registro
# en el log.
# Podria llevar un log de errores (solo si el usario quiere).
#
# ------------------------------------------------------------
# Ahora copio los archivos
#
# variables importantes de shell (Kernighan & Pike -  The UNIX Programming Environment)
#
# $#  cantidad de argumentos (sin contar el nombre del programa)
# $*  la lista de todos los argumentos
# $-  las opciones suministradas
# $?  valor del ultimo comando ejecutado  

# init
log_h_written=$STAT_KO


COUNT="+"

for arg in $*
do
  # analizo para ver si en arg tiene directorio (distinto al ./)
  # esto sirve para hacer el backup sin tener que pararme en el
  # directorio que deseo.
  #
  # N.B.: dirname pepe     -> .
  #       dirname ./pepe   -> .
  #

  debug arg
  debug $arg

  # get dirname of arg 
  my_dirname $arg
  LISTA_DIR_ORIGEN=$RET_my_dirname; export LISTA_DIR_ORIGEN

  # get the string after the last / of arg 
  my_basename $arg
  SOURCE_BASENAME=$RET_my_basename; export SOURCE_BASENAME

  debug "LISTA_DIR_ORIGEN: $LISTA_DIR_ORIGEN"
  debug "SOURCE_BASENAME: $SOURCE_BASENAME"


  # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  # para que funcione algo como save /etc/rc?.d/AKA, que si no no anda 
  # debo probar mejor tengo mis dudas acerca de este for


  for DIR_ORIGEN in $LISTA_DIR_ORIGEN
  do

    # ------------------------------------------
    # manage . and ..
    # transform it in an absolute path
    if test $DIR_ORIGEN = "."; then
       DIR_ORIGEN=$CURRDIR

       if [ $SOURCE_BASENAME = "." ]; then

            aux_dir=$DIR_ORIGEN
            my_dirname $aux_dir
            DIR_ORIGEN=$RET_my_dirname

            my_basename $aux_dir
            SOURCE_BASENAME=$RET_my_basename

            debug "-- $RET_my_dirname - $RET_my_basename"

       fi     

       if [ $save_plain -eq 1 ]; then
         DIR_ORIGEN="."
       fi

    elif test $DIR_ORIGEN = ".."; then
       cd ..
       DIR_ORIGEN=`pwd`
       cd $CURRDIR

       if [ $SOURCE_BASENAME = ".." ]; then

            aux_dir=$DIR_ORIGEN
            my_dirname $aux_dir
            DIR_ORIGEN=$RET_my_dirname

            my_basename $aux_dir
            SOURCE_BASENAME=$RET_my_basename
       fi     

    fi
    # ------------------------------------------

    if [ $save_inplace -eq 1 -o  $save_plain -eq 1 ]; then
        DEST_DIR=${DIR_BASE_BACKUP} 
    else
        DEST_DIR=${DIR_BASE_BACKUP}${DIR_ORIGEN} 
    fi

    debug "DEST_DIR: $DEST_DIR"

    ABS_SOURCE_PATHNAME=$DIR_ORIGEN"/"$SOURCE_BASENAME
 
    
    # init
    status=$STAT_CONTINUE
    my_status=$STAT_OK

    if [ ! -f $ABS_SOURCE_PATHNAME -a ! -d $ABS_SOURCE_PATHNAME ]; then 
       # target file doesn't exist
       echo "860 - $MSG_NOT_FOUND $ABS_SOURCE_PATHNAME"
       my_status=$STAT_KO
    fi
    
    if [ $my_status -eq $STAT_OK ]; then 
       status=$my_status

       if [ ! -d $DEST_DIR ]; then 
          debug "mkdir -m $RWXR_XR_X -p $DEST_DIR 2> /dev/null"
          mkdir -m $RWXR_XR_X -p $DEST_DIR 2> /dev/null
          status=$?
       fi
    fi

    if [ $status -eq $STAT_CONTINUE ];then
        # nothing to do
        x=x
 
    elif [ $status -eq $STAT_OK ];then
       make_copy $SOURCE_BASENAME $ABS_SOURCE_PATHNAME $DEST_DIR
       status=$?
       
       # para usar en debug como un contador 
       COUNT=$COUNT"+"

       if [ $status -eq $STAT_OK ];then
         if [ $log_h_written -eq $STAT_KO ]; then
            log_h_written=$STAT_OK
            put_log_header 
         fi

         if [ -f $arg ]; then
             ABS_SOURCE_PATHNAME=$DIR_ORIGEN"/"$SOURCE_BASENAME
             ls_2_log $ABS_SOURCE_PATHNAME
         else
            echo $MSG_DIR_LIST $ABS_SOURCE_PATHNAME >> $LISTA
            list_2_log $ABS_SOURCE_PATHNAME
         fi
       else

         # make_copy has failed
          MSG_AUX="$DIR_ORIGEN/$SOURCE_BASENAME: $MSG_NOT_FOUND"
          echo $MSG_AUX 
       fi
       
    else   
       MENSAJE="900 - $MSG_CANT_CREATE_DIR $DEST_DIR"
       echo $MENSAJE
       #echo $MENSAJE >> $LISTA
    fi
    done
    # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
done

# end of saveit
