Re: FAQ 5.35 How do I close a file descriptor by number?



On 2010-04-20 20:41, Vilmos Soti <vilmos@xxxxxxx> wrote:
Jürgen Exner <jurgenex@xxxxxxxxxxx> writes:

How do I find all the open file descriptors so I can close them?

I have a program which basically does this (runs on Unix):
[...]
The problem is that if the user hits Ctrl-C in the middle of the copy,
the open file descriptors on /mnt/cdrom will prevent umounting and
ejecting.

AFAIR file descriptors are closed automatically when they go out of
scope.

File descriptors are handled by the OS. They don't go out of scope until
the process exits (or execs, if they are marked "close on exec").

But it looks like you care about Perl handles anyway, not about file
descriptors.



So scope them correctly and you shouldn't have any problems.

How do I do this?

Here is an actual (and running) perl program which demonstrates this problem:

---------------------- code starts ---------------------
#!/usr/bin/perl

use File::Copy;
use File::Find;

my $find_code = sub {
copy ($File::Find::name, "/dev/null") if -f $File::Find::name;
};

sub bye () {
system ("/bin/umount /mnt/cdrom");
system ("/usr/bin/eject /mnt/cdrom");
exit;
}

$SIG{INT} = \&bye;

Here is the problem. You are calling bye() as a signal handler, so it is
called while the process is still busy copying files.

Instead you could just die in the signal handler:

$SIG{INT} = sub { die "interrupted" }

and then wrap the copy operations into an eval block:

system ("/usr/bin/eject -t /mnt/cdrom"); # close the cd tray
system ("/bin/mount /mnt/cdrom");

print "copy starts\n";
find ( { wanted => $find_code, follow => 0, no_chdir => 1 }, "/mnt/cdrom");
print "copy ends\n";

eval {
print "copy starts\n";
find ( { wanted => $find_code, follow => 0, no_chdir => 1 }, "/mnt/cdrom");
print "copy ends\n";
};
if ($@) {
print "caught exception: $@\n";
}

bye;

Then, when you press Ctrl-C, perl will cleanly abort whatever it is
doing (freeing any container[1] which goes out of scope) and jump to the
end of eval block. Finally, bye is called, just as if the block had
been processed normally.


The problem with this approach is that it will only close lexical file
handles. Bareword filehandles never go out of scope, so they won't be
closed. And I haven't checked now, but I'm almost sure that File::Copy
uses bareword filehandles, simply because it is older than lexical
filehandles.


Basically I would like something like this in the bye function:

foreach (@OPEN_FILE_DESCRIPTORS) {
next if stdin or stdout or stderr;
close $_;
}

The question is ... how can I get a list of open file descriptors.

I don't think you can get them. You could uswe the same approach as in
C: Simply calling POSIX::close on all filedescriptors between 3 and some
maximum.

hp
.



Relevant Pages