I don't know quite how to ask this question and I'm not even sure this is the place to ask it. It seems rather complex and I don't have a full understanding of what is going on. Frankly, that's why I'm posting - to get some help wrapping my head around this. My end goal is to learn, not to solve my overall problem. I want to understand when I can expect to encounter the situation I'm about to describe and why it happens.
I have a perl module which I've been developing. One of the things it does is it detects whether there is input on standard in (whether that's via a pipe or via a redirect (i.e. <
)).
To catch redirects, I employ a few different checks for various cases. One of them is looking for 0r
file descriptors in lsof
output. It works fairly well and I use my module in a lot of scripts without issue, but I have 1 use-case where my script thinks it's getting input on STDIN when it is not - and it has to do with what I'm getting in the lsof output. Here are the conditions I have narrowed down the case to, but these are not all the requirements - I'm missing something. Regardless, these conditions seem to be required, but take my intuition with a hefty grain of salt, because I really don't know how to make it happen in a toy example - I have tried - which is why I know I'm missing something:
- When I run a perl script from within a perl script via backticks, (the inner script is the one that thinks it has been intentionally fed input on STDIN when it has not - though I should point out that I don't know whether it's the parent or child that actually opened that handle)
- An input file is supplied to the inner script call that resides in a subdirectory
The file with the 0r
file descriptor that lsof is reporting is:
/Library/Perl/5.18/AppendToPath
This file does not show up in the lsof output under other conditions. And if I do eof(STDIN)
before and after the lsof
call, the result is 1 each time. -t STDIN
is undefined. fileno(STDIN)
is 0
.
I read about this file here and if I cat it, it has:
>cat /Library/Perl/5.18/AppendToPath
/System/Library/Perl/Extras/5.18
It appears this is a macOS-perl-specific file meant to append to the @INC
perl path, but I don't know if other OS's provide analogous mechanisms.
I'd like to know more about when that file is present/opened and when it's closed. Can I close it? It seems like the file content has already been read in by the interpreter maybe - so why is it hanging around in my script as an open file handle? Why is it on STDIN? What happens in this case when I actually redirect a file in myself? Is the child process somehow inheriting it from the parent under some circumstance I'm unaware of?
UPDATE: I figured out a third (possibly final) requirement needed to make that AppendToPath file handle be open on STDIN during script execution of the child script. It turns out I had a line of code at the top of the parent script (probably added to try and solve a similar problem when I knew even less than I know now about detecting input on STDIN) that was closing STDIN. I commented out that close and everything started working without any need to exclude that weird file (i.e. that file: /Library/Perl/5.18/AppendToPath
no longer shows as open on STDIN in lsof). This was the code I commented out:
close(STDIN) if(defined(fileno(STDIN)) && fileno(STDIN) ne '' &&
fileno(STDIN) > -1);
It had a comment above it that read:
#Prevent the passing of active standard in handles to the calls to the script
#being tested by closing STDIN.
So I was probably learning about standard input detection at the time I wrote that years ago. My module probably ended up using -t STDIN
and -f STDIN
, etc, but I'd switched those out to work around a problem like this one using lsof so I could see better what was going on. So with the current module (using either lsof or my new(/reverted?) streamlined version using -t/-f/-p
works just fine (as intended) when I don't close STDIN in the parent.
However, I would still like to understand why that file is on STDIN in a child process when the parent closes STDIN...