Rebuilding SIS attachment links from log

Daniel Miller dmiller at amfes.com
Wed Mar 4 04:26:06 UTC 2015


Well, with no guarantees or promises whatsoever...here's my first 
attempt.  I'm certain someone else can come up with a much more robust 
solution but it's a starting point.

Since I typically see a batch of the error messages during an FTS 
update, my current usage is:

1.  doveadm fts rescan -u user-to-fix
2.  Perform a fts search to do a full mailbox scan
3.  Check the mail log to see the date/time of the errors (I usually 
have a window open with tail -f)
4.  Something like "grep 'Mar  3 20:17' mail.log > mail.err" gives me a 
starting point

execute dovesisfix and see if it helps.

--
Daniel

On 3/3/2015 1:08 PM, Daniel Miller wrote:
> This seems simple enough...I'm just not script wizard.  If someone can 
> throw together a starting point I can test and tweak it from there.  
> It seems to me:
>
> 1.  Read /var/mail/mail.err or specified logfile
> 2.  For each "failed: 
> read(/var/mail/attachments/aa/bb/attachmentHash-userHash" line,
>     a. Confirm /var/mail/attachments/aa/bb/hashes/attachmentHash exists
>         i. If attachmentHash is missing display such for possible 
> backup searching.
>     b. create link attachmentHash-userHash to hashes/attachmentHash
> 3.  Continue to end of file
>
> Can this be done via "pure" BASH?  Need sed/awk as well?
>

-------------- next part --------------
#!/bin/bash

# These variables need to be customized for your particular installation
LOGFILE='/var/log/mail.err'
ATTACHMENT_STORAGE_BASE='/var/mail/attachments'

# These variables are based on current Dovecot behaviour and should not require changing
HASH_FOLDER='hashes'

# Initialization
PREVIOUS_ERR=''
ERR=''

function usage
{
    echo "Dovecot Single-Instance-Storage Attachment Repair"
    echo "usage: dovesisfix [-d] [-t] [-v] [-h]"
    echo "   -t | --test-only	perform logfile analysis and show steps to be taken without any on-disk modification"
    echo "   -v | --verbose	provide verbose messages at each step"
    echo "   -d | --debug		provide additional debug messages"
    echo "   -h | --help		this screen"
}

while [ "$1" != "" ]; do
    case $1 in
	-d | --debug )		DEBUG=1
				VERBOSE=1
				;;
	-t | --test-only )	TESTMODE=1
				;;
	-v | --verbose )	VERBOSE=1
				;;
	-h | --help )		usage
				exit
				;;
	* )			usage
				exit 1
    esac
    shift
done

while read -r LINE
do
    ERR=$LINE

    # Format of log line has date, host, process, user, mail storage file, and then the
    # attachment path failure, followed by a duplicate of the path as an argument to open,
    # and then final details.

    # Verify this line is indeed a dovecot attachment error.  Don't look for "dovecot" specifically
    # in case that name was changed - but the individual worker names are probably safe searches.
    # So we test against "attachments-connector" - hopefully that's good enough.
    TEST=$(echo "$ERR" | sed -n "s|.*attachments-connector.*|1|p")
    if [ "$TEST" != "1" ]; then
	# Not found - not relevant
        if [ "$DEBUG" = 1 ]; then
	    echo "Skipping non-relevant log line. $ERR"
	fi
	continue
    fi

    # Remove prefacing details from log line - find start of attachment path within log line
    # This is a greedy match - so the second attachment path is returned along with the trailing info
    ATTACH_LINE_FILTER="s|.*$ATTACHMENT_STORAGE_BASE||"
    ATTACH_LINE=$(echo "$ERR" | sed "$ATTACH_LINE_FILTER")

    # Now extract the aa/bb/ prefix, the base attachment file name, and user hash
    CATEGORY_PATH="${ATTACH_LINE:1:5}"
    BASE_HASH="${ATTACH_LINE:7:40}"
    USER_HASH="${ATTACH_LINE:48:32}"

    ATTACH_SOURCE="$ATTACHMENT_STORAGE_BASE/$CATEGORY_PATH/$HASH_FOLDER/$BASE_HASH"
    ATTACH_TARGET="$ATTACHMENT_STORAGE_BASE/$CATEGORY_PATH/$BASE_HASH-$USER_HASH"

    # There appear to be duplicate lines - so to try to filter some out.
    if [ "$PREVIOUS_TARGET" = "$ATTACH_TARGET" ]; then
        if [ "$DEBUG" = 1 ]; then
	    echo "Skipping duplicate log line for $ATTACH_SOURCE-$ATTACH_TARGET"
	fi
	continue
    fi
    PREVIOUS_TARGET=$ATTACH_TARGET

    # If in debug/verbose mode show operation about to occur
    if [ "$VERBOSE" = 1 ]; then
        echo "The file $ATTACH_SOURCE must be linked to $ATTACH_TARGET"
    fi

    # Verify that source exists
    if [ ! -f "$ATTACH_SOURCE" ]; then
	echo "ERROR: File $ATTACH_SOURCE does not exist. You must restore this from a backup and run this utility again."
    fi
    # This is a Good Thing.
    if [ "$DEBUG" = 1 ]; then
        echo "The file $ATTACH_SOURCE appears to be a valid file."
    fi

    # Check if user link mysteriously reappeared
    if [ -f "$ATTACH_TARGET" ]; then
	echo "INFO: File $ATTACH_TARGET exists. This may mean the fault has been previously corrected. Clearing/rotating the logfile $LOGFILE is appropriate now."
	continue
    fi

    # Prepare to create user link
    LINK_LINE="$ATTACH_SOURCE $ATTACH_TARGET"
    if [ "$DEBUG" = 1 ]; then
	echo "About to execute command: ln $LINK_LINE"
    fi

    # If test mode, do nothing
    if [ "$TESTMODE" = 1 ]; then
	continue
    fi

    # There's probably more tests I could/should do - but I don't know how
    # So...if we're not in test mode...time to do it to it.
    LINK_CREATED=$(ln $LINK_LINE)
    if [ "$VERBOSE" = 1 ]; then
	echo "Repair result for $ATTACH_TARGET - $LINK_CREATED"
    fi

done < "$LOGFILE"


More information about the dovecot mailing list