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

flock monks,

I am working on Windows. My script has a BEGIN block

BEGIN { $0 =~ /^(.*)\\([^\\]*)\.pl$/; our ($path, $prog) = ($1, $2); open(STDERR, ">>$path/$prog.err") or die "invisible error"; warn "$0 started ". localtime() . $/; }

Besides the .err created above, I also have a .log to which I write other conversational stuff.

Further in my code I have a little homespun log rotation snippet. Essentially, if .err or .log filesize is more than a preset value, I move it to a "backlogs" directory (using File::Copy::move) and create a new one.

The script is able to do the above to the .log file, but fails with "Permission denied" error for the .err file. I am guessing that is because the Perl process is not letting go of the .err file.

What can I do to coax the .err file out of the program's hand so that the program can archive it and start another one?

In anticipation...

--

when small people start casting long shadows, it is time to go to bed

Replies are listed 'Best First'.
Re: Getting around a possible file lock
by moot (Chaplain) on Apr 08, 2005 at 18:48 UTC
    The standard way to do this is to close and re-open the file upon receipt of a HUP or other signal. Alternatively your program can watch the file itself, but why re-invent this wheel?
Re: Getting around a possible file lock
by tlm (Prior) on Apr 08, 2005 at 22:15 UTC

    Minimally tested:

    use strict; use File::Basename; errlog_on(); warn "$0 started ". localtime() . $/; warn; errlog_rotate(); warn; # ... { my ( $errlog_file, $orig_stderr ); INIT { our ( $prog, $path ) = fileparse( $0, '.pl' ); $errlog_file = "${path}${prog}.err"; } sub errlog_on { $orig_stderr and defined fileno $orig_stderr or open $orig_stderr, '>&', STDERR or die "Failed to dup STDERR"; open STDERR, '>>', $errlog_file or die "invisible error"; } sub errlog_off { return unless defined fileno STDERR; defined fileno $orig_stderr or die "Can't find original STDERR\n"; close STDERR or die "failed to close $errlog_file"; open STDERR, '>&', $orig_stderr or die "Can't restore STDERR\n"; close $orig_stderr or die "failed to close STDERR dup\n"; } sub errlog_rotate { errlog_off(); log_rotate( $errlog_file ); # backs up $errlog_file # and truncates it; dies # on failure errlog_on(); } }

    Update: Fixed a few bugs. In particular, I followed my own advice and used File::Basename to parse the name of the script (for reasons I did not bother to investigate further, the regex in the original code, which I simply copied for this snippet, was producing wrong values for $path and $prog). Also added a check to ensure that $orig_stderr was defined before applying fileno to it (fileno on undef is fatal).

    the lowliest monk

Re: Getting around a possible file lock
by dmorelli (Scribe) on Apr 08, 2005 at 19:09 UTC
    I know this doesn't answer your question, but using File::Basename::fileparse is a better (and cross-platform) way to parse paths:

    #! /usr/bin/perl -w use strict; use File::Basename; BEGIN { our ($prog, $path) = fileparse $0, '.pl'; open STDERR, ">>$path/$prog.err" or die "invisible error"; warn "$0 started ". localtime() . $/; }