in reply to detecting directory in perl

This operation:

open CRONTABFILE, '>crontab'; flock CRONTABFILE, 2;

...is a potentially catastrophic bug waiting to happen, and it's repeated on a couple of different files in your sample script. You are opening crontab in write mode. More specifically, write-and-truncate mode. Imagine this sequence of events:

  1. Someone opens the crontab file and gets a lock on it.
  2. You open the file in clobber mode, clobbering the file.
  3. You fail to get a lock because someone else already had one.
  4. You've now clobbered a file someone else has a lock on.

MJD likens this scenario to taking a dump on someone's front porch and then ringing the doorbell to ask for tissue.

If you wish to obtain a lock on the crontab file, you will need to open it in a mode that doesn't clobber it before you ever get the lock. < or +< would be a reasonable approach if you are certain the file already exists. If you do not have such a guarantee, and you don't mind not knowing for sure whether or not you created the file, you could use +>> and then truncate and seek after obtaining the lock. A common idiom would also be to open and lock the target, then open a tempfile with a sufficiently randomized name (see File::Temp, do your writing there, and then rename or move the tempfile into place over the output file. The move becomes an atomic operation, which is about the least risky approach if you aren't guaranteed that other actors aren't occasionally touching the same file without proper locking.

Updated to reflect the order I intended to describe in the first place but managed to still present out of order when I typed in my thoughts (thanks MidLifeXis).

Also see http://www.plover.com/~mjd/perl/yak/flock/


Dave

Replies are listed 'Best First'.
Re^2: detecting directory in perl
by MidLifeXis (Monsignor) on Sep 09, 2016 at 14:43 UTC

    A common idiom would also be to open a tempfile with a sufficiently randomized name (see File::Temp, do your writing there, and then after obtaining a lock on the output file, rename or move the tempfile into place over the output file. (emphasis added)

    Race condition waiting to happen (at least as I am reading your statement). Have the lock signal the ability to modify the file (lock first, write second). If you don't lock first, you risk clobbering someone else's changes:

    • You create a tmp file
    • They create a tmp file
    • They lock
    • They overwrite
    • They unlock
    • You lock
    • You overwrite
    • You unlock
    The changes made by "They" are now gone. Lock before read just to ensure that you have the newest data. Otherwise, I agree.

    --MidLifeXis

      You lock the target before creating a temp, and as a final step move the temp in place over the target. If you fail to get a lock on the target to begin with, stop there.

      After re-reading my post I see that my words didn't reflect the process I had in my head when I wrote them. I've updated. Thanks for noticing and bringing it to my attention! :)


      Dave