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

Hey all,

Apologies in advance for my second question of the day, however having been a lurker of perlmonks for years, I thought I'd bite the bullet and make more use of the resources available. Twice. In one day.

My question is: how can I check whether a directory handle has been closed or not?

The reason I ask is that I've written a common module for use in my scripts which attempts to cleanup any open file or directory handles before the script exits. This means that I have methods like openFile() which pushes the filehandle into an array which I can then iterate over at a later point (i.e when cleanup() is called) to ensure that the filehandle was indeed closed.

For example:

sub openFile { my ($filename, $mode) = @_; use FileHandle; my $filehandle = FileHandle->new($filename,$mode); if (defined $filehandle) { push(@openedFileHandles, $filehandle); return $filehandle; } return 0; }

and I open my files like

my $logfile = openFile("application.log",">>");

From reading various nodes on perlmonks, I picked up that I can check if a filehandle is open/present by using fileno(), so this lets me do something like

foreach my $filehandle (@openedFileHandles) { if (fileno($filehandle)) { $filehandle->close(); } }

when I'm cleaning up.

But I get the impression that fileno() doesn't work for directory handles. If that is the case, how can I check if a directory handle is still open or present?

I'm opening directories in a similar fashion to openFile(), except using DirHandle instead of FileHandle

Any thoughts appreciated. Actually, if anyone has any suggestions on what a good cleanup module should do, or whether there is something like this already available, that'd also be extremely helpful information.

Replies are listed 'Best First'.
Re: Cleaning up filehandles and directoryhandles
by ikegami (Patriarch) on Aug 10, 2005 at 05:10 UTC
    But I get the impression that fileno() doesn't work for directory handles.

    So don't use it. close the filehandle unconditionally. If it's already closed, close may indicate an error by returning false, which you can ignore. In fact, you already ignore errors returned by close.

    $_->close() foreach @openedFileHandles;

    On the more general topic, this seems like a whole lot of work for something that should be handled by scope. File and directory handles are automatically closed when they go out of scope. It's much easier and safer to limit the scope of the handles than doing what you are attempting.

    and I open my files like

    And finally, it's very poor design for openFile's arguments to be in the reverse order of open's. Seeing that erodes my trust in the module, to say the least.

      So don't use it. close the filehandle unconditionally.

      Fair enough. I was trying to find a correct way to do things (in admist what seems to be a few mistakes). It doesn't exactly feel right that there is a method for checking if a file is open, but not a directory, and that it's good form to just close on everything, even if it isn't actually open.

      And finally, it's very poor design for openFile's arguments to be in the reverse order of open's. Seeing that erodes my trust in the module, to say the least.

      A fair call. The reversed order of openFile's arguments was done to match the order of argument's to FileHandle->new(). Thanks for the advice and I'll take a 'bigger picture' approach and match up openFile() to open().

Re: Cleaning up filehandles and directoryhandles
by graff (Chancellor) on Aug 10, 2005 at 01:44 UTC
    Um, last time I checked, issuing a "close" call on a file handle that is already closed is not an error, and it doesn't even generate a warning. It just ends up being equivalent to a no-op. Ditto for "closedir" on directory handles.

    So why worry about whether the handle is already closed before you do clean-up?

      I'm not sure, but I'm going to hazard a guess.

      I do know that if you open a filehandle to some device, and then you execute another program (via system, exec, whatever), the filehandle remains open and the new process can use it. This is what allows us to set up pipes so that stdin and stdout of a subprocess are regular files to the parent, etc.

      However, I'm not so sure if that holds true for dir handles. Looking at the opendir (3) manpage, there is a "file descriptor" associated here, so it may be true here, too.

      What does this have to do with exit? Very little. In fact, nothing. But if you have the cleanup routine, you could do something like this:

      sub system_no_filehandles { my $pid = fork(); if ($pid) { waitpid($pid, 0); return $? } cleanup_all_filehandles(); cleanup_all_dirhandles(); exec(@_); }
      The subprocess will not have any of the files or directories opened, thus the file descriptor table will be as clean as possible for that child. I've had cases where this has been important - I've had to write wrappers (in C at the time) where I'd just loop through all file descriptors from 3 to 255, closing each one, and then exec'ing the next process which needs way too many files opened at a time, but was failing for lack of descriptors. So this technique can be quite useful, but it requires discipline up front to manage the list - it's not something that's easy to add later.

        I do know that if you open a filehandle to some device, and then you execute another program (via system, exec, whatever), the filehandle remains open and the new process can use it.

        Perl automatically sets the close-on-exec flag (if available on the system) for all descriptors above 2, so exec'd programs should never inherit them. (See $^F in perlvar, F_SETFD in fcntl(2).)

      Only because I didn't want to perform a close unnecessarily. Also because I was trying to learn and possibly implement some good practise by ensuring that anything opened was noted as being opened, and anything noted as being opened was closed.

      It seems a bit amiss that there's no simple way (mentioned so far) to tell if the directory handle is actually open or not.

      Cheers for your help! Most appreciated.

Re: Cleaning up filehandles and directoryhandles
by anonymized user 468275 (Curate) on Aug 10, 2005 at 09:12 UTC
    I was once faced with a similar problem, but it occurred to me that prevention was better than cure. Code demonstrating that approach can be found here Re: Counting open files?

    One world, one people