#!/bin/bash # If your bash is located elsewhere or if you dare to try sh edit above. # Nicon's Autodelete script version 1.70 (c) 2004 Nicon # EXTERNAL DEPENDENCIES: # ls, du, df, date, cut, bash from FILEUTILS # SHELLUTILS also required for gdate etc # Tested on: Debian GNU/Linux, Gentoo, OpenBSD SectionInclude="/glftpd/glftpd/bin/autodelete.sections" ConfigurationInclude="/glftpd/glftpd/bin/autodelete.config" #### Section Delete Configuration #### function sections { . $SectionInclude } #### Load configuration settings #### . $ConfigurationInclude #### End Delete Configuration #### NICE="nice -n 10" if [ "$1" == "-t" ]; then TEST="YES"; DisableBot="YES"; fi if [ "$1" == "-v" -o "$1" == "--version" ]; then echo "Autodelete v1.70 (c) 2004 Nicon" exit 0 fi function ConsoleAnnounce { if [ "$TEST" == "YES" ]; then if [ "$1" == "-n" ]; then shift; echo -n "$1"; else echo "$1"; fi fi } function BotAnnounce { if [ "$DisableBot" != "YES" ]; then echo "$($DATE "+%a %b %d %T %Y") $LogVar: \"$1\"" >>$LogDir/glftpd.log fi if [ $DebugBotAnnounce == "YES" -a "$TEST" == "YES" ]; then ConsoleAnnounce " -- Bot would have said: \"$1\""; fi } function Log { echo "$($DATE "+%d/%m/%Y %H:%M:%S"): $1" >>$LogFile } if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_MANUALSTART="${MSG_MANUALSTART//"\%b"/}" MSG_MANUALHALT="${MSG_MANUALHALT//"\%b"/}" MSG_AUTOSTART="${MSG_AUTOSTART//"\%b"/}" else MSG_MANUALSTART="${MSG_MANUALSTART//\%b/}" MSG_MANUALHALT="${MSG_MANUALHALT//\%b/}" MSG_AUTOSTART="${MSG_AUTOSTART//\%b/}" fi # Initial variables and compatability N="/dev/null" ITEMS=0 sitedir=$SiteDir logdir=$LogDir logfile=$LogFile IGNORE=$Ignore Incomplete="${Incomplete//[/\\[}" Incomplete="${Incomplete//]/\\]}" NukePattern="${NukePattern//[/\\[}" NukePattern="${NukePattern//]/\\]}" #### Generating ls and du ignore string #### for i in $Ignore; do IgnoreLS="$IgnoreLS --ignore=$i" IgnoreDU="$IgnoreDU --exclude=$i" done function CheckMinimum { MinimumSpace="-1" for d in $ManualDrives; do FreeSpace=$($DF --block-size=1048576 -P $d 2>$N | tail -n1 | awk '{print $4}') ConsoleAnnounce "Checking drive $d. Free space: $FreeSpace, limit $ManualLimit" if [ "$FreeSpace" -lt "$ManualLimit" -o "$FreeSpace" == "-1" ]; then MinimumSpace="$FreeSpace" fi done } function NukeModule { $LS -d $NukePattern >$N 2>$N if [ "$?" == "0" ]; then for n in $($LS -d $NukePattern 2>$N); do let "NukeDiff=($($DATE +%s)/3600)-($($DATE +%s -r $n)/3600)" if [ "$NukeDiff" -gt "$MinNukeHrs" ]; then Log "Nuked old dir: $(pwd)/$n" $NICE rm -rf $n 2>$N; fi done fi } function SymlinkModule { for file in * ; do if [ ! -e "$file" ] ; then $NICE rm -f "$file"; Log "Invalid Symlink: $(pwd)/$file" fi done } function GetDatedOldest { FOUND=0 DAY=0 COUNT=0 while [ "$FOUND" != 1 ]; do CURSTRING="$($DATE +$PATTERN --date "$DAY days ago")" IGN=0 for m in ${IgnoreLS//--ignore=/}; do if [ "$m" == "$CURSTRING" ]; then IGN=1; fi done if [ -e "$CURSTRING" -a "$IGN" != "1" ]; then OLDEST="$CURSTRING" let DAY++ COUNT=0 else let COUNT++ if [ "$COUNT" -lt "$MaxGap" ]; then let DAY++ else FOUND=1 fi fi done echo $OLDEST } ##### Default Messages ##### if [ "$1" == "1" -o "$1" == "2" ]; then if [ "$MSG_MANUAL" != "DISABLED" ]; then if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_MANUAL="${MSG_MANUAL//"\%t"/$ManualLimit}" MSG_MANUAL="${MSG_MANUAL//"\%b"/}" else MSG_MANUAL="${MSG_MANUAL//\%t/$ManualLimit}" MSG_MANUAL="${MSG_MANUAL//\%b/}" fi BotAnnounce "$MSG_MANUAL" fi CheckMinimum if [ "$MinimumSpace" -lt "$ManualLimit" -a "$MinimumSpace" != "-1" ]; then ConsoleAnnounce " -- Manual Start: Minimum Space was $MinimumSpace" if [ "$MSG_MANUALSTART" != "DISABLED" ]; then BotAnnounce "$MSG_MANUALSTART"; fi else if [ "$MSG_MANUALHALT" != "DISABLED" ]; then BotAnnounce "$MSG_MANUALHALT"; fi exit 0 fi else if [ "$MSG_AUTOSTART" != "DISABLED" ]; then BotAnnounce "$MSG_AUTOSTART"; fi fi #### End Default Messages #### ### CurrentSize, MaxSize, Percent ### function addstring { let CUTS=${#SiteDir}+1 SECTION=$(echo $(pwd) | cut -c$CUTS-) ADD="$ANNOUNCESEP $SECTION:$1MB (Calc. max: ${2}MB,$3)" let TOTAL=${#POST}+${#ADD} if [ "$TOTAL" -gt "467" ]; then echo $POST POST="$ANNOUNCE" else POST="$POST $ADD" fi } #### $1=PercentValue, $2=NumberOfPercents function percent { let "TOTAL=$1*$2" echo $TOTAL } function NewDrive { CurrentDrive="$1" TotalSpace=$($DF --block-size=1048576 -P $1 2>$N | tail -n1 | awk '{print $2}') FreeSpace=$($DF --block-size=1048576 -P $1 2>$N | tail -n1 | awk '{print $4}') ConsoleAnnounce -n " + Drive $1, Capacity ${TotalSpace}MB" if [ "$2" == "-i" ]; then ConsoleAnnounce ", Ignoring patterns: $3" for i in $3; do LIgnoreLS="$LIgnoreLS --ignore=$i" LIgnoreDU="$LIgnoreDU --exclude=$i" done else LIgnoreLS="" LIgnoreDU="" ConsoleAnnounce "" fi let "TotalSpace = $TotalSpace - $MinimumSpace" STATIC="1" } function static { STATIC="1" } function dynamic { STATIC="0" SKIPDRIVE="0" if [ "$StrictMinimum" == "YES" -a "$FreeSpace" -gt "$MinimumSpace" ]; then ConsoleAnnounce " - StrictMinimum set. Enough free space, skipping drive." SKIPDRIVE="1" return fi if [ "$SubtractStatic" == "YES" ]; then subtract $STATICDIRS; fi let "PERCENT=$TotalSpace/100" ConsoleAnnounce " One percent rounded to ${PERCENT}MB" STATICDIRS="" } #Subtracting Dir1 Dir2 ... DirX from $TotalSpace function subtract { LENGTH=$(expr ${#SiteDir} + 1) ConsoleAnnounce " Subtracting directories:" for d in $*; do cd $d 2>$N if [ "$?" == "0" ]; then DIRSPACE="$($NICE $DU $IgnoreDU $LIgnoreDU --max-depth=1 --block-size=1048576 | tail -n1 | cut -d'.' -f1)" let "DIRSPACE=$DIRSPACE*1" let "TotalSpace = $TotalSpace - $DIRSPACE" ConsoleAnnounce " $(echo $d | cut -c$LENGTH-) (${DIRSPACE}MB)" else ConsoleAnnounce " $d nonexistant" fi done ConsoleAnnounce " New Total: $TotalSpaceMB" } #### Removes latest object from current directory #### function erasefile { if [ "$TEST" == "YES" ]; then FreeSpace="$(expr $FreeSpace + $($DU --max-depth=0 --block-size=1048576 $1 | tail -n1 | awk '{print $1}'))" else FreeSpace=$($DF --block-size=1048576 -P $CurrentDrive 2>$N | tail -n1 | awk '{print $4}') fi if [ $STATIC == "0" -a "$StrictMinimum" == "YES" -a "$FreeSpace" -gt "$MinimumSpace" ]; then ConsoleAnnounce " - StrictMinimum set. Enough free space, skipping drive." SKIPDRIVE="1" return fi if [ "$TEST" != "YES" ]; then if [ "$MOVE" == "Y" -a "$NoMove" != "Y" ]; then if [ -e "$DEST/$1" ]; then case "$ArchiveExists" in RMD) $NICE rm -rf $DEST/$1 Log "Warning: $DEST/$1 does already exist. Removing $DEST/$1 according to settings" ;; RMS) $NICE rm -rf $1 Log "Warning: $DEST/$1 does already exist. Removing $1 according to settings" ;; IGN) IgnoreLS="$IgnoreLS --ignore=$1" Log "Warning: $DEST/$1 does already exist. Ignoring $1 according to settings" ;; *) IgnoreLS="$IgnoreLS --ignore=$1" Log "Warning: $DEST/$1 does already exist. NO SETTING FOUND, REVIEW CONFIG! Ignording $1" ;; esac else $NICE mv "$1" "$DEST" 2>>$LogFile if [ "$?" == "0" ]; then Log "Moved $(pwd)/$1 -> $3" else if [ "$ArchiveFailBot" == "YES" -a "$MSG_MOVE_FAIL" =! "DISABLED" ]; then CUTLEN="$(expr ${#SiteDir} + 1)" SECTION="$(echo $DIRECTORY | cut -c$CUTLEN-)" SECTIONMV="$(echo $DEST | cut -c$CUTLEN-)" if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_MOVE_FAIL2="${MSG_MOVE_FAIL//"\%o"/$1}" MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//"\%l"/$SECTION}" MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//"\%d"/$SECTIONMV}" MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//"\%b"/}" else MSG_MOVE_FAIL2="${MSG_MOVE_FAIL//\%o/$1}" MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//\%l/$SECTION}" MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//\%d/$SECTIONMV}" MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//\%b/}" fi ANN_FAIL="Y" fi case "$OnMoveFail" in IGN) IgnoreLS="$IgnoreLS --ignore=$1" Log "Warning: Move of $(pwd)/$1 failed. Ignoring $1 according to settings" MERR="Ignoring this object and continue execution" ;; CON) Log "Warning: Move of $(pwd)/$1 failed. Continuing execution according to settings" MERR="Continuing execution" ;; NOM) NoMove="Y" Log "Warning: Move of $(pwd)/$1 failed. Disabling archiving according to settings" MERR="Disabling archiving" ;; EXT) Log "Warning: Move of $(pwd)/$1 failed. Stopping execution according to settings" if [ "$ANN_FAIL" == "Y" ]; then if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//"\%e"/Disabling archiving}" else MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//\%e/Disabling archiving}" fi BotAnnounce $MSG_MOVE_FAIL2 fi exit 0 ;; *) Log "Warning: Move of $(pwd)/$1 failed. NO SETTING FOUND, REVIEW CONFIG! Disabling archiving mode (WARNING, THIS MUST BE ATTENDED TO AVOID LOW DISKSPACE)" MERR="" ;; esac if [ "$ANN_FAIL" == "Y" ]; then if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//"\%e"/$MERR}" else MSG_MOVE_FAIL2="${MSG_MOVE_FAIL2//\%e/$MERR}" fi BotAnnounce $MSG_MOVE_FAIL2 fi fi fi fi if [ "$MOVE" == "N" ]; then $NICE rm -rf "$1" 2>> $LogFile if [ "$?" == 0 ]; then Log "Deleted $(pwd)/$1" else Log "Warning: Failed to delete $1. Any stderr logged above this message. Ignoring $1 for future removal" IgnoreLS="$IgnoreLS --ignore=$1" fi fi else IgnoreLS="$IgnoreLS --ignore=$1" IgnoreDU="$IgnoreDU --exclude=$1" ConsoleAnnounce " * Simulated to take actions to $1" fi if [ "$HIDDEN" != "Y" ]; then CUTLEN="$(expr ${#SiteDir} + 1)" SECTION="$(echo $DIRECTORY | cut -c$CUTLEN-)" let ITEMS++ if [ "$MOVE" == "Y" ]; then SECTIONMV="$(echo $DEST | cut -c$CUTLEN-)" if [ "$MSG_MOVE" != "DISABLED" ]; then if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_MOVE2="${MSG_MOVE//"\%o"/$1}" MSG_MOVE2="${MSG_MOVE2//"\%l"/$SECTION}" MSG_MOVE2="${MSG_MOVE2//"\%d"/$SECTIONMV}" MSG_MOVE2="${MSG_MOVE2//"\%b"/}" else MSG_MOVE2="${MSG_MOVE//\%o/$1}" MSG_MOVE2="${MSG_MOVE2//\%l/$SECTION}" MSG_MOVE2="${MSG_MOVE2//\%d/$SECTIONMV}" MSG_MOVE2="${MSG_MOVE2//\%b/}" fi BotAnnounce "$MSG_MOVE2" fi else if [ "$THROW" != "DISABLED" ]; then if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_THROW2="${MSG_THROW//"\%o"/$1}" MSG_THROW2="${MSG_THROW2//"\%l"/$SECTION}" MSG_THROW2="${MSG_THROW2//"\%b"/}" else MSG_THROW2="${MSG_THROW//\%o/$1}" MSG_THROW2="${MSG_THROW2//\%l/$SECTION}" MSG_THROW2="${MSG_THROW2//\%b/}" fi BotAnnounce "$MSG_THROW2" fi fi fi } function parameters { HIDDEN="N"; MOVE="N"; DEST=""; AMMOUNT="" while [ "$#" -gt 0 ]; do case "$1" in -h) HIDDEN="Y" ;; -m) MOVE="Y" shift DEST="$1";; -[dsfo]) METHOD="$1" shift AMMOUNT="$1" ;; esac shift done } function GetPattern { if [ "$BASH_VERSINFO" -lt 3 ]; then PSTRING="${1//"\%m"/[0-9][0-9]}" PSTRING="${PSTRING//"\%d"/[0-9][0-9]}" PSTRING="${PSTRING//"\%W"/[0-9][0-9]}" PSTRING="${PSTRING//"\%y"/[0-9][0-9]}" else PSTRING="${1//\%m/[0-9][0-9]}" PSTRING="${PSTRING//\%d/[0-9][0-9]}" PSTRING="${PSTRING//\%W/[0-9][0-9]}" PSTRING="${PSTRING//\%y/[0-9][0-9]}" fi echo $PSTRING } #Dir Mode Size function erase { DIRECTORY=$1; shift parameters $* if [ "$SKIPDRIVE" == "1" ]; then return fi #Dated Dir Pattern Check if [ "$(echo $DIRECTORY | grep %m)" != "" -o "$(echo $DIRECTORY | grep %d)" != "" -o "$(echo $DIRECTORY | grep %y)" != "" -o "$(echo $DIRECTORY | grep %W)" != "" ]; then DATED="Y" C=1 while [ "$C" -lt ${#DIRECTORY} ]; do if [ "$(echo $DIRECTORY | cut -c$C)" == "/" ]; then POS=$C; fi let C++ done let POS++ PATTERN="$(echo $DIRECTORY | cut -c$POS-)" let POS--; let POS-- DIRECTORY="$(echo $DIRECTORY | cut -c1-$POS)" else DATED="N"; fi if [ "$STATIC" == "1" ]; then STATICDIRS="$STATICDIRS $DIRECTORY"; fi cd $DIRECTORY 2>$N if [ "$?" == "0" -a "$($LS $LIgnoreLS $IgnoreLS)" != "" ]; then ConsoleAnnounce -n " * Entered $DIRECTORY" if [ "$DATED" == "Y" ]; then ConsoleAnnounce -n ", Dated. maximum gap: $MaxGap days"; fi ConsoleAnnounce "" ### Remove nuked dirs module if [ "$RemoveNukes" == "YES" -a "$TEST" != "YES" ]; then if [ "$DATED" == "Y" ]; then for d in *; do if [ -d "$d" ]; then cd $d NukeModule cd .. fi; done; else NukeModule; fi fi ### Remove errornous symlinks module if [ "$RemoveIncomplete" == "YES" -a "$TEST" != "YES" ]; then if [ "$DATED" == "Y" ]; then for d in *; do if [ -d "$d" ]; then cd $d SymlinkModule cd .. fi done else SymlinkModule; fi fi case $METHOD in ### Per Size ### -s) if [ "$(echo $AMMOUNT | cut -c${#AMMOUNT})" == "%" ]; then LENGTH="$(expr ${#AMMOUNT} - 1)" CURRPERC="$(echo $AMMOUNT | cut -c1-$LENGTH)" AMMOUNT="$(percent $PERCENT $CURRPERC)" PERC="Y" else PERC="N"; CURRPERC="0"; fi CurrentSize=$($NICE $DU $IgnoreDU $LIgnoreDU --max-depth=1 --block-size=1048576 | tail -n1 | awk '{print $1}') ConsoleAnnounce " Current Size: ${CurrentSize}MB, Wanted Size: ${AMMOUNT}MB" ### Reuse space of sections if [ "$CurrentSize" -lt "$AMMOUNT" -a "$UtilizeEmptySpace" == "YES" -a "$CURRPERC" -lt 100 ]; then DiffSize="$(expr $AMMOUNT - $CurrentSize)" ConsoleAnnounce -n " - Unfilled ${DiffSize}MB" if [ "$PERC" == "Y" ]; then PERCENT="$(expr $PERCENT + $DiffSize \/ \( 100 - $CURRPERC \))" ConsoleAnnounce ", recalculated one percent = ${PERCENT}MB" else ConsoleAnnounce "" if [ "$STATIC" != "1" ]; then subtract $DIRECTORY; fi fi fi if [ "$DATED" == "N" ]; then LSRESULT="$($LS $IgnoreLS $LIgnoreLS)" else LSRESULT="$(GetDatedOldest)"; fi while [ $CurrentSize -gt $AMMOUNT -a "$LSRESULT" != "" ]; do if [ "$NUKED" == "Y" ]; then erasefile "$(GetDatedOldest)" else erasefile $($LS -t $IgnoreLS $LIgnoreLS | tail -n1); fi if [ "$SKIPDRIVE" == "1" ]; then return; fi CurrentSize=$($NICE $DU $IgnoreDU $LIgnoreDU --max-depth=1 --block-size=1048576 | tail -n1 | awk '{print $1}') ConsoleAnnounce " Current Size: ${CurrentSize}MB, Wanted Size: ${AMMOUNT}MB" if [ "$DATED" == "N" ]; then LSRESULT="$($LS $IgnoreLS $LIgnoreLS)" else LSRESULT="$(GetDatedOldest)"; fi done ;; ### Per Date ### -d) if [ "$DATED" == "Y" ]; then GAP="0" LDAY="$(expr $AMMOUNT + 1)" DDIR="$($DATE +$PATTERN --date "$LDAY days ago")" ConsoleAnnounce " Finding older than $DDIR" while [ "$GAP" != "$MaxGap" ]; do DDIR="$($DATE +$PATTERN --date "$LDAY days ago")" if [ -d "$DDIR" ]; then erasefile $DDIR if [ "$SKIPDRIVE" == "1" ]; then return; fi let LDAY++ GAP="0" else let GAP++ let LDAY++ fi done else OldestFl="$($LS -t $IgnoreLS $LIgnoreLS | tail -n 1)" OldestDate="$(expr $($DATE +%s -r $OldestFl) \/ 3600 \/ 24)" CheckDate="$(expr $OldestDate + $AMMOUNT)" CurrentDate="$(expr $($DATE +%s) \/ 3600 \/ 24)" ConsoleAnnounce " Current Date: $($DATE +%y%m%d), Oldest Date: $($DATE +%y%m%d -r $OldestFl). Days to keep: $AMMOUNT" while [ $CurrentDate -gt $CheckDate -a "$($LS $IgnoreLS $LIgnoreLS)" != "" ]; do erasefile "$OldestFl" if [ "$SKIPDRIVE" == "1" ]; then return; fi OldestFl="$($LS -t $IgnoreLS $LIgnoreLS | tail -n 1)" OldestDate="$(expr $($DATE +%s -r $OldestFl) \/ 3600 \/ 24)" CheckDate="$(expr $OldestDate + $AMMOUNT)" ConsoleAnnounce " Current Date: $($DATE +%y%m%d), Oldest Date: $($DATE +%y%m%d -r $OldestFl). Days to keep: $AMMOUNT" done fi ;; ### Per Objects ### -o) OBJECTS="0" OBJECTSDEL="0" if [ "$DATED" == "N" ]; then AFFECTED="$($LS --ignore="$Incomplete" $IgnoreLS $LIgnoreLS)" else AFFECTED="$($LS -d --ignore="$Incomplete" $IgnoreLS $LIgnoreLS $(GetPattern $PATTERN))" fi for i in $AFFECTED; do let OBJECTS++ if [ "$OBJECTS" -gt "$AMMOUNT" ]; then let OBJECTSDEL++ fi done OBJECTSD="0" ConsoleAnnounce " Objects: $OBJECTS, To take actions to: $OBJECTSDEL, Allowed Objects: $AMMOUNT" while [ "$OBJECTSD" -lt "$OBJECTSDEL" ]; do if [ "$DATED" == "N" ]; then erasefile $($LS -t $IgnoreLS $LIgnoreLS | tail -n1) else erasefile "$(GetDatedOldest)" fi if [ "$SKIPDRIVE" == "1" ]; then return; fi let OBJECTSD++ done ;; ### Per size left of drive ### -f) CurrentFree="$($DF --block-size=1048576 -P $DIRECTORY 2>$N | tail -n1 | awk '{print $4}')" ConsoleAnnounce " $CurrentFreeMB free on drive. Minimum: $AMMOUNTMB" while [ "$CurrentFree" -lt "$AMMOUNT" -a "$($LS $IgnoreLS $LIgnoreLS -l)" != "total 0" ]; do if [ "$DATED" == "N" ]; then OLDEST="$($LS -t $IgnoreLS $LIgnoreLS | tail -n1)" else OLDEST="$(GetDatedOldest)" fi erasefile $OLDEST if [ "$SKIPDRIVE" == "1" ]; then return; fi if [ "$TEST" == "YES" ]; then CurrentFree="$(expr $CurrentFree + $($DU --max-depth=0 --block-size=1048576 $OLDEST | tail -n1 | awk '{print $1}'))" else CurrentFree="$($DF --block-size=1048576 -P $DIRECTORY 2>$N | tail -n1 | awk '{print $4}')" fi ConsoleAnnounce " Now $CurrentFreeMB free, Minimum: $AMMOUNTMB" done ;; esac else ConsoleAnnounce " Directory $DIRECTORY, nonexistant or empty" fi } sections if [ "$MSG_END" != "DISABLED" ]; then if [ "$BASH_VERSINFO" -lt 3 ]; then MSG_END="${MSG_END//"\%n"/$ITEMS}" MSG_END="${MSG_END//"\%b"/}" else MSG_END="${MSG_END//\%n/$ITEMS}" MSG_END="${MSG_END//\%b/}" fi BotAnnounce "$MSG_END" fi #END