#!/bin/bash
# ---------------------------------------------------------------------
# Copyright (c) 2020, 2022 by Cisco Systems, Inc.
# All rights reserved.
# Author: Wilson Talaugon (wtalaugo@cisco.com)
#
# xr_dir_monitor
# Script that monitors changes in any given directory in the list using
# inotifywait() and takes an action accordingly. It is spawned by the
# xr_startup.sh script and terminated by the xr_stop.sh script.
# ---------------------------------------------------------------------

source /etc/init.d/pd-functions &> /dev/null
if declare -F pd_is_emerg_shell_supported &> /dev/null ; then
    if [ $(pd_is_emerg_shell_supported) -eq 0 ]; then
        exit 0
    fi
else
    exit 0
fi

# archive folders in DR
DR_DIR="/mnt/dr_part"
DR_PASSWD_DIR="$DR_DIR/etc"
DR_LVM_METADATA_ARCHIVE_DIR="$DR_DIR/lvm/archive"
DR_LVM_METADATA_BACKUP_DIR="$DR_DIR/lvm/backup"
LVM_METADATA_ARCHIVE_DIR="/etc/lvm/archive"
LVM_METADATA_BACKUP_DIR="/etc/lvm/backup"
PASSWD_DIR="/etc"

# set default permission to root
umask 077

# pre-event actions
# -----------------------------------------------------------------
if [ -d $DR_DIR ]; then
   # create the password archive folder in DR, if it does not exist
   mkdir -p $DR_PASSWD_DIR
   # copy password and shadow files, if they do not exist
   if [ ! -f $DR_PASSWD_DIR/passwd ]; then
      cp /etc/passwd $DR_PASSWD_DIR
      evmctl ima_sighash $DR_PASSWD_DIR/passwd
   fi
   if [ ! -f $DR_PASSWD_DIR/shadow ]; then
      cp /etc/shadow $DR_PASSWD_DIR
      evmctl ima_sighash $DR_PASSWD_DIR/shadow
   fi
   # create the lvm metadata archive folders in DR
   mkdir -p $DR_LVM_METADATA_ARCHIVE_DIR
   # copy the latest lvm metadata file from the archive
   if [ "$(ls -A $LVM_METADATA_ARCHIVE_DIR)" ]; then
      rm -f $DR_LVM_METADATA_ARCHIVE_DIR/*
      cp "`ls -dtr $LVM_METADATA_ARCHIVE_DIR/* | tail -1`" $DR_LVM_METADATA_ARCHIVE_DIR
   fi
   # create the lvm metadata backup folders in DR
   mkdir -p $DR_LVM_METADATA_BACKUP_DIR
   # copy the latest lvm metadata file from the backup
   if [ "$(ls -A $LVM_METADATA_BACKUP_DIR)" ]; then
      rm -f $DR_LVM_METADATA_BACKUP_DIR/*
      cp "`ls -dtr $LVM_METADATA_BACKUP_DIR/* | tail -1`" $DR_LVM_METADATA_BACKUP_DIR
   fi

   # Remove auto_recovery file if it is present
   if [ -f $DR_DIR/.auto_recovery ]; then
       rm $DR_DIR/.auto_recovery
   fi
   /usr/bin/logger -t xr_dir_monitor "File monitoring started. DR [$DR_DIR] archive & backup folders were created."
else
   /usr/bin/logger -t xr_dir_monitor "File monitoring started. Unable to create DR [$DR_DIR] archive & backup folders!"
fi
# -----------------------------------------------------------------

# enumerate the directories to monitor
dirs_to_monitor=(
   "$LVM_METADATA_ARCHIVE_DIR"
   "$LVM_METADATA_BACKUP_DIR"
   "$PASSWD_DIR"
)

function lvm_archive_create_event()
{
   directory=$1
   filename=$2
   extension="${filename##*.}"
   case $directory in
      # LVM metadata archive
      "archive")
	 if [ "$extension" = "vg" ]; then
            # copy the updated lvm metadata file to DR from the lvm archive folder
            if [ -d $DR_LVM_METADATA_ARCHIVE_DIR ]; then
               rm -f $DR_LVM_METADATA_ARCHIVE_DIR/*
               cp $LVM_METADATA_ARCHIVE_DIR/$filename $DR_LVM_METADATA_ARCHIVE_DIR
               /usr/bin/logger -t xr_dir_monitor "LVM archive metadata $filename was created. Archived to DR."
            else
               /usr/bin/logger -t xr_dir_monitor "LVM archive metadata $filename was created. Unable to archive to DR!"
            fi
         fi
         ;;
   esac
}

function lvm_backup_moved_to_event()
{
   directory=$1
   filename=$2
   extension="${filename##*.}"
   case $directory in
      # LVM metadata backup
      "backup")
         # copy the updated lvm metadata file to DR from the lvm backup folder
	 if [ "$extension" = "$filename" ]; then
            if [ -d $DR_LVM_METADATA_BACKUP_DIR ]; then
               rm -f $DR_LVM_METADATA_BACKUP_DIR/*
               cp $LVM_METADATA_BACKUP_DIR/$filename $DR_LVM_METADATA_BACKUP_DIR
               /usr/bin/logger -t xr_dir_monitor "LVM backup metadata $filename was created. Archived to DR."
            else
               /usr/bin/logger -t xr_dir_monitor "LVM backup metadata $filename was created. Unable to archive to DR!"
            fi
	 fi
         ;;
   esac
}

function etc_close_write_event()
{
   directory=$1
   filename=$2
   case $directory in
      # password directory 
      "etc")
         # copy the updated lvm metadata file to DR from the lvm archive folder
         [ "$filename" != ".pwd.lock" ] && return
         if [ -d $DR_PASSWD_DIR ]; then
            # copy the password & shadow file
            cp $directory/passwd $DR_PASSWD_DIR
            cp $directory/shadow $DR_PASSWD_DIR
            # sign the password & shadow file
            evmctl ima_sighash $DR_PASSWD_DIR/passwd
            evmctl ima_sighash $DR_PASSWD_DIR/shadow
            /usr/bin/logger -t xr_dir_monitor "Password files were updated. Archived to DR."
         else
            /usr/bin/logger -t xr_dir_monitor "Password files were updated. Unable to archive to DR!"
         fi
         ;;
   esac
}

# monitor any updates to the directories
inotifywait -q -m -e create,moved_to,close_write ${dirs_to_monitor[@]} --format "%e %w %f" |
# identify the updated dir and make a backup copy in DR
while read event source filename; do
   directory="$(basename $source)"
   case $event in
      # file create event 
      "CREATE")
         # process LVM metadata arcchive file event handler
	 lvm_archive_create_event $directory $filename
         ;;
      # file rename event 
      "MOVED_TO")
         # process LVM metadata backup file event handler
	 lvm_backup_moved_to_event $directory $filename
         ;;
      # file close event
      "CLOSE_WRITE,CLOSE")
         # process password file event handler
	 etc_close_write_event $directory $filename
         ;;
   esac
done
# exit if there is a problem monitoring the files
if [ $? -ne 0 ]; then
   /usr/bin/logger -t xr_dir_monitor "Invalid event! Exiting."
   exit 1
fi
