[comp.unix.wizards] Getting the pathname from a FILE*.

karl@umb.umb.edu (Karl Berry.) (07/09/88)

The title says it all. Am I missing something obvious?
The pathname doesn't seem to be a field in either the
_iobuf or the structure returned by stat.
ttyname or ctermid will give you the pathname
of your terminal, but I want the pathname of an
arbitrary FILE* I have fopen. Or am I missing some
reason why this is not feasible?

Karl.
karl@umb.edu     ...!harvard!umb!karl

gandalf@csli.STANFORD.EDU (Juergen Wagner) (07/09/88)

The _iobuf structure as defined in <stdio.h> includes a component _file
which is supposed to hold the file descriptor number. With fdopen() you
can create a FILE* structure from an arbitrary file descriptor (which
may refer to a UNIX file, a socket, or whatsoever), so the FILE* structure
may access something else than a plain UNIX file.

fstat(fd, &statbuf) gives information about the open file descriptor, so
you can find out the device the inode is on, the inode's number, and a 
few other attributes of interest. With that you should be able to find
out the information wanted by looking at the st_mode field (check the 
fd type), and eventually by walking through the file system the inode is
on.

I know, it's a painful procedure but as far as I know, there is no other
way to obtain the information you're looking for, other than by fiddling
around with statbuf.

-- 
Juergen "Gandalf" Wagner,		   gandalf@csli.stanford.edu
Center for the Study of Language and Information (CSLI), Stanford CA

budd@bu-cs.BU.EDU (Philip Budne) (07/09/88)

Names are a property of directory entries, not files (inodes).  Un*x
files do not have "names" since many directory entries can reference
the same file.  The stdio library echos this.  Since you called
fopen() you can save the info.  The real pain is figuring out what an
fd from a parent is, or chasing down what file finally was opened
after 3 symlinks.

Philip Budne, Boston U
(Ahh for JFNS%)

cjc@ulysses.homer.nj.att.com (Chris Calabrese[rs]) (07/10/88)

In article <651@umb.umb.edu>, karl@umb.umb.edu (Karl Berry.) writes:
> 
> The title says it all. Am I missing something obvious?
> The pathname doesn't seem to be a field in either the
> _iobuf or the structure returned by stat.
> ttyname or ctermid will give you the pathname
> of your terminal, but I want the pathname of an
> arbitrary FILE* I have fopen. Or am I missing some
> reason why this is not feasible?


If _you_ have fopened the file, then _you_ already know
what the name is (just have it sitting around in your program),
but if the file is inheritted(sp?) how do you even know it's a file???

If you rsh or rlogin, then the stdin to any process created on the
remote machine is a socket (mabee it's something similar, but you get
the idea), or a stream (ditto) for sysV.

Even if you don't have any kind of a network, then stdin could be
a pipe, which has no name for unnamed pipes.  These are, infact, files
in most versions of sysV, but they have no names, just inodes.

-- 
	Christopher Calabrese
	AT&T Bell Laboratories
	ulysses!cjc

leo@philmds.UUCP (Leo de Wit) (07/10/88)

In article <651@umb.umb.edu> karl@umb.umb.edu (Karl Berry.) writes:
>
>The title says it all. Am I missing something obvious?
>The pathname doesn't seem to be a field in either the
>_iobuf or the structure returned by stat.
>ttyname or ctermid will give you the pathname
>of your terminal, but I want the pathname of an
>arbitrary FILE* I have fopen. Or am I missing some
>reason why this is not feasible?

This is not trivial. Think for instance of multiple links to a file
(either hard or symbolic links); which name will you use? Or what if
one of the directories in the path has multiple links - apart from the
trivial ones (for example /usr/include/sys, which on our system ==
/usr/sys/h) ? Or what if the FILE * is connected to a pipe? Or what if
the file is already gone (i.e. unlinked but still open) ?

VMS has a function for it: fgetname().
On Unix you could fstat the file descriptor (the char _file member from
the _iobuf struct). This gives you the inode number; now go look for
the filename(s).

What is the use? If you have opened the file, you used the filename 
already (unless the open file is inherited from a parent process).

                   Leo.

guest@osiris.UUCP (Guest account) (07/10/88)

In article <4531@csli.STANFORD.EDU> gandalf@csli.stanford.edu (Juergen Wagner) writes:
>The _iobuf structure as defined in <stdio.h> includes a component _file
>which is supposed to hold the file descriptor number.

*PLEASE*  - if you are going to do things like using internal elements of
"standard" libraries, try to access them in a more or less "standard"
way. Most stdio libraries I've seen have a macro (but could be func, I
guess) called fileno(myfd) - which returns just the information you are
referring to. This way, your code won't break if someone does something
cute or clever to the stdio library and include files.

>fstat(fd, &statbuf) gives information about the open file descriptor, so
>you can find out the device the inode is on, the inode's number, and a 
>few other attributes of interest. With that you should be able to find
>out the information wanted by looking at the st_mode field (check the 
>fd type), and eventually by walking through the file system the inode is
>on.

Does this work if the file system is NFSsed, or something like that ?

It almost seems to me that this is a case which stdio is not designed to
handle. So - I'd say add another level of indirection. Write a routine
that acts like fopen() - and one that acts like fclose(), etc. Have it
store the name someplace, using only the "standard" interface to stdio,
and then write another routine, or macro, that allows you to get the
information back. I can't imagine that would be hard, and I expect it
will work a LOT faster than reading your file system.

Then again, maybe I don't understand what you're trying to do.

'V'.

gandalf@csli.STANFORD.EDU (Juergen Wagner) (07/11/88)

In article <1645@osiris.UUCP> guest@osiris.UUCP (Guest account) writes:
>...
>*PLEASE*  - if you are going to do things like using internal elements of
>"standard" libraries, try to access them in a more or less "standard"
>way. Most stdio libraries I've seen have a macro (but could be func, I
>guess) called fileno(myfd) - which returns just the information you are
>referring to. This way, your code won't break if someone does something
>cute or clever to the stdio library and include files.

I am aware of the fact that there is fileno(f). The point is: there
is a way to find out the file descriptor associated with FILE *f.

>Does this work if the file system is NFSsed, or something like that ?

If you do it properly: yes. Otherwise: no! The problem with NFS file systems
is that you have to walk through something other than the local file system.
I have a small program which determines the file system a file resides on,
and in case of NFS just returnes the remote host's name and the remote file
system's name. This allows you to walk through the directories as before.

At the time I posted my article, I didn't think of files being deleted while
they are still open somewhere else... This shouldn't cause any problems because
your function determining the file name could then just say so. Sockets, pipes,
ptys, and other stuff like raw devices can be handled with fstat. The inode
type will give you the information needed.

As for files having multiple links, I can only ask the question "what do you
want the routine to do?" Do you want a list of all names the file can be
accessed under, or are you merely looking for some way to associate this 
FILE * structure with *SOME* file name on your UNIX system? Personally, I
would be happy with the latter solution. If you get your hands on one of the
file's names, you've got the file in your grip!

>It almost seems to me that this is a case which stdio is not designed to
>handle. So - I'd say add another level of indirection. Write a routine
>that acts like fopen() - and one that acts like fclose(), etc. Have it
>store the name someplace, using only the "standard" interface to stdio,
>and then write another routine, or macro, that allows you to get the
>information back. I can't imagine that would be hard, and I expect it
>will work a LOT faster than reading your file system.

That's not always possible, as I've explained above. You can only find out
the names of files *YOU* have opened yourself. You will never be able to 
find out what stdin/stdout/stderr are connected to...

>Then again, maybe I don't understand what you're trying to do.

I guess, understanding a tool is not a necessary precondition for being able
to use this tool. I can fairly well work with UNIX but don't claim to have
understood all the bits of it! The issue is to provide some function which
performs its task in a way opaque to the user. One reason to do so is that
what this function really does is operating-system dependent. And there we
are again at the same point where you flamed at me because I preferred to 
mention _file instead of fileno(f). Opaqueness is a very important means of
keeping things understandable. If somebody knew that a certain function would
work more efficient under some circumstances than under other, he/she would 
use that knowledge in his/her programs. However, you know as well as I do that
this may turn out to be much less efficient on other systems.

# include <disclaimers/strawberry.h>

-- 
Juergen "Gandalf" Wagner,		   gandalf@csli.stanford.edu
Center for the Study of Language and Information (CSLI), Stanford CA

rwhite@nusdhub.UUCP (Robert C. White Jr.) (07/13/88)

in article <651@umb.umb.edu>, karl@umb.umb.edu (Karl Berry.) says:
> The title says it all. Am I missing something obvious?
> The pathname doesn't seem to be a field in either the
> _iobuf or the structure returned by stat.
> ttyname or ctermid will give you the pathname
> of your terminal, but I want the pathname of an
> arbitrary FILE* I have fopen. Or am I missing some
> reason why this is not feasible?

At great risk of being wrong...

Since one i-node may have many file names I think that
the individual file name is disposed of as useless after
the object in question is opened.  The closest I can even
picture you getting is to retreive the inode number.

All else would seem to be un-workable.


Rob.

Disclaimer:  Then again, maby not.

jc@minya.UUCP (John Chambers) (07/21/88)

In article <560@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes:
> In article <651@umb.umb.edu> karl@umb.umb.edu (Karl Berry.) writes:
> >
> >The title says it all. Am I missing something obvious?
> >The pathname doesn't seem to be a field in either the
> >_iobuf or the structure returned by stat.
> >ttyname or ctermid will give you the pathname
> >of your terminal, but I want the pathname of an
> >arbitrary FILE* I have fopen. Or am I missing some
> >reason why this is not feasible?
> 
> What is the use? If you have opened the file, you used the filename 
> already (unless the open file is inherited from a parent process).

There are lots of uses.  Consider a problem I am having on a current
project:  A program running on a Sun is running out of files.  My code
opens maybe 6 or 8 files at the most.  So where do the others come from?
Easy - they are opened by library subroutines.  My code can't remember
the names of those files; my code didn't open them.  This makes debugging
very difficult.  Sun hasn't been very helpful, either.  Sure, I have a
routine to fstat() all the open files and print out the magic numbers.
That doesn't help me much in getting the answer to the question "What's
causing all those @#$*^% files to be opened?"

For debugging, it would be very useful if I could use a library that
would keep around a copy of the name used to open a file.  For inherited
files, the info *could* be passed in the environment.

The fact that some files have no valid name isn't a valid counter-argument.
For debugging purposes, it would be useful if some pseudo-names ("<stdin>",
"<socket>") were returned.  

Some of us occasionally write code that doesn't work the first time, and
we sometimes have a few problems figuring out what we did wrong.  Having
the libraries so secretive about what they're doing isn't very helpful.  

-- 
John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393)

[Any errors in the above are due to failures in the logic of the keyboard,
not in the fingers that did the typing.]

mesard@bbn.com (Wayne Mesard) (07/21/88)

From article <49@minya.UUCP>, by jc@minya.UUCP (John Chambers):
> There are lots of uses.  Consider a problem I am having on a current
> project:  A program running on a Sun is running out of files.  My code
> opens maybe 6 or 8 files at the most.  So where do the others come from?
> Easy - they are opened by library subroutines.  My code can't remember
> the names of those files; my code didn't open them.  This makes debugging
> very difficult.

This isn't by any chance a SunView program is it?  Since SunView windows
are actually devices, client programs access them via file descriptors.
It's amazing how fast 4.2BSD's limit of 30 can get eaten up in a
fair-sized [full-screen] application.

-- 
unsigned *Wayne_Mesard();        MESARD@BBN.COM           BBN, Cambridge, MA

"When Martin Sheen visited me, he was smoking again after his heart
attack, and I asked why.  He said, 'It is my friend it is always there
and doesn't pass judgment.' I said, 'Your friend is going to kill you.'"

                                         - Larry King

allbery@ncoast.UUCP (Brandon S. Allbery) (07/22/88)

As quoted from <1645@osiris.UUCP> by guest@osiris.UUCP (Guest account):
+---------------
| It almost seems to me that this is a case which stdio is not designed to
| handle. So - I'd say add another level of indirection. Write a routine
| that acts like fopen() - and one that acts like fclose(), etc. Have it
| store the name someplace, using only the "standard" interface to stdio,
| and then write another routine, or macro, that allows you to get the
| information back. I can't imagine that would be hard, and I expect it
| will work a LOT faster than reading your file system.
+---------------

But it won't work in the case of stdin, stdout, stderr -- which are
implicitly fdopen()'ed from fd's 0, 1, and 2.  And stdin is usually the one
you want the name for.

++Brandon
-- 
Brandon S. Allbery, uunet!marque!ncoast!allbery			DELPHI: ALLBERY
	    For comp.sources.misc send mail to ncoast!sources-misc