lock.pl for BSD and Linux

Michael Chaney mdchaney at MICHAELCHANEY.COM
Mon May 20 17:22:11 IST 2002


I'm not sure if I've sent this along before, so here it is.

Here's the lock.pl that I use for FreeBSD, works with Linux also.  With
some minor modifications, it should be trivial to make it work with any
Unix system out there.

Michael
--
Michael Darrin Chaney
mdchaney at michaelchaney.com
http://www.michaelchaney.com/
-------------- next part --------------
#   MailScanner - SMTP E-Mail Virus Scanner
#   Copyright (C) 2001  Julian Field
#
#   $Id: lock.pl,v 1.4 2001/08/10 12:53:44 jkf Exp $
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#   The author, Julian Field, can be contacted by email at
#      Jules at JulianField.net
#   or by paper mail at
#      Julian Field
#      Dept of Electronics & Computer Science
#      University of Southampton
#      Southampton
#      SO17 1BJ
#      United Kingdom
#

# Provide functions to deal with opening + locking spool files

package Lock;

use strict;
use Fcntl qw(:DEFAULT :flock);
use POSIX qw(:unistd_h :errno_h);

# Open and lock a file.
#
# Pass in a filehandle, a filespec (including ">", "<", or
# whatever on the front), and (optionally) the type of lock
# you want - "r" or "s" for shared/read lock, or pretty much
# anything else (but "w" or "x" really) for exclusive/write
# lock.
#
# Lock type used (flock or fcntl/lockf/posix) depends on
# config. If you're using posix locks, then don't try asking
# for a write-lock on a file opened for reading - it'll fail
# with EBADF (Bad file descriptor).
#
sub openlock {
    my ($fh, $fn, $rw) = @_;

    my ($locktype,$struct_flock);

    $locktype = ($Config::LockType)?
      $Config::LockType : $MTA::LockType;

    defined $rw or $rw = ((substr($fn,0,1) eq '>')?"w":"r");
    $rw =~ /^[rs]/i or $rw = 'w';

    unless (open($fh, $fn)) {
        Log::InfoLog("Could not open file $fn: %s", $!);
        return 0;
    }

    if ($locktype =~ /posix/i) {
        # HORRIBLY HARDWIRED
        # would like to "use File::lockf" but that would make
        # installation harder.
        #
        # I guess the pack() is not too bad so long as most parms
        # are zero ;)
        #
        # I've seen sslls, ssllll and all sorts used there...
        # ...not too sure what the best most portable way is :(
        #
        Log::DebugLog("Using fcntl() to lock $fn");
        #$struct_flock =  pack('ssx32',($rw eq 'w' ? F_WRLCK : F_RDLCK),0);
        $struct_flock =  struct_flock(($rw eq 'w' ? F_WRLCK : F_RDLCK),SEEK_SET,0,0,0);
        fcntl($fh, F_SETLK, $struct_flock) and return 1;
    }
    elsif ($locktype =~ /flock/i) {
        Log::DebugLog("Using flock() to lock $fn");
        flock($fh, ($rw eq 'w' ? LOCK_EX : LOCK_SH) + LOCK_NB) and return 1;
    }
    else {
        Log::DebugLog("Not locking spool file $fn");
        return 1;
    }

    print "Couldn't lock $fn: $!\n";

    close ($fh);

    Log::DebugLog("Failed to lock $fn: %s", $!);

    return 0;
}


sub unlockclose {
    my ($fh) = @_;

    my $locktype;

    $locktype = ($Config::LockType)?
      $Config::LockType : $MTA::LockType;

    if ($locktype =~ /posix/i) {
        #fcntl($fh, &F_SETLK, pack('sslls',&F_UNLCK,0,0,0,0));
        fcntl($fh, F_SETLK, struct_flock(F_UNLCK,0,0,0,0));
    }
    elsif ($locktype =~ /flock/i) {
        flock($fh, LOCK_UN);
    }
# else {
#   default - do nothing, as we didn't lock it in the first place
# }

    close ($fh);
    return 1;
}

BEGIN {
        my $FLOCK_STRUCT = 'S s L L I';
        sub linux_flock {
                if (wantarray) {
                        my ($type, $whence, $start, $len, $pid) =
                                unpack($FLOCK_STRUCT, $_[0]);
                        return ($type, $whence, $start, $len, $pid);
                } else {
                        my ($type, $whence, $start, $len, $pid) = @_;
                        return pack($FLOCK_STRUCT,
                                        $type, $whence, $start, $len, $pid);
                }
        }
}

BEGIN {
# XXX: should be Q not LL
        my $FLOCK_STRUCT = 'LL LL L l s';

        sub bsd_flock {
                if (wantarray) {
                        my ($xxstart, $start, $xxlen, $len, $pid, $type, $whence) =
                                unpack($FLOCK_STRUCT, $_[0]);
                        return ($type, $whence, $start, $len, $pid);
                } else {
                        my ($type, $whence, $start, $len, $pid) = @_;
                        my ($xxstart, $xxlen) = (0,0);
                        return pack($FLOCK_STRUCT,
                                        $xxstart, $start, $xxlen, $len, $pid, $type, $whence);
                }
        }
}

BEGIN {
        for ($^O) {
                if    (/bsd/)   { *struct_flock = \&bsd_flock       }
                elsif (/linux/) { *struct_flock = \&linux_flock    }
                else {
                        die "unknown operating system: $!";
                }
        }
}


1;


More information about the MailScanner mailing list