For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > March 2008 > flock - exclusive file locking









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author flock - exclusive file locking
Dermot

2008-03-17, 7:08 pm

Hi,

I have a cgi script that writes to a disk file. It would be safest if I can
get an exclusive lock on the file. I had a look at the opentut and believe I
have followed that the example there. Here's what I have

sysopen my $fh, $file_path, O_WRONLY || die "can't open
$file_path: $!\n";
flock($fh,LOCK_EX) or die "can't lock $file_path: $!\n";
s($fh, 0, 2); # Append to file
print $fh $status."\n";
print STDERR "$0: $! $?\n";
close($fh);

I am getting the error
"Inappropriate ioctl for device 0"

The worst part about this problem is that it seems completely erratic.
Sometimes the string is written to the file and sometimes not. Sometimes I
get an error and sometimes not but it never dies and the user will think the
data has been written to file! Does anyone see something wrong with the
snippet above or have any insights on file-clocking they could offer.

Thanx,
Dp.

Dr.Ruud

2008-03-17, 7:08 pm

Dermot schreef:

> sysopen my $fh, $file_path, O_WRONLY
> || die "can't open $file_path: $!\n";


Change or-operator (or use parenthesis).

--
Affijn, Ruud

"Gewoon is een tijger."
Gunnar Hjalmarsson

2008-03-17, 7:08 pm

Dermot wrote:
> I have a cgi script that writes to a disk file. It would be safest if I can
> get an exclusive lock on the file. I had a look at the opentut and believe I
> have followed that the example there. Here's what I have
>
> sysopen my $fh, $file_path, O_WRONLY || die "can't open
> $file_path: $!\n";
> flock($fh,LOCK_EX) or die "can't lock $file_path: $!\n";
> s($fh, 0, 2); # Append to file
> print $fh $status."\n";
> print STDERR "$0: $! $?\n";
> close($fh);
>
> I am getting the error
> "Inappropriate ioctl for device 0"


Even if I can't reproduce that error, I see one thing that is not correct.

> sysopen my $fh, $file_path, O_WRONLY || die ...


That is interpreted as

sysopen my $fh, $file_path, (O_WRONLY || die ... )

i.e. the script will never die at that line, since the constant O_WRONLY
is always true. You need to do either

sysopen( my $fh, $file_path, O_WRONLY ) || die ...
-----------^------------------------------^

or

sysopen my $fh, $file_path, O_WRONLY or die ...
-----------------------------------------^^

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
John W. Krahn

2008-03-17, 7:08 pm

Dermot wrote:
> Hi,


Hello,

> I have a cgi script that writes to a disk file. It would be safest if I can
> get an exclusive lock on the file. I had a look at the opentut and believe I
> have followed that the example there. Here's what I have
>
> sysopen my $fh, $file_path, O_WRONLY || die "can't open $file_path: $!\n";


You are using the high precedence '||' operator which means that
O_WRONLY is ORed with die() before sysopen() is called and since
O_WRONLY is probably always true then die() will *never* be called.

You intend to append to the file so you should probably also include
O_APPEND with the third argument.

You want to either use parentheses:

sysopen( my $fh, $file_path, O_WRONLY | O_APPEND ) || die "can't open
$file_path: $!\n";

Or use the low precedence 'or' operator:

sysopen my $fh, $file_path, O_WRONLY | O_APPEND or die "can't open
$file_path: $!\n";


> flock($fh,LOCK_EX) or die "can't lock $file_path: $!\n";
> s($fh, 0, 2); # Append to file


It looks like you are using the Fcntl.pm module to get the LOCK_EX macro
so you should use it to get the SEEK_END macro as well. And since you
are using sysopen() to open the file you should use syss() instead of
s()

syss $fh, 0, SEEK_END or die "can't s on $file_path: $!\n";

Although you don't really need to do this if you use O_APPEND with
sysopen().


> print $fh $status."\n";
> print STDERR "$0: $! $?\n";


It makes no sense to print the values of $! or $? unless *an* *error*
*actually* *occured*. Without an actual error the values in them will
be meaningless.


> close($fh);
>
> I am getting the error
> "Inappropriate ioctl for device 0"


That error message is not listed in perldiag.pod so it is not a Perl
error/warning and it doesn't match any of the error messages in your
code above so something other than your Perl program is producing it.

perldoc perldiag


> The worst part about this problem is that it seems completely erratic.
> Sometimes the string is written to the file and sometimes not. Sometimes I
> get an error and sometimes not but it never dies and the user will think the
> data has been written to file! Does anyone see something wrong with the
> snippet above or have any insights on file-clocking they could offer.


perldoc -q lock



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall
Chas. Owens

2008-03-18, 7:03 pm

On Mon, Mar 17, 2008 at 4:47 PM, Dermot <paikkos@googlemail.com> wrote:
snip
> print $fh $status."\n";
> print STDERR "$0: $! $?\n";

snip

$? holds the status returned by the last external call (call to
system() function, pipes, qx// operator, call to wait() or waitpid(),
or possibly the gethost*() functions), but you are not making an
external call in your code, so it is inappropriate to be checking its
value.

$! is not gaurenteed to have a valid value unless an error code has
been returned by the last function called, so unless print has an
error $! could be anything (and often is something weird).

from perldoc perlvar
$? The status returned by the last pipe close, backtick ('')
command, successful call to wait() or waitpid(), or from the
system() operator. This is just the 16$B!](Bbit status word
returned by the wait() system call (or else is made up to look
like it). Thus, the exit value of the subprocess is really
("$? >> 8"), and "$? & 127" gives which signal, if any, the
process died from, and "$? & 128" reports whether there was a
core dump. (Mnemonic: similar to sh and ksh.)

Additionally, if the "h_errno" variable is supported in C, its
value is returned via $? if any "gethost*()" function fails.

If you have installed a signal handler for "SIGCHLD", the value
of $? will usually be wrong outside that handler.

Inside an "END" subroutine $? contains the value that is going
to be given to "exit()". You can modify $? in an "END"
subroutine to change the exit status of your program. For
example:

END {
$? = 1 if $? == 255; # die would make it 255
}

Under VMS, the pragma "use vmsish 'status'" makes $? reflect
the actual VMS exit status, instead of the default emulation of
POSIX status; see "$?" in perlvms for details.
snip
$! If used numerically, yields the current value of the C "errno"
variable, or in other words, if a system or library call fails,
it sets this variable. This means that the value of $! is
meaningful only immediately after a failure:

if (open(FH, $filename)) {
# Here $! is meaningless.
...
} else {
# ONLY here is $! meaningful.
...
# Already here $! might be meaningless.
}
# Since here we might have either success or failure,
# here $! is meaningless.

In the above meaningless stands for anything: zero, non$B!>(Bzero,
"undef". A successful system or library call does not set the
variable to zero.

If used as a string, yields the corresponding system error
string. You can assign a number to $! to set errno if, for
instance, you want "$!" to return the string for error n, or
you want to set the exit value for the die() operator.
(Mnemonic: What just went bang?)

--
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com