From: Ben Morrow on

Quoth Vilmos Soti <vilmos(a)soti.ca>:
> PerlFAQ Server <brian(a)theperlreview.com> writes:
>
> > 5.35: How do I close a file descriptor by number?
> >
> > If, for some reason, you have a file descriptor instead of a filehandle
> > (perhaps you used "POSIX::open"), you can use the "close()" function
> > from the "POSIX" module:
>
> I have a related question:
>
> How do I find all the open file descriptors so I can close them?

There is no way to do this in general, short of calling _exit(2) (or
something else that calls _exit, like Perl's exit). One crude way is
something like

POSIX::close $_ for 3..1024;

for some suitably large value of '1024'; most systems have some sort of
limit on the maximum possible fd, so check your system documentation.

Ben

From: C.DeRykus on
On Apr 21, 11:09 am, Vilmos Soti <vil...(a)soti.ca> wrote:
> "Peter J. Holzer" <hjp-usen...(a)hjp.at> writes:
>
> > But it looks like you care about Perl handles anyway, not about file
> > descriptors.
>
> Well, yes.
>
> > and then wrap the copy operations into an eval block:
>
> I guess the solution in this case is to use eval, and there no
> sane way to have a list of file descriptors.

Another possibility, although not particularly efficient,
is just redefine the handler to not interrupt the copy
and run bye() in an END{}:

#!/usr/bin/perl

my $INT = 0;
...

my $find_code =
sub { local $SIG{INT} = sub { $INT = 1; };
copy ...;
exit if $INT
};
...

END { bye; }

--
Charles DeRykus
From: Peter J. Holzer on
On 2010-04-20 20:41, Vilmos Soti <vilmos(a)soti.ca> wrote:
> J�rgen Exner <jurgenex(a)hotmail.com> 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
From: Ben Morrow on

Quoth "Peter J. Holzer" <hjp-usenet2(a)hjp.at>:
>
> 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.

File::Copy (at least, v2.14, which comes with 5.10.1) uses

my $fh = \do { local *FH };

which is how you created a scoped filehandle before 5.6. At least in
modern perls, these handles will also auto-close on scope exit.

Ben

From: Vilmos Soti on
"Peter J. Holzer" <hjp-usenet2(a)hjp.at> writes:

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

Well, yes.

> and then wrap the copy operations into an eval block:

I guess the solution in this case is to use eval, and there no
sane way to have a list of file descriptors.

Thanks for everybody, Vilmos