file locking

Joshua Goodall joshua at roughtrade.net
Sun Jan 20 22:13:28 CST 2002


On Mon, Jan 21, 2002 at 11:47:34AM +1100, Paul Fenwick wrote:
> If you're doing the access over NFS, then despair.  NFS makes
> file locking exceedingly difficult.

It isn't insurmountable. I've attached some sample code of how I
do it. It does require a working lockd, and of course there's NFS's
usual failure-modes to cope with.

Cheers, Joshua.
-------------- next part --------------
#!/usr/bin/perl

# fcntldemo
# NFS lockd-safe locking with fcntl
# demo code by Joshua Goodall <joshua at myinternet.com.au>

# * compatible with C library fcntl, lockf and (locally, not nfs) flock
# * also works on ext2/ufs mounts
# * fcntl can also lock file ranges
# * beware that locking is advisory, not mandatory


use IO::File;
use Fcntl;

use strict;
use vars qw($fh $filename $basename);
$basename = ($0 =~ /([^\/]+)$/)[0] || "fnctldemo";

sub usage () {
	print STDERR "usage: $basename outputfile [inputfile ...]\n";
	exit 1;
}
sub fatal ($) {
	print STDERR "$basename: $_[0]\n";
	exit 2;
}

# the meat

sub lockf ($$) {
	my ($fh, $mode) = @_;
	my $params;

	die "bad mode \"$mode\" to lockf" unless $mode =~ /^[rw]$/;

	$params = pack("ssx32", ($mode eq "r" ? F_RDLCK : F_WRLCK), 0);
	return fcntl($fh, F_SETLKW, $params);
}

sub unlockf ($) {
	my $fh = shift;
	my $params;

	$params = pack("ssx32", F_UNLCK, 0);
	return fcntl($fh, F_SETLKW, $params);
}


# the cutlery

usage unless scalar @ARGV;

$filename = shift @ARGV;
$fh = new IO::File;
open ($fh, ">$filename") or fatal "can't open $filename for output: $!";
lockf ($fh, "w") or fatal "can't lock $filename: $!";

# prevent overwrite corruptions following lock race;
# comment this out for entertainment value
truncate($fh, 0);

print "got lock; enter data\n";
while (<>) {
	chomp;
	print $fh "$$: $_\n";
}

unlockf ($fh) or die "can't unlock $filename: $!";
close $fh;


More information about the Melbourne-pm mailing list