perlaixflock

Flock calls in perl module on AIX systems


I'm trying to make the following project work on AIX systems. I have almost finished, the end is near but I srill have an issue at tha execution of the agent.

My AIX Systems do not have flock installed and that is problematic during the download process in this file

The result of the flock tests all return false

e.g I systematically have the following error message even when I delete the file

[Sat Jun 29 09:47:24 2024][error] [download] /opt/ocsinventory/var/lib/ocsinventory-agent/https:__hostname.com_ocsinventory/download/lock locked. Cannot begin work... :-(

which comes from the following failed flock test


# At the beginning of end handler
sub begin{
    my ($pidfile,$logger) = @_;

    open LOCK_R, "$pidfile" or die("Cannot open pid file: $!");
    if (flock(LOCK_R,LOCK_EX|LOCK_NB)){
        open LOCK_W, ">$pidfile" or die("Cannot open pid file: $!");
        select(LOCK_W) and $|=1;
        select(STDOUT) and $|=1;
        print LOCK_W $$;
        $logger->info("Beginning work. I am $$.");
        return 0;
    } else {
        close(LOCK_R);
        $logger->error("$pidfile locked. Cannot begin work... :-(");
        return 1;
    }
}

I tried to build util-linux 2.40 2.21 and 2.13 and they all fail

I also read here that flock wouldn't be so mandatory on Unix Systems

I think my analysis is good but I'm stuck abour how to implement a fix.

How would you do if you had to make it work. I really need to fix this coode so thhat it becomes compliant with AIX


Solution

  • Try use File::FcntlLock instead of flock. Here is an example:

    flock

    read_shared.pl

    use v5.38;
    use Fcntl ':flock';  # Import LOCK_* constants
    
    my $filename = 'example.txt';
    open(my $fh, '<', $filename) or die "Could not open file '$filename': $!";
    flock($fh, LOCK_SH) or die "Could not lock file '$filename': $!";
    
    # Read from the file
    while (my $line = <$fh>) {
        print $line;
        sleep 1;  # Simulate a long operation
    }
    
    # Close the file (automatically releases the lock)
    close($fh);
    
    print "File has been read with a shared lock.\n";
    

    write_exclusive.pl

    use v5.38;
    use Fcntl ':flock';  # Import LOCK_* constants
    
    my $filename = 'example.txt';
    
    # Open the file for both reading and writing
    # NOTE: Do not open the for writing only, as this will truncate the file before acquiring the lock
    open(my $fh, '+<', $filename) or die "Could not open file '$filename': $!";
    
    # Try to acquire an exclusive lock
    if (flock($fh, LOCK_EX | LOCK_NB)) {
        print "Acquired exclusive lock on file '$filename'.\n";
    
        truncate($fh, 0) or die "Could not truncate file '$filename': $!";
        # Write to the file
        print $fh "Adding a new line to the file.\n";
    
        # Close the file handle (automatically releases the lock)
        close($fh);
    } else {
        print "Could not acquire exclusive lock on file '$filename': $!\n";
    }
    
    print "Attempt to acquire exclusive lock has finished.\n";
    

    File::FcntlLock

    Doing the same with File::FcntlLock:

    read_shared.pl

    use v5.38;
    use File::FcntlLock;
    
    my $filename = 'example.txt';
    
    open(my $fh, '<', $filename) or die "Could not open file '$filename': $!";
    
    my $lock = File::FcntlLock->new(
        l_type => F_RDLCK,
        l_whence => SEEK_SET,  # Lock from the beginning of the file
        l_start => 0,
        l_len => 0,  # Lock the entire file
        l_pid => $$,  # Lock is owned by the current process
    );
    
    # Acquire a shared lock
    $lock->lock( $fh, F_SETLK ) or die "Could not lock file '$filename': $!";
    
    while (my $line = <$fh>) {
        print $line;
        sleep 1;  # Simulate a long operation
    }
    
    # Close the file (automatically releases the lock)
    close($fh);
    
    print "File has been read with a shared lock.\n";
    

    write_exclusive.pl

    use v5.38;
    use File::FcntlLock;
    use Fcntl qw(SEEK_SET);
    
    my $filename = 'example.txt';
    
    # Open the file for both reading and writing without truncating it
    # NOTE: Do not open the for writing only, as this will truncate the file before acquiring the lock
    open(my $fh, '+<', $filename) or die "Could not open file '$filename': $!";
    
    # Create a File::FcntlLock object
    my $lock = File::FcntlLock->new(
        l_type => F_WRLCK,
        l_whence => SEEK_SET,  # Lock from the beginning of the file
        l_start => 0,
        l_len => 0,  # Lock the entire file
        l_pid => $$,  # Lock is owned by the current process
    );
    
    # Try to acquire an exclusive lock in non-blocking mode
    if ($lock->lock( $fh, F_SETLK )) {
        print "Acquired exclusive lock on file '$filename'.\n";
    
        # Truncate the file
        truncate($fh, 0) or die "Could not truncate file '$filename': $!";
    
        print $fh "Adding a new line to the file.\n";
        
        # Close the file handle (automatically releases the lock)
        close($fh);
    } else {
        print "Could not acquire exclusive lock on file '$filename': $!\n";
    }
    
    print "Attempt to acquire exclusive lock has finished.\n";