peterr has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I've recently moved a website and one Perl script will not work. The previous site had a Unix box with Perl 5.006 , and the new site has a Linux box with Perl 5.006001

After inserting "print" statements all over the place, finally this piece of code is where the script is stopping:

system ("lockfile -2 -r 5 $base_dir/.lock" ) == 0 or diehtml("Lock error: ", $? >> 8, "\n" ); # TODO stop stderr of system

There is no msg appearing (what happened to the "diehtml" ?), the script just stops. I have checked all the path and file permissions, and they are exactly the same s the previous website. The variable $base_dir has a value of '/home/username/public_html/.orders'

The 'shebang' line, etc is:

#!/usr/bin/perl -wT use CGI qw/:standard/; use DBI; # resource limits $CGI:DISABLE_UPLOADS = 1; $CGI::POST_MAX = 1024;

Any clues as to why this is stopping ?

Thanks,

Peter

Replies are listed 'Best First'.
Re: Perl script crashing at lockfile ?
by tachyon (Chancellor) on Oct 01, 2003 at 12:03 UTC

    System is a blocking call. Here is the begining of the man page for lockfile. Does that help?

    lockfile can be used to create one or more semaphore files. If lockfile can't create all the specified files (in the specified order), it waits sleeptime (defaults to 8) seconds and retries the last file that didn't succeed. You can specify the number of retries to do until failure is returned. If the number of retries is -1 (default, i.e., -r-1) lockfile will retry forever.

    So it is not able to create the file and it retries forever. Actually you are setting -2 as the retry interval and trying to set a max of 5 retries so it sould return after 10 seconds but it is not. GOK. Why shell out to create lockfiles anyway? Why not just do it native say like

    sysopen($fh, "$dir/$name", O_CREAT | O_EXCL | O_RDWR, 0600);

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      >>Why shell out to create lockfiles anyway?

      I didn't write it, and I don't know Perl very well at all.

      >>Why not just do it native say like

      sysopen($fh, "$dir/$name", O_CREAT | O_EXCL | O_RDWR, 0600);

      Thanks for supplying the code. I don't know why the person wanted to lock the file. Here is a bigger snippet of what is happening, down to the unlink, which I think is like the "unlock" ??

      system ("lockfile -2 -r 5 $base_dir/.lock") == 0 or diehtml("Lock error: ", $? >> 8, "\n"); # TODO stop stderr of system # create unique suffix if (-f "$base_dir/$seq_file") { open(SEQ, "+<$base_dir/$seq_file") or diehtml("Error opening seq file: $!\n"); $seq = ; seek SEQ, 0, 0; } else { open(SEQ, ">$base_dir/$seq_file") or diehtml("Error creating seq file: $!\n"); $seq = 0; } $outfile .= sprintf "%7.7d", $seq; $ordernumber = $seq; #store this order no. before 'next' is cal +c. print SEQ ++$seq; close SEQ or warn "Something wrong closing seq: $!\n"; unlink "$base_dir/.lock" or diehtml("Unlock error: $!\n"); open(ORDERFILE, ">$outfile") or diehtml("Can't open order records: $!\n"); print ORDERFILE @_; close ORDERFILE or warn "Something fishy with closing the order: $ +!\n"; }

      The file SEQ, is just a line line ASCII file with the next order number in it.

      Peter

        I didn't write it, and I don't know Perl very well at all.

        We know. Regardless you have come to the right place for help.

        The purpose of a lockfile is to tell other processes (ie copies of a CGI) to bugger off and wait their turn.

        Anyway here is a pure Perl replacement that is identical to the lockfile call (well it is not IDENTICAL) because this actually works as the system call to lockfile should....

        my $got_lock; use Fcntl; # to get constants for O_CREAT | O_EXCL | O_RDWR for ( 0 .. 5 ) { if ( sysopen(my $fh, "$base_dir/.lock", O_CREAT | O_EXCL | O_RDWR, + 0600) ) { $got_lock = 1; close $fh; last; } sleep 2; } diehtml("Lock error $!\n") unless $got_lock;

        That should be a cut and paste replacement for this:

        system ("lockfile -2 -r 5 $base_dir/.lock") == 0 or diehtml("Lock error: ", $? >> 8, "\n"); # TODO stop stderr of system

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

        I don't know why the person wanted to lock the file.

        I actually found a post on comp.lang.perl.misc that was from the guy that wrote it; here is his algorithm:

        enter program while (1) look for lockfile if lockfile does not exist exit sleep 5 seconds } create lockfile ..... do normal program stuff ...... unlink lockfile exit

        However, if the process died before removing the lock, it crashed the web server. The post was 7 years ago, so no doubt what has been suggested here will be _much_ better. :)

        Peter

      >>Suggestion. SSH into the shell and deal with your server like a (man/woman/real hacker).

      Okay, I will have to leave it until the morning, it's late here (down under), and the pwd for SSH access is on another computer.

      Possibly the code needs rewriting anyway. Thanks to you all for your help, ... wow, I have never received such fast responses. :)

      Peter

      Hi tachyon,

      Thanks for sorting out the lockfile problem. I will either use this one you supplied

      my $got_lock; use Fcntl; # to get constants for O_CREAT | O_EXCL | O_RDWR for ( 0 .. 5 ) { if ( sysopen(my $fh, "$base_dir/.lock", O_CREAT | O_EXCL | O_RDWR, + 0600) ) { $got_lock = 1; close $fh; last; } sleep 2; } diehtml("Lock error $!\n") unless $got_lock;

      .. or the "fully blown" lockfile code you supplied in your other post ..You either have to delete it by hand or do something like this:

      I consider the lockfile problem sorted out now, thanks. Because of the problems now with "opens", I would to replace code like this:

      open(ORDERFILE, ">$outfile") or diehtml("Can't open order records: $!\n");

      with (native) code of the format:

      sysopen($fh, "$dir/$name", O_CREAT | O_EXCL | O_RDWR, 0600);

      ... would it be something like:

      $fh = "ORDERFILE"; sysopen($fh, "$outfile", O_CREAT | O_EXCL | O_RDWR, 0600) or diehtml("Can't open order records: $!\n");

      Just a wild guess. :)

      Peter

        No :-)

        This code is fine for what it does:

        open # open a file for read or write ( ORDERFILE # onto a FILEHANDLE called ORDERFILE , " > # > means write to the file, create if does not exist # Note all previous content will be deleted # if this file exists >> means append to the end $outfile # full or relative path to file " ) or # if the open works it returns true so we never do the next + bit diehtml() # print an error message

        You don't wanna touch anything in the demon code. It was for illustrative purposes and is not relevant to your problem provided you are happy that the code you have worked just replace the lockfile code.

        In this code:

        $fh = "ORDERFILE"; sysopen($fh, "$outfile", O_CREAT | O_EXCL | O_RDWR, 0600) or diehtml("Can't open order records: $!\n");

        You don't need to set $fh to a string. It will just get overwritten in the open. A FILEHANDLE is a type of perl internal object (like a scalar) and the reference to it is held in the $fh var. To illustrate the syntax:

        open $fh, ">$file" or die "Can't write $file $!\n"; print $fh "here is some data\n"; close $fh;

        Same with sysopen but I can't be bothered to type that much.

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Perl script crashing at lockfile ?
by robartes (Priest) on Oct 01, 2003 at 12:00 UTC
    If by 'stopping' you mean 'just sitting there and doing nothing usefull' (as opposed to 'exiting'), than have a look at the man page for lockfile on your system. The system function does not return until the spawned program, lockfile in this case, returns.

    If your system call is not returning, that means the lockfile process is not returning. Take a look at that.

    File locking is a tricky field that is very susceptible to portability issues. You might have been bitten by one of them.

    CU
    Robartes-

      Hi,

      Yikes, .. I just used CPanel to check on the installed Perl modules, and I couldn't find lockfile or system, so I guess I'm going to have to change the code.

      Thanks,

      Peter

        Whoa, hang on there.

        system is a perl built-in function, so you do not need any modules installed to have it available.

        lockfile is part of your operating system software (well, that's not technically completely accurate, but close enough), so it has nothing to do with Perl in itself.

        Back out of that alley you've gone down and look for the solution in another direction :). Your problem is most probably situated in different behaviour of lockfile between your original and current systems.

        CU
        Robartes-

        lockfile(1) is part of the OS. system() is part of Perl. Neither are Perl modules. Regardless of your lack of understanding of what your code is doing to what and where your analysis of the required actions is correct.

        Suggestion. SSH into the shell and deal with your server like a (man/woman/real hacker).

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Perl script crashing at lockfile ?
by hardburn (Abbot) on Oct 01, 2003 at 14:13 UTC

    You're running under taint mode and don't appear to be setting $ENV{PATH}. You can't execute external programs under taint without setting the PATH env var. Better still is to write the lockfile code in pure Perl.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      You're running under taint mode and don't appear to be setting $ENV{PATH}. You can't execute external programs under taint without setting the PATH env var.

      How do I set $ENV{PATH} , and what should I set it to ?

      Better still is to write the lockfile code in pure Perl.

      The lockfile part of the code is now in pure Perl

      Thanks,

      Peter

        On most *nix systems, the PATH environment var is a colon-delimited list of directories where programs can be executed without specifying the full path. Setting it to /bin:/usr/bin is typical.

        ----
        I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
        -- Schemer

        Note: All code is untested, unless otherwise stated

Re: Perl script crashing at lockfile ?
by peterr (Scribe) on Oct 02, 2003 at 03:37 UTC
    Hi,

    With replacing the code, the script is getting further now. It is stopping or just sitting at the following block of code

    open(ORDERFILE, ">$outfile") or diehtml("Can't open order records: $!\n"); print ORDERFILE @_; close ORDERFILE or warn "Something fishy with closing the order: $ +!\n";

    The value of the variable $outfile has been printed before the above code, and is "/home/username/public_html/.orders/2003-10-01-0001130"

    There were other "open" commands performed successfully, prior to _this_ open stopping ?

    Peter

      Should I replace the following with a 'sysopen' function, like in the locking example ?

      open(ORDERFILE, ">$outfile")

      Peter

        Hi,

        Well, that worked, it has now actually created the ascii order file, and gone much further. Now it is stopping/doing nothing here

        open(SENDMAIL, '|/usr/sbin/sendmail -oi -t') or (unlink ($outfile), diehtml("Can't fork for sendmail: $!\n"));
        So, .... it looks like the moral to this story is replace ALL open() with sysopen(), using the parameters and examples as supplied, to fix the locking example.

        If I used this code as a template for all the file opens

        my $got_lock; use Fcntl; # to get constants for O_CREAT | O_EXCL | O_RDWR for ( 0 .. 5 ) { if ( sysopen(my $fh, "$base_dir/.lock", O_CREAT | O_EXCL | O_RDWR, + 0600) ) { $got_lock = 1; close $fh; last; } sleep 2; } diehtml("Lock error $!\n") unless $got_lock;
        .... would I need the 'sleep', and what does the FOR contruct do ? Does it try for 6 times ?? Please pardon my ignorance, I'm _very_ much a novice at Perl. :)

        Thanks,

        Peter