[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: nother bash question



On Monday 13 June 2016 13:53:14 Thomas Schmitt wrote:

> Hi,
>
> > ++ /usr/bin/inotifywait -q -e close --format %f /var/spool/mail/
>
> From the man page i learn that you let it watch the whole directory.
> This way you get notifications about any file in there.
>
> The empty variable content possibly stems from this feature:
>   "-format <fmt>
>    ...
>    %f
>    When an event occurs within a directory, this will be replaced with
>    the name of the File which caused the event to occur. Otherwise,
>    this will be replaced with an empty string."
> But i have difficulties to imagine which "close" event could happen
> outside the directory and would still be noticed.
>
> It looks like you can avoid this condition by formatter %w and by
> watching only those mailbox files which you are interested in.
> I'd try this
>
>   /usr/bin/inotifywait -q -e close --format %w \
>                        /var/spool/mail/gene \
>                        /var/spool/mail/gene-from_linda \
>                        /var/spool/mail/amanda
>
> If InMail then contains full paths, like
>
>   /var/spool/mail/amanda
>
> i'd process them by command "basename":
>
>   InMail=$(basename "$InMail")
>
>
> But it seems you have blind time periods in your loop, during which
> inotifywait is not on guard and thus would not catch events.
> Not very reliable.
>
> Maybe you should additionally check the mtime stamps of the mailbox
> files and record them in little data files:
>
>   stamp=$(stat --format=%Y /var/spool/mail/gene)
>   if test "$stamp" -gt "$(cat "$HOME"/timestamp_gene)"
>   then
>      ... something changed in /var/spool/mail/gene ...
>   fi
>
> I have no proposal yet how to avoid processing the mailbox files
> while the fetcher programs are still operating on them.
> (This race condition arises already with your reaction on a reply
>  from inotifywait.)
>
inotifywait does that, only returning with the name when the file has 
been closed.

Now, I've been doing a little cleanup, so here is the current version
to pick apart. It IS working with no errors.
=========================================
#!/bin/bash
# set -x
# this was a test, was /bin/sh above, but /bin/sh is a softlink to /bin/dash
# REQUIRES your distros inotify-tools package, assume kde/kmail in use
# but might be adaptable to other agents too
# requires a ~/log directory, so mkdir it before running it
# you will also need to either do the housekeeping of this file, or
# figure out how to make logrotate do it for you.

WatchDir=/var/spool/mail/

# Setup temporary log
Log=mail.log
Mlog=~/log
# in case it doesn't exist, make it
touch ${Mlog}/${Log}
# the command to send over dbus/dcop to make kmail pull the mailfile
#in /var/spool/mail

# First set method
Method=dcop
if [[ ${Method} = 'dbus' ]]
then
	Cmd="/usr/bin/qdbus org.kde.kmail /KMail org.kde.kmail.kmail.checkMail"
fi
if [[ ${Method} = 'dcop' ]]
then
#or for dcop, use:
	Cmd="/opt/trinity/bin/dcop kmail KMailIface checkMail"
fi

#  Now, do forever
while :
do
	sleep 2
	if [ $(pidof -s kmail) ]
	then
		echo -n "Kmail is running " >>${Mlog}/${Log}
		date -R >>${Mlog}/${Log}
		sleep 1 # delay to give kmail a chance to settle in
		# only start fetchmail once!
		if [ $(pidof -s fetchmail) ]
		then
			sleep 1
			echo "fetchmail already running " >>${Mlog}/${Log}
		else
			echo -n "starting fetchmail at " >>${Mlog}/${Log}
			fetchmail -d 180 -t 60 --fetchmailrc /home/gene/.fetchmailrc >>${Mlog}/${Log} &
			date -R >>${Mlog}/${Log}
		fi
		sleep 1 # delay to give kmail a chance to get its dcop/dbus sockets setup?
		$cmd
		while [ $(pidof -s kmail) ]
		do
			# I've found that stderr needs dumped to /dev/null, so
			InMail=`/usr/bin/inotifywait -q -e close_write --format %f ${WatchDir}` # 2>&1 >/dev/null 		
			# and here it sits until inotifywait exits because of an incoming mail
			# and time later it will exit, setting $InMail to something, so
			# recheck to make sure kmail is still about before sending the signal
			# as dbus/dcop seems to get a tummy ache if there is no receiver

			if test "${InMail}" = "gene"
			then
				$Cmd
				sleep 2
				# log it
				echo -n ${InMail} >>${Mlog}/${Log}
				echo -n " @ " >>${Mlog}/${Log}
				date -R >>${Mlog}/${Log}
			elif test "${InMail}" = "gene-from_linda"
			then
				$Cmd
				sleep 2
				# log it
				echo -n ${InMail} >>${Mlog}/${Log}
				echo -n " @ " >>${Mlog}/${Log}
				date -R >>${Mlog}/${Log}
			elif test "${InMail}" = "amanda"
			then
				$Cmd
				sleep 2
				# log it
				echo -n ${InMail} >>${Mlog}/${Log}
				echo -n " @ " >>${Mlog}/${Log}
				date -R >>${Mlog}/${Log}
			fi

		done
		# we don't have a pidof kmail, log that its gone
		echo -n "Kmails pid is missing - it has stopped ">>${Mlog}/${Log}
		date -R >>${Mlog}/${Log}
		# Now, kill fetchmail too, and this is ok to do
		killall fetchmail
		# get rid of a waiting inotifywait, but this is not inotifywait instance
		# sensitive and may kill the one for cocoprint.
		killall inotifywait
	fi
	# and should be back in the outer loop, waiting for a kmail PID
done

=========================================

> In a newer mail from Gene:
> > fetchmail fires off a session of mailfilter, which can nuke
> > undesirables on the server so fetchmail never sees them, then
> > fetchmail does the pulling, hands it off to procmail for some deaths
> > and diversions, and puts what survives into one of 4 named files in
> > /var/spool/mail/
>
> And you cannot talk any of the participants into performing the
> actions of $Cmd when it knows that the data are ready and no other
> participant is manipulating them ?

I hadn't considered that procmail might be able to do that, which would 
bypass the need for this script.  Lets just say that procmail's recipe 
construction is written in Swahili in its man pages, which it has several 
of by the time you get it all swept into one pkg.  If procmail can do 
that as part of its output recipe, that would be even better, but is it 
capable of checking to see if pidof -s kmail is non-null?  It seems 
likely not, so it would have to launch a wrapper that did check that,

if not null, send the command and return 0, else skip it and return 0

sort of contruction, launched with a trailing & so procmail didn't have
to wait on it.

procmail can't easily do that as the output target is actually specified 
in the .fetchmailrc as the first active line in the file. I have other
tricks in there that can put it in a different location, possibly
overriding the command line "user" it is launched with.  We may play 
with variations on those two recipe's.  But I've other things to do yet
today that aren't internet related at all.  So I'm out of here for a bit.

> Some shell nitpicking:
> > # I've found that stderr needs dumped to /dev/null, so
> > InMail=`/usr/bin/inotifywait -q -e close_write --format %f
> > ${WatchDir}` 2>&1 >/dev/null

That, with the changes made today, seems no longer required.  Historically 
it was because of the warnings and some unwanted line feed noise from 
Inotifywait that it is not now doing with the close_write argument.

> This line consumes stdout of inotifywait, redirects stderr of the
> empty command after the variable assignment to stdout, and redirects
> original stdout to /dev/null. (So if there was stderr output outside
> the ``-quotes it would be shown on stdout.)
> stderr of inotifywait is not redirected by this line.
> See this example which puts "a" on stdout and "b" on stderr:
>
>   $ x=`echo a ; echo b >&2` 2>&1 >/dev/null
>   b
>   $ echo "$x"
>   a
>
> Your comment suggests you want something like
>
>   InMail=`/usr/bin/inotifywait -q -e close_write --format %f
> ${WatchDir} 2>/dev/null`
>
> which redirects stderr of inotifywait to /dev/null.
> Since there is no command after the variable assignment, there is no
> need to redirect its output.
>
My logging in that script leaves something to be desired as to format, 
date it seems, cannot be prevented from issueing a newline, so the 
loging sequence was just redone, but I expect will need and extra 
echo -n " @ " just to put a something between the filename and the date. 
Yup, its all run together. :(

It's rather a kludge, but the logging is neater now, one line per message.

Thank you Thomas

Cheers, Gene Heskett
-- 
"There are four boxes to be used in defense of liberty:
 soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author)
Genes Web page <http://geneslinuxbox.net:6309/gene>


Reply to: