[comp.unix.questions] Identify file name given file descriptor

grt@twitch.UUCP ( G.R.Tomasevich) (05/07/87)

This is a subsidiary to the 'more' discussion.  I partly tested a method
on Sys V R2, VAX 11/785.  One can fstat(2) to get the inode value and the
block-special identity.  One must find out the name of the device, perhaps
from stat'ting the disk devices until finding the right one (untested).
One then generates and runs a command "/etc/ncheck -i inode blockdevice".
On twitch one must be super-user to do that; I tried a file, and it took
several minutes for ncheck to find the name.  One then needs /etc/mount
to associate the device with the proper mount directory.  Whew!  Is there
a better way?  Someone suggested walking down from /.  How would he find
out the correct file system, assuming more than one file matched the inode
number?
-- 
	George Tomasevich, ihnp4!twitch!grt
	AT&T Bell Laboratories, Holmdel, NJ

mpl@sfsup.UUCP (05/11/87)

In article <710@twitch.UUCP>, grt@twitch.UUCP writes:
> ....
> One then generates and runs a command "/etc/ncheck -i inode blockdevice".
> On twitch one must be super-user to do that; I tried a file, and it took
> several minutes for ncheck to find the name.  One then needs /etc/mount
> ....

On the last project I worked on, someone (Larry Feigen to give him credit)
wrote a program called "fdcheck".  It does the following for each file
descriptor of interest:

	runs /etc/mount to get the mount points of all mounted file systems
	does a stat to get the device number for each mounted file system
	does an fstat on the file descriptor(s) to get the device/inode
		number(s)
	does a "find dir -print | xargs ls -i | sed -e ...." to pick out
		the path names of interest.

This method is surprisingly fast (takes a minute or 2 on our 3B20s with
big disks - a little longer on slower machines), and if you give the
program some hints as to where you think the files might be (he has a
way of passing it a file with a table of such info in it), it can get by
in just a few seconds!

Mike Lindner

jfh@killer.UUCP (John Haugh) (05/13/87)

I opened my mouth and said it could be done.  I refuse to write C code
on my lunch hour so you will have to take what you get.   Refer to ftw(3),
fstat(2) and stat(2) for all of the information you should need.  You
don't REALLY need ncheck, find, /etc/mnttab or any of that other stuff.
stat(2) and fstat(2) return plenty enough information.  You _can_ make things
go faster by finding the correct root directory.


main
    find_file_name ("/", your_fstat_structure) -- start from root directory
					       -- with fstat(2) values.
end

procedure find_file_name (current_directory, file_fstat)

    if current_directory.file_stat = file_fstat then
				-- was FD this directory?
	    putstring (current_directory)
            return
    fi
    for each file_entry in current_directory    -- stat(2) each slot
        if file_entry.file_type = directory_type then
				-- recursively call directories
            find_file_name (current_directory + file_entry.file_name,
						file_fstat)
        elif file_entry.file_stat = file_fstat then
				-- else check to see if it is the file
				-- by checking st_ino and st_dev fields.
            putstring (current_directory + file_entry.file_name)
				-- and print the name if you found one.
            return
        fi
end


There you have it.  All accessible files are checked, which should include
yourown since you should be able to read you own directory.  The ones you
can't access can't be accessed :-(.  st_ino and st_dev are all you need to
compare to see if the files are the same ones.  This should (once written
in C or something) be as fast or faster than find(1) since find(1) has atleast
this much work to do.

- John.

Disclaimer -
	I speak for myself.  My boss pays me money when he wants me to
	speak for him.

jgy@hropus.UUCP (John Young) (05/19/87)

> main
>     find_file_name ("/", your_fstat_structure) -- start from root directory
> 					       -- with fstat(2) values.
> end
> 
> procedure find_file_name (current_directory, file_fstat)
> 
>     if current_directory.file_stat = file_fstat then
> 				-- was FD this directory?
> 	    putstring (current_directory)
>             return
>     fi
>     for each file_entry in current_directory    -- stat(2) each slot
>         if file_entry.file_type = directory_type then
> 				-- recursively call directories
>             find_file_name (current_directory + file_entry.file_name,
> 						file_fstat)
>         elif file_entry.file_stat = file_fstat then
> 				-- else check to see if it is the file
> 				-- by checking st_ino and st_dev fields.
>             putstring (current_directory + file_entry.file_name)
> 				-- and print the name if you found one.
>             return
>         fi
> end
> 
> 
> There you have it.  All accessible files are checked, which should include
> yourown since you should be able to read you own directory.  The ones you
> can't access can't be accessed :-(.  st_ino and st_dev are all you need to
> compare to see if the files are the same ones.  This should (once written
> in C or something) be as fast or faster than find(1) since find(1) has atleast
> this much work to do.
> 
> - John.
> 

This doesn't seem to handle the case of having a filesystem
mounted on anything but a root level directory.

 - John Young

jda@mas1.UUCP (05/20/87)

Several pointed out that a file with no links has no name.

But Ultrix 1.0 (and presumably also 4.2BSD) often makes NO change
to the directory entry when a file is unlinked.  (The preceding
entry has its d_reclen incremented to render the obsolete entry
"invisible".  Presumably the obsolete entries are destroyed only
when the directory is about to grow by a block.)

You will need a special version of readdir(3) which returns "erased"
entries.  It should be fun to write since the obsoleted entries can
be in various stages of obliteration!   :-)

BTW, has anyone written a real "unrm" program?

             -- James D. Allen

gwyn@brl-smoke.UUCP (05/20/87)

In article <513@mas1.UUCP> jda@mas1.UUCP (James Allen) writes:
>You will need a special version of readdir(3) which returns "erased"
>entries.

What good would that do you?  You couldn't open the inode anyway.

matt@oddjob.UChicago.EDU (Keeper of the Sacred Tablets) (05/21/87)

gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
) In article <513@mas1.UUCP> jda@mas1.UUCP (James Allen) writes:
) >You will need a special version of readdir(3) which returns "erased"
) >entries.
) 
) What good would that do you?  You couldn't open the inode anyway.

And the block pointers have all been zeroed out.  (This makes
fsck happier.)  Oh well, if he just wants the name of the file
that's gone, much good may it do him.
________________________________________________________
Matt	     University		matt@oddjob.uchicago.edu
Crawford     of Chicago     {astrovax,ihnp4}!oddjob!matt

dhesi@bsu-cs.UUCP (05/22/87)

Following up on the discussion of how to find a name given a file
descriptor, I want to point out that the ttyname() library function
already does that to a limited extent.  It accepts a file descriptor
and returns the name of the terminal device corresponding to it.
Presumably it only searches /dev.

And the name it finds that may not be the one that is needed.  Using cu
under Microport System V/AT when multiple links exist to the same
serial device, I find that cu creates the lock file
/usr/spool/uucp/LCK..tty0 when it is invoked, because /dev/tty0 is the
default device for cu.  But when it exits, it does not use the same
name, because it apparently calls ttyname() and uses whatever name is
returned.  In my case it tries to then remove the lock file
/usr/spool/uucp/LCK..ttycg and fails to find it and complains.

This was clearly an oversight on part of the author, who assumed that
there would be only one link to a serial device.  The right thing to do
would be to always use ttyname(), so no matter how many links exist,
the same lock file will be used for the same physical device.

I found similar strange things happening under 4.3BSD if there was more
than one link to a terminal in /dev, though I don't remember which
program (tip or cu or uucico) was affected.
-- 
Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

jfh@killer.UUCP (John Haugh) (05/27/87)

In article <3792@oddjob.UChicago.EDU>, matt@oddjob.UChicago.EDU (Keeper of the Sacred Tablets) writes:
> And the block pointers have all been zeroed out.  (This makes
> fsck happier.)  Oh well, if he just wants the name of the file
> that's gone, much good may it do him.

Those block pointers had better be someplace or anyone trying to read/write
the file is gonna' be in _BIG_ trouble.  There is still the inode table,
you if you _really_ want to, you can open /dev/kmem and go looking for
the inode there.  Bmap() still needs the 13 inode (last time I looked :-))
addresses - and the *-indirect blocks still have to have their addresses.

- John.


Disclaimer -
	No disclaimer.  Whatcha gonna do, sue me?