Recently I found this fantastic tool that lets you pull mails from
an IMAP account and push them into another one. Basically implementing
a forwarding functionality for me for a certain university outlook
mail server (ugly, I know) to a certain free mail service (lets call
it gmail) which offers IMAP access and active “pulling” of mails from
POP servers, but not from IMAP servers.
The tool I’m talking about is
imapfilter . You can set it up such that
cron runs it every such and such minutes, but beware that you never
ever run two instances of the process at the same time. Otherwise bad
things can happen, and of course you don’t want that to happen to your
mail.
To ensure that only one instance runs at the same time, I put
together the following little script. This allows me to have cron try
and run imapfilter every minute without having to fear that I loose
mail.
The corresponding crontab entry reads
*/2 * * * * runnonconcurrently.sh imapfilter -l/home/myname/imapfilter_error.log >/dev/null 2>&1
And here’s the the script:
#!/bin/bash
# Copyright (C) 2010 by Bjoern Rueffer
function usage (){
# display usage information
CMDNAME = $( basename $0 )
cat<<EOF
$CMDNAME Copyright (c) 2010 Bjoern Rueffer. Run a
command/program non-concurrently, i.e., avoid that
several instances of the same program run at the
same time.
Usage: $CMDNAME command [command parameters]
Return values: -1 if you see this help or if there
is a stale lock file which cannot be obtained;
0 if another process is already running; otherwise
the return value of the sub process is returned.
EOF
exit -1
}
function escapestr (){
# escape all non alpha numerical characters
# for file name generation
echo -n " $1 " | sed -e s:[^a-zA-Z0-9]:_:g
}
function runsubprocess(){
# $LOCKFILE has been successfully created, so
# we can proceed to run the job. First, make
# the lock file writable, then store the PID
# (of this script) and make sure we delete it
# even if the script gets killed, then we make
# it read-only again so that the lock file
# command doesn't get compromised. The next
# step is to actually execute the program we
# wanted to execute non-concurrently. We retain
# the return value of it (the exit status) to
# pass it on to the calling process when this
# script terminates
chmod +w $LOCKFILE
# the following two lines come from
# http://stackoverflow.com/questions/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at-a
trap "rm -f ${ LOCKFILE } ; exit" INT TERM EXIT
echo $$ > $LOCKFILE
chmod -w $LOCKFILE
$PROGRAM " $@ " ; RETURNVALUE = $?
rm -f $LOCKFILE
exit $RETURNVALUE
}
### actual script starts here
if [ $# -lt 1 ] ; then
usage;
elif [ $1 = -h ] ; then
usage;
elif [ $1 = --help ] ; then
usage;
fi
PROGRAM = $( which $1 )
shift
LOCKFILE = /tmp/$( escapestr $PROGRAM ) _$UID
if lockfile -r 0 $LOCKFILE 2>/dev/null; then
runsubprocess " $@ "
else
# Something went wrong, the lock file
# exists. Now check if it isn't a stale lock:
if kill -0 $( head $LOCKFILE | awk '{ print $1; }' ) 2>/dev/null; then
# The lock is indeed stale:
echo The process is already running. >&2
exit 0
else
# No running process seems to exist, lock
# must be stale, so delete it and run the
# process anew.
echo Trying to remove stale lock. >&2
rm -f $LOCKFILE
if lockfile -r 0 $LOCKFILE 2>/dev/null; then
echo Success. Running process. >&2
runsubprocess " $@ "
else
cat>&2<<EOF
$CMDNAME: Something bad has happened. I was unable
to properly acquire the the lock file
$LOCKFILE. Please investigate.
EOF
exit -1
fi
fi
fi