tags:

views:

167

answers:

2

To compare with diff adjacent records from a file, I created two FIFOs, forked children to supply their write ends, and captured the output of

diff -ub $previous $current

where the scalars contain the FIFOs’ paths—kind of how bash process substitution works.

This is not a program that needs to be bullet-proof, but if it were, how would I create temporary FIFOs so as to avoid race conditions and other vulnerabilities? Imagine File::Temp has a File::Temp::FIFO cousin: what would be the latter's implementation?

+3  A: 

Assuming all the process ends are connected to the FIFOs you created, can't you just remove them from the filesystem? The opened filehandles will keep the FIFO from being deleted, but no new handles could be attached to it, and once the existing filehandles are closed, the FIFO itself will disappear.

zigdon
On Unix, you should be fine - I can't answer for Windows. The other issue I see is does `mkfifo` follow incomplete symlinks? On MacOS X, both the shell command and the system call fail with EEXISTS. Choosing random names for the FIFOs should help, too.
Jonathan Leffler
@zigdon My question centers on creating the FIFOs, but this answer seems to assume them as given. What am I missing?
Greg Bacon
Well, you mentioned in your question that "I created two FIFOs"? Either way, you can create them with the `mkfifo` or `mknod` system commands.
zigdon
@zigdon As with creating temporary files and `open`, creating a temporary FIFO *safely* is more involved than a simple call to `mkfifo`, *cf.* the [source of `File::Temp`](http://cpansearch.perl.org/src/TJENNESS/File-Temp-0.22/Temp.pm).
Greg Bacon
I was addressing the temporary nature of the FIFOs, and getting distracted from the creation part. For that, I believe @Michael's answer might be your best bet - create a safe, temporary directory, and create your FIFOs within it. Since directory creation is atomic, it's easy to use them as locks/race condition busters.
zigdon
+4  A: 

How about creating a temporary directory (a la mkdtemp()) to avoid race conditions, and then put your FIFOs in there?

For example:

use File::Temp qw(tempdir);
use File::Spec::Functions qw(catfile);
use POSIX qw(mkfifo);

my $dir = tempdir(CLEANUP=>1);
my $fifo0 = catfile($dir, "fifo0");
mkfifo($fifo0, 0700) or die "mkfifo($fifo0) failed: $!";
my $fifo1 = catfile($dir, "fifo1");
mkfifo($fifo1, 0700) or die "mkfifo($fifo1) failed: $!";

print "FIFO #0: $fifo0\n";
print "FIFO #1: $fifo1\n";
Michael Krebs
Why two directories? At least twice as much cleanup needed. One directory is sufficient.
Jonathan Leffler
Hmmm.. I was being too clever for my own good. You're right, only one temp directory is necessary.
Michael Krebs
@Michael Don't forget to check that `tempdir` succeeded.
Greg Bacon
tempdir() already die's upon error for me. E.g. If I have it call tempdir(DIR=>"/etc") on Linux, it die's with "Error in tempdir() using /etc/XXXXXXXXXX: Parent directory (/etc) is not writable".
Michael Krebs