Tuesday, 28 September 2004

Hardlinks 101

It was late, I was tired and needed to keep more than 2 rotated logs of Resin's stderr file. By default it only saves 3: stderr.log (the one it is writing to), stderr.log.1 and stderr.log.2 (the last two most recent copies).

I didn't want to dig through all the documentation and I still don't want to. In fact, the solution I found is still in place. I must confess, the solution wasn't mine, but my from a work colleague of mine, Dom. He is the kind of guy who comes up with the weirdest stuff using named pipes, hardlinks and whatever they stuffed in his head on university classes.

Anyway, he suggested I kept count of the number of hardlinks to the file. As you may well know, the EXT3 filesystem keeps the number of references to a file, and when this number equals 0, the space is marked as free (or, if you prefer, the file is "deleted" - the data is still there, and theoretically you can recover it, but only the gurus at bugtraq know how to do it).

So I came up with this little script, that I believe sums up pretty well the elegance and simplicity of *nix.




if [ ! -r $PH ]; then
echo $PH not found - trying to create link
if [ -r "stderr.log.2" ]; then
ln stderr.log.2 $PH
if [ $? -eq 1 ]; then
echo error trying to create hardlink - bailing out
exit 1


echo stderr.log.2 does not exist yet - bailing out
exit 0

HLCNT=`stat -c %h stderr.log.2`
if [ $HLCNT -eq 1 ]; then
cat $PH >> stderr.$(date +%Y%m%d)
rm -f $PH
ln stderr.log.2 $PH

The first big block of code just checks to see if the placeholder for the stderr.log.2 file already exists. If it then tries to create it.

The real magic happens from HLCNT and beyond. This variable will hold the results of the stat comand, enclosed in ``s, which is the number of hardlinks to the stderr.log.2 file data. This is normally 2: one for the hardlink the script created (and pointed by the file stderr.placeholder) and the other is for the stderr.log.2 file itseld.

When resin rotates the logfile, the hardlink count drops to 1, because now only stderr.placeholder points to the data. That happening, the script then concatenates the file contents to another file, which will hold all the data for the day. VoilĂ . Thanks to my buddy Dom I could go home without reading wads of documentation. :)

No comments: