If I do (in a Bourne-like shell):
exec 3> file 4>&3 5> file 6>> file
File descriptors 3 and 4, since 4 was dup()ed from 3, share the same open file description (same properties, same offset within the file…). While file descriptors 5 and 6 of that process are on a different open file description (for instance, they each have their own pointer in the file).
Now, in lsof output, all we see is:
zsh 21519 stephane 3w REG 254,2 0 10505865 /home/stephane/file zsh 21519 stephane 4w REG 254,2 0 10505865 /home/stephane/file zsh 21519 stephane 5w REG 254,2 0 10505865 /home/stephane/file zsh 21519 stephane 6w REG 254,2 0 10505865 /home/stephane/file
It’s a bit better with lsof +fg:
zsh 21519 stephane 3w REG W,LG 254,2 0 10505865 /home/stephane/file zsh 21519 stephane 4w REG W,LG 254,2 0 10505865 /home/stephane/file zsh 21519 stephane 5w REG W,LG 254,2 0 10505865 /home/stephane/file zsh 21519 stephane 6w REG W,AP,LG 254,2 0 10505865 /home/stephane/file
(here on Linux 3.16) in that we see fd 6 has different flags, so it has to be a different open file description from the one on fd 3, 4 or 5, but from that we can’t tell fd 5 is on a different open file description. With -o, we could also see the offset, but again same offset doesn’t guarantee it’s the same open file description.
Is there any non-intrusive1 way to find that out? Externally, or for a process’ own file descriptors?
1. One heuristic approach could be to change the flags of one fd with fcntl() and see what other file descriptors have their flags updated as a result, but that’s obviously not ideal nor fool proof
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
For Linux 3.5 and onward, this can be accomplished with kcmp(2):
KCMP_FILE
- Check whether a file descriptor idx1 in the process pid1 refers to the same open file description (see open(2)) as file descriptor idx2 in the process pid2. The existence of two file descriptors that refer to the same open file description can occur as a result of dup(2) (and similar) fork(2), or passing file descriptors via a domain socket (see unix(7)).
The man page provides an example specifically for the use case OP asked. Note that this syscall requires the kernel be compiled with CONFIG_CHECKPOINT_RESTORE set.
Method 2
What you’re looking to compare are the struct file pointers that the file descriptors point to. (Inside the kernel is one task_struct data structure for each thread. It contains a pointer to another structure called the files_struct. And that structure contains an array of pointers, each one to a struct file. It’s the struct file that holds the seek offset, the open flags, and a few other fields.)
I don’t know of any user-visible way to see the pointers in the files_struct other than the use of some intrusive tools. For example, SystemTap could be given a PID and it could find the corresponding task_struct and follow the pointers. If you’re looking for passive, though, I think that’s about it. Dell released a tool a long time ago called KME (Kernel Memory Editor) that gave a spreadsheet-like interface to live kernel memory and it could do what you want, but it was never ported to 64-bit. (I tried and never got it completely working, and wasn’t sure why.)
One reason you’re not finding lsof to be helpful is that it doesn’t see those pointers either (but look at the +f option for non-Linux systems). You could theoretically compare all of the fields in the struct file and think the two structures are the same, yet they could still be from separate open(2) calls.
Take a look at the pfiles SystemTap script for ideas. If you modified it to print the address of the struct file, you’d have your solution. You might also check opened_file_by_pid.stp since there’s a function in it that walks the files_struct, ie. the file descriptor table, looking at the struct file objects…
Might I ask what you’re trying to accomplish?
Method 3
Here is a linux specific solution: /proc/self/fd is a directory of symbolic links for open file handles in the current process. You can just compare the link values. It gets more complicated when using a child process, because the child will have a different /proc/self because it is a pid dependant symbolic link. You can workaround this problem by using /proc/$$/fd where $$ is the desired pid.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0