#!/bin/bash
# retire.sh
# script to move somewhere else (DESTN) those files considered
# unused after not having been accessed since some predetermined
# date (LIMIT)

# Copyright :   EUROGARAN Informatica S.L.   http://www.eurogaran.com
# This software is published under the terms of the GNU GPL license :
# Copying and redistribution is permitted, changing the license is not,
# even after modifying the software.

# Please send modifications-enhancements to  <informatica@eurogaran.com>

# DEPENDS ON recent versions of ls and GNU tools.
# Just check they admit the modifiers used.

#=============================================================================
#>>>> MODIFIABLE PARAMETER No. 1
# LIST of directories to be included.
# In 1 same line (beware your editor does not break that line),
# separated by 1 space. Therefore, no dir can have spaces in its name.
# Example :
# INCLU='/root /home/albert /home/user25'
INCLU='/home/juanjo/tmp'

#>>>> MODIFIABLE PARAMETER No. 2
# FILE containing the names of directories and files to be excluded, each in its
# own line and "double quoted" whenever special characters or spaces appear.
# (In case of doubt, double quote the absolute path as produced by ls).
# Excluding a directory implies excluding all its subdirectories.
EXCLU='/etc/retirexcep.txt'

#>>>> MODIFIABLE PARAMETER No. 3
# Date from which files are to be kept.
# Files unaccessed from that date or before are to be moved.
# The format must be year-month-day.  Example :  2005-02-30
# Pay attention everything goes in its place, and do not forget
# to prepend an aditional zero to the month or day if necessary.
LIMIT=2006-01-01

#>>>> MODIFIABLE PARAMETER No. 4
# Name of the destination repository.
# It is recommended to include the date in the path.  Example :
# DESTN=/old/not_used_since/$LIMIT
DESTN=/tmp/not_used_since/$LIMIT

#>>>> MODIFIABLE PARAMETER No. 5
# Whether to eliminate or not the directories emptied during the process.
# Dangerous if for at least one of them it has sense to exist empty, as
# for instance the /Trash folder in a desktop, the documents folder, etc.
ELIMINA_DIRS="Afirmativo"
# Uncomment/comment the following line to keep/delete emptied directories.
# unset ELIMINA_DIRS


#>>>> MODIFIABLE PARAMETER No. 6
# Create in each origin directory a link or access to destination.
# Its main purpose is to avoid surprises/complaints from users
# that do not found their files.
DIRECT_ACCESS="not_used_since_$LIMIT"
# Uncomment the following line to not create any link.
# unset DIRECT_ACCESS


#>>>> MODIFIABLE PARAMETER No. 7
# log to archive
LOGAR=/dev/null
LOGAR=/tmp/retirelog.txt

#=============================================================================
# Normally it should not be necessary to modify anything below this line.

mkdir -p $DESTN || exit 1

# Now LIMIT can be converted to a purely numeric format :
LIMIT=`echo "$LIMIT" | tr -d '-'`

# The exclusion file is read and a filter to be applied later is built :
# The purpose of the filter's initial value is to avoid directories ./ and ../
FILTR=" | grep -ve '^\.$' | grep -ve '^\.\.$'"
TEMPF=`tempfile`
echo "$FILTR" > $TEMPF
cat "$EXCLU" | {
while read; do
  # Empty lines are discarded :
  if [ "$REPLY" ]; then
    if ! [ -e "$REPLY" ]; then
      echo "Nonexistent excluded file or directory $REPLY"
      echo "Remains excluded (just in case it would appear during execution)."
    fi
    FILTR="$FILTR | grep -v ^$REPLY"
    echo "$FILTR" > $TEMPF
  fi
done
}
FILTR=`cat "$TEMPF"` && rm "$TEMPF"

if ! [ "$LOGAR" ]; then
  LOGAR=/dev/null
fi
echo "Filter is:$FILTR" > $LOGAR || exit 1


# Directories not excluded by the filter are entered, and inside each subdir
# its files are examined after passing the filter again :
for ORIGN in $INCLU; do
  find $ORIGN -type d | {
    while read; do
      DIRECTORY_IS_NOT_EXCLUDED=`sh -c "echo \"$REPLY\"$FILTR"`
      if [ "$DIRECTORY_IS_NOT_EXCLUDED" ]; then
        NOMDIR=$REPLY
        echo "Checking directory $NOMDIR" >> $LOGAR
        cd "$NOMDIR"
        ls -1 --color=never | {
          while read; do
            ARCHIVE_IS_NOT_EXCLUDED=`sh -c "echo \"$REPLY\"$FILTR"`
            if [ "$ARCHIVE_IS_NOT_EXCLUDED" ]; then
              if ! [ -d "$REPLY" ]; then
                # ls -ult  to use last access time
                # ls -lt   to use last modification time
                FECHA=`ls -ult "$REPLY" | tr -s '[:space:]'\
                      | cut -d ' ' -f 6 | tr -d '-'`
                if [ "$FECHA" -le "$LIMIT" ] ; then
                  if ! [ -e "$DESTN/$NOMDIR" ]; then
                    mkdir -p "$DESTN/$NOMDIR" &&\
                    chown --reference="$NOMDIR" "$DESTN/$NOMDIR" &&\
                    chgrp --reference="$NOMDIR" "$DESTN/$NOMDIR" &&\
                    chmod --reference="$NOMDIR" "$DESTN/$NOMDIR" &&\
                    getfacl "$NOMDIR" |\
                    setfacl --set-file=- "$DESTN/$NOMDIR" 2>&1 >> $LOGAR &&\
                    echo "Created directory $DESTN/$NOMDIR" >> $LOGAR ||\
                    echo "Could not create directory $DESTN/$NOMDIR" >> $LOGAR
                    if [ "$DIRECT_ACCESS" ]; then
                      if ! [ -e "$ORIGN/$DIRECT_ACCESS" ]; then
                        ln -s "$DESTN/$ORIGN" "$ORIGN/$DIRECT_ACCESS"
                      fi
                    fi
                  fi
                  # Deleting files only after having copied them is equivalent
                  # but more secure than moving them, and it additionally allows
                  # to reproduce ACLs :
                  cp -dp "$REPLY" "$DESTN/$NOMDIR" &&\
                  getfacl "$REPLY" |\
                  setfacl --set-file=- "$DESTN/$NOMDIR/$REPLY" 2>&1 >> $LOGAR &&\
                  echo "Transferred archive $NOMDIR/$REPLY" >> $LOGAR \
#                  && rm -f "$REPLY" && echo "Original has been deleted." >> $LOGAR
                  # Uncomment/comment the preceding line to activate/deactivate
                  # deletion.
                  # Important :  Do not ever write any comments above that line.
                fi
              fi
            fi
          done
        }
        cd -
      fi
    done
  }
done
echo "Processing complete." >> $LOGAR


if [ "$ELIMINA_DIRS" ]; then
  echo "All empty directories will be eliminated." >> $LOGAR
  for ORIGN in $INCLU; do
    # Proceeding from the bottom up (-depth), opposite as before :
    find $ORIGN -type d -depth | {
      while read; do
        if [ -e "$DESTN/$REPLY" ]; then
          # If any files remain, just do nothing, but do not signal error.
          rmdir "$REPLY" --ignore-fail-on-non-empty
        fi
      done
    }
  done
fi

