[comp.unix.wizards] To find out the names of open files in a process

garg@mandrill.CWRU.Edu (Dev Datt Garg) (01/18/88)

Hi Friends,
	I am working on my M.S. Thesis. I am extending the command language of
GDB(Gnu Debugger) for Sun3 running BSD unix. One of the features I am trying 
to add is to be able to save the context of a process at any point in the 
user program, so that at later stage program can be restarted from that point.
I have got some success in doing that. I am having a problem, If the program,
which I am debugging has some files open. I am unable to know which files were
 open, so that the status of those files can be restored.

	Of course one of the things I am saving is a user structure, which 
contains most of the info regarding process context. I somehow want to
recover the names of the open files from this struct or from anywhere else.
I will highly appreciate if some Guru could tell me some way of achieving
that.
	Thanx in advance.

usenet: {decvax,cbosgd,sun}!mandrill!garg	Dev Datt Garg
csnet:       garg@mandrill.CWRU.edu
arpa:        garg@mandrill.CWRU.edu


-- 
usenet: {decvax,cbosgd,sun}!mandrill!garg	Dev Datt Garg
csnet:       garg@mandrill.CWRU.edu
arpa:        garg@mandrill.CWRU.edu

ram%shukra@Sun.COM (Renu Raman, Sun Microsystems) (01/19/88)

In article <2346@mandrill.CWRU.Edu>, garg@mandrill.CWRU.Edu (Dev Datt Garg) writes:
> 
> Hi Friends,
> 	I am working on my M.S. Thesis. I am extending the command language of
> GDB(Gnu Debugger) for Sun3 running BSD unix. One of the features I am trying 
> to add is to be able to save the context of a process at any point in the 
> user program, so that at later stage program can be restarted from that point.
> I have got some success in doing that. I am having a problem, If the program,
> which I am debugging has some files open. I am unable to know which files were
>  open, so that the status of those files can be restored.
> 
> 	Of course one of the things I am saving is a user structure, which 
> contains most of the info regarding process context. I somehow want to
> recover the names of the open files from this struct or from anywhere else.
> I will highly appreciate if some Guru could tell me some way of achieving
> that.
> 	Thanx in advance.
> 
> usenet: {decvax,cbosgd,sun}!mandrill!garg	Dev Datt Garg
> csnet:       garg@mandrill.CWRU.edu
> arpa:        garg@mandrill.CWRU.edu

   Read the report "An unix 4.2 BSD implementation of Process suspension
   and resumption" by A.Y. Chen (Jun 86 , U. of Ill, report no. UiUCDCS-R-86-1286
   ).  At the end of the report is included the source code which includes
   some diffs to the kernel - user structure, kern_descrip.c, kern_exec.c,
   ufs_nami.c.   I guess the objective there was to checkpoint a process and
   save the process state in a stable storage and restore it when needed.

   An implementation was done on SYS V too.  Just send mail to 
   Erna Amerman (erna@a.cs.uiuc.edu) and ask for report DCS-R-86-1286.

---------------------
   Renukanthan Raman				ARPA:ram@sun.com
   Sun Microsystems			UUCP:{ucbvax,seismo,hplabs}!sun!ram
   M/S 5-40, 2500 Garcia Avenue,
   Mt. View,  CA 94043

narayan@tandem.UUCP (narayan mohanram TCP/IP Conso) (01/21/88)

In article <2346@mandrill.CWRU.Edu>, garg@mandrill.CWRU.Edu (Dev Datt Garg) writes:
> 
 One of the features I am trying 
> to add is to be able to save the context of a process at any point in the 
> user program, so that at later stage program can be restarted from that point.
> I have got some success in doing that. I am having a problem, If the program,
> which I am debugging has some files open. I am unable to know which files were
>  open, so that the status of those files can be restored.

The conovoluted way to do that would be to look at the inode (incore)
by looking at u.u_ofile[x]->f_inode. This can then give you the
major/minor device number of the file that is open (You can also get
the seek pointers). You then have to search the mount table, and find
where this major/minor device is mounted, and then search the file system
for the necessary inode number. You can thus establish a path to the
file. 

Alternately you can write a simple character device driver that will
open a file given inode information. You can thus supply this as
an ioctl to the program that can then munge the internals of the
kernel data structures (XXX).

Narayan Mohanram

(narayan@ati.tis.llnl.gov)

ok@quintus.UUCP (Richard A. O'Keefe) (01/21/88)

In article <339@tandem.UUCP>, narayan@tandem.UUCP (narayan mohanram TCP/IP Conso) writes:
> In article <2346@mandrill.CWRU.Edu>, garg@mandrill.CWRU.Edu (Dev Datt Garg) writes:
> > 
>  One of the features I am trying 
> > to add is to be able to save the context of a process at any point in the 
> > user program, so that at later stage program can be restarted from that point.
> > I have got some success in doing that. I am having a problem, If the program,
> > which I am debugging has some files open. I am unable to know which files were
> >  open, so that the status of those files can be restored.
> 
There is a moderately straightforward method which doesn't involve kernel
hacking.  Basically, the original poster has
    {revised GNU debugger}
			 \
			  {child process}
and wants to maintain, in the debugger, a table
    {child's file descriptor number} --> {symbolic file name}.

The answer is simple:
	The child already contains stubs for all the system calls it
	uses.
	The debugger knows which system calls can allocate and
	deallocate file descriptors.
	The debugger places special break-points on each appropriate
	stub (it has the symbol table for the child, so knows where
	all the stubs are).  Note that you have to track chdir() too!

The debugger initialises its table when it starts the child.
(I don't know the GNU debugger, but presumably you can say e.g.
	run <input >output 2>error 12<another-file
and the debugger knows perfectly well which fd goes with what
symbolic file name at this point, because it put them there.)
Then, whenever the child executes open() or whatever, the debugger
adds the appropriate entry to its table, and whenever the child
executes close() or whatever, the debugger deletes the corresponding
entry from its table.

None of this requires the debugger to know anything that a debugger
doesn't have to know anyway, nor does it require special devices or
system calls not already provided or not available to ordinary users.
In fact, apart from ptrace() as such, it isn't even UNIX-specific.

There is a problem, of course:  what happens if a file has been deleted,
renamed, or otherwise altered since the checkpoint was saved?  But this
approach is actually better than scanning the disc, because although a
file can have any number of names in UNIX, with this approach you know
>>the name the child used<<.  So if something has gone wrong, at least
the user stands a chance of identifying the file name.

rsalz@bbn.com (Rich Salz) (01/21/88)

>In article <2346@mandrill.CWRU.Edu>, garg@mandrill.CWRU.Edu (Dev Datt Garg) writes:
> I have got some success in doing that. I am having a problem, If the program,
> which I am debugging has some files open. I am unable to know which files were
>  open, so that the status of those files can be restored.
In the general case you can't do it.  For example:
	char *p = "/tmp/mail1234";
	freopen(p, "r", stdin);
	unlink(p);
	...
(I've got some highly useful programs that do this.)

If you can get the major/minor device numbers, you can rummage around
to find the inode, then work back from that, but all this was hashed
out here about six months ago and the conclusion was: good luck, you
won't get them all.
	/r$
-- 
For comp.sources.unix stuff, mail to sources@uunet.uu.net.

gallmeis@wasp.cs.unc.edu (Bill Gallmeister) (01/28/88)

In article <7124@ncoast.UUCP> allbery@ncoast.UUCP (Brandon Allbery) writes:
>As quoted from <339@tandem.UUCP> by narayan@tandem.UUCP (narayan mohanram TCP/IP Conso):
>+---------------
>| In article <2346@mandrill.CWRU.Edu>, garg@mandrill.CWRU.Edu (Dev Datt Garg) writes:
>| > to add is to be able to save the context of a process at any point in the 
>| > user program, so that at later stage program can be restarted from that point.
>| 
>| Alternately you can write a simple character device driver that will
>| open a file given inode information. You can thus supply this as
>| an ioctl to the program that can then munge the internals of the
>| kernel data structures (XXX).
>+---------------
>
>That last sounds like a security disaster to me...<etc>

I promised myself I wouldn't get into this.  So here I am.  What's wrong with rewriting
the library routines so they squirrel away file names + file statistics, then pass them
over when the process gets migrated?  It really seems that the mapping of filename to
inode can be done outside of the kernel.  And therefore should be.  Run the processes
under control of a "puppet master" that knows how to do these things.  Much better than
modifying the kernel, although it doesn't look quite as good on the resume...

this kind of reminds me of someone who asked how to get the size of a malloc'ed block.
The answer?  "Remember how much you asked for, dimwit!"

- bill o
---
Bill O. Gallmeister					gallmeis@cs.unc.edu
"Offer me solutions -- offer me alternatives -- and I decline.
 It's the end of the world as we know it, and I feel fine."

dmt@ptsfa.UUCP (Dave Turner) (01/28/88)

In article <7124@ncoast.UUCP> allbery@ncoast.UUCP (Brandon Allbery) writes:
>As quoted from <339@tandem.UUCP> by narayan@tandem.UUCP (narayan mohanram TCP/IP Conso):
>+---------------
>| In article <2346@mandrill.CWRU.Edu>, garg@mandrill.CWRU.Edu (Dev Datt Garg) writes:
>| > to add is to be able to save the context of a process at any point in the 
>| > user program, so that at later stage program can be restarted from that point.
>| 


I almost hate to suggest this but since you are trying to add a new feature,
why don't you simply modify open() to save the filename and current directory name.
It should be easy to hide the names along with the associated file descriptors
and avoid all the trouble and ambiguity of trying to match the inode number
to the proper filename.


-- 
Dave Turner	415/542-1299	{ihnp4,lll-crg,qantel,pyramid}!ptsfa!dmt

hansen@mips.COM (Craig Hansen) (01/29/88)

In article <904@thorin.cs.unc.edu>, gallmeis@wasp.cs.unc.edu (Bill Gallmeister) writes:
> this kind of reminds me of someone who asked how to get the size of a malloc'ed block.
> The answer?  "Remember how much you asked for, dimwit!"

Actually, if free() is going to be able to deallocate the space, the
dimwit malloc() ought to be salting the size away somewhere, since
free doesn't depend on the dimwit programmer telling it how big the
block is. With that in mind, there's no conceivable reason why there
isn't an msize() function for us comp.unix.dimwits.

-- 
Craig Hansen
Manager, Architecture Development
MIPS Computer Systems, Inc.
...{ames,decwrl,prls}!mips!hansen or hansen@mips.com   408-991-0234

kent@tifsie.UUCP (Russell Kent) (01/29/88)

in article <2120@ttrdc.UUCP>, levy@ttrdc.UUCP (Daniel R. Levy) says:
 [ deleted lines - RAK ]
} #> Alternately you can write a simple character device driver that will
} #> open a file given inode information. You can thus supply this as
} #> an ioctl to the program that can then munge the internals of the
} #> kernel data structures (XXX).
} 
} This if not done carefully would pose a security hole.  Either this form
} of access should only be allowed to the superuser (perhaps by making the
} special device be readable/writeable only by the root, a la /dev/mem
} and block devices for disks) or access should only be permitted for files
} which could also be opened in the desired manner by pathname.
} -- 
} Dan Levy

Wouldn't "access ... permitted for files which could also be opened in the
desired manner by pathname" imply that the kernel would have to search the
file system directory tree for an accessible path?  Do you _really_ want
to put this sort of thing into the kernel (can you see the kernel spending
millions of machine cycles scanning the disk drive??)

-- 
Russell Kent                    Phone: +1 214 995 3501
Texas Instruments               UUCP address:
P.O. Box 655012   MS 3635       ...!convex!smu!tifsie!kent
Dallas, TX 75265                ...!ut-sally!im4u!ti-csl!tifsie!kent

brett@wjvax.UUCP (Brett Galloway) (01/30/88)

>In article <1427@mips.mips.COM> hansen@mips.COM (Craig Hansen) writes:
>>In article <904@thorin.cs.unc.edu>, gallmeis@wasp.cs.unc.edu (Bill Gallmeister) writes:
>>> this kind of reminds me of someone who asked how to get the size of a malloc'ed block.
>>> The answer?  "Remember how much you asked for, dimwit!"
>>
>>Actually, if free() is going to be able to deallocate the space, the
>>dimwit malloc() ought to be salting the size away somewhere, since
>>free doesn't depend on the dimwit programmer telling it how big the
>>block is. With that in mind, there's no conceivable reason why there
>>isn't an msize() function for us comp.unix.dimwits.

I don't agree that only dimwits require this information.  All
implementations of malloc() will give you *at least* the amount of room
you asked for; many will give you more (BSD is reputed to allocate in
powers of 2).  I have several applications where I could make more
efficient use of space if I knew how much space malloc() actually gave
me.  This occurs whenever I am malloc()'ing a buffer that I may want
to realloc() later because it filled up; knowing how much malloc()
actually gave me could save both malloc space and run-time.

I suggested this on comp.lang.c a while back as a useful, portable
enhancement to any malloc() package, but got no response.  I have
redirected follow-ups back to comp.lang.c because it seems of general
interest to users of standard C libraries with a malloc() routine.

-- 
-------------
Brett D. Galloway
{ac6,calma,cerebus,isi,isieng,pyramid,tymix}!wjvax!brett

eichin@athena.mit.edu (Mark W. Eichin) (01/30/88)

In article <1427@mips.mips.COM> hansen@mips.COM (Craig Hansen) writes:
>In article <904@thorin.cs.unc.edu>, gallmeis@wasp.cs.unc.edu (Bill Gallmeister) writes:
>> The answer?  "Remember how much you asked for, dimwit!"
>
>Actually, if free() is going to be able to deallocate the space, the
>dimwit malloc() ought to be salting the size away somewhere, since

Exactly: a DIMWIT malloc might be allocating the exact amount of space
asked for; this then requires a full copy on any realloc and causes
other performance problems. A fast malloc might just manage the heap
as a set of blocks of power of 2 sizes, which are near (modulo some
hysteresis value) the actual size requested via malloc(). Thus free
can just relink the block onto a chain, never knowing what the ACTUAL
size was, msize() not being inherent in the block structure. This is
more efficient than a serial allocator when there is much thrashing of
the memory pool (eg. a lisp-like system or an editor) since you can
just make the block available for quick re-use. {If anyone knows
really precise results of this type, can you point me at them?  We
have ``proven'' them here in a small way, but real results might make
a good thesis project...}

The GNU Emacs malloc (derived from several places) did this, with the
debugging option of keeping msize in the block header, and storing a
magic number at each end of the block, which it could check at free or
realloc time (simple bounds checking.) I enhanced this for a project
here to fill the ENTIRE `extra' area with magic numbers, and then
scanning them for error at the appropriate times... It also trashes
freed blocks (with a magic number) and makes sure they aren't written
in when they next get reused. These things have helped trap software
bugs that make 4.nBSD malloc corrupt the memory pool, making debugging
impossible... 

This project actually needed msize, so we left it always running with
the first level of bounds checking (though we haven't gotten it stable
enough for non alpha users, so we really run with full checking most
of the time.) If it ran well, we would just hook an msize() onto what
ever allocator we ended up with, so we could actually port the
software. msize() was convenient enough (we were using `intelligent
arrays') that we wanted to add it at the allocator level, for
performance, rather than including it in the higher level structures.

In summary: there IS a reason that there isn't an msize() by default,
it is a constraint upon the allocator which can be overly restrictive
in certain usage patterns.

				Mark Eichin
			<eichin@athena.mit.edu>
		SIPB Member & Project Athena ``Watchmaker'' 

brett@wjvax.UUCP (Brett Galloway) (02/01/88)

In article <2672@bloom-beacon.MIT.EDU> eichin@athena.mit.edu (Mark W. Eichin) writes:
>>[why isn't there an msize() routine that returns the actual amount of space
>>allocated by malloc()?]
>In summary: there IS a reason that there isn't an msize() by default,
>it is a constraint upon the allocator which can be overly restrictive
>in certain usage patterns.

I posted the other day another reason for making such a feature (a feature
to return the *actual* malloc()'d size available to the user) available.
I neglected to mention that I was thinking in terms of a variant malloc()
that returned the actual size as well as the character pointer.  I agree that
an after-the-fact msize() routine might be overly expensive.  However, it seems
to me that a variant malloc() that reported what it actually allocated could
be had for free.  I mean a routine like

	char	*mallocsize(size,actual)
	unsigned size;
	unsigned *actual;

(with types ala BSD -- fill in your own types).  If the implementor were
lazy, or forgot to implement it at all, he (or you) could just use

	char	*mallocsize(size,actual)
	unsigned size;
	unsigned *actual;
	{
		*actual = size;
		return(malloc(size));
	}
-- 
-------------
Brett D. Galloway
{ac6,calma,cerebus,isi,isieng,pyramid,tymix}!wjvax!brett

kent@tifsie.UUCP (Russell Kent) (02/02/88)

in article <904@thorin.cs.unc.edu>, gallmeis@wasp.cs.unc.edu (Bill Gallmeister) says:
> I promised myself I wouldn't get into this.  So here I am.  What's wrong
> with rewriting the library routines so they squirrel away file names +
> file statistics, then pass them over when the process gets migrated?  It
> really seems that the mapping of filename to inode can be done outside
> of the kernel.  And therefore should be.  Run the processes under control
> of a "puppet master" that knows how to do these things.  Much better than
> modifying the kernel, although it doesn't look quite as good on the resume...
> Bill O. Gallmeister					gallmeis@cs.unc.edu

Migrating the pathname to inode number translation from the kernel into
the user space would:

	1. Eliminate some of the file access security afforded by the
	   present scheme.

	2. Destroy the orthogonality of the physical resource naming

Explanations:
	As we all know, the kernel uses the execute bit (x bit) of a directory 
	to allow "search" permission, as opposed to "read" permission which
	is still handled by the read bit (r bit).  Presently, it is possible to
	construct to path types which I will call "under glass", and "blackhole."

	An "under glass" pathname is one in which the terminal directory
	(ie next-to-last pathname component) is readable, but not searchable.
	This allows programs to see that the file exists, but does not
	allow it to open the file (the clever reader will note that this is
	easily accomplished with the permissions on the file itself -- I never
	said that this was a _useful_ technique 8-).

	A "blackhole" pathname is on in which at least one of the directories
	in the pathname is searchable but not readable.  This allows programs
	to access the file _if_ they already know the pathname.  Since the
	directories are not readable, then (with some careful naming) the
	file is effectively inaccessible unless the name is already known.
	This can be used where the other security techniques provided by
	the system are ineffective, awkward, or have potentially unpleasant
	side-effects.  (SA's golden rule: every setuid root program is a
	potential disaster)

    These are admittedly esoteric objections; but what about that
	panacea for nearly all security problems: chroot().  How
	will you implement this if the user/kernel open is done
	with inode numbers? (Of course, the _truely_ mischievous user
	can be dealt with by more extreme measures such as putting his/her
	home directory on /dev/tape 8-).

	As for the orthogonality of the name space of physical resources,
	I can best demonstrate with a question: What is the inode number
	of /dev/ra0a? Or of /dev/tty03?
-- 
Russell Kent                    Phone: +1 214 995 3501
Texas Instruments               UUCP address:
P.O. Box 655012   MS 3635       ...!convex!smu!tifsie!kent
Dallas, TX 75265                ...!ut-sally!im4u!ti-csl!tifsie!kent

jc@minya.UUCP (John Chambers) (02/04/88)

In article <1427@mips.mips.COM>, hansen@mips.COM (Craig Hansen) writes:
> In article <904@thorin.cs.unc.edu>, gallmeis@wasp.cs.unc.edu (Bill Gallmeister) writes:
> > this kind of reminds me of someone who asked how to get the size of a malloc'ed block.
> > The answer?  "Remember how much you asked for, dimwit!"
> 
> Actually, if free() is going to be able to deallocate the space, the
> dimwit malloc() ought to be salting the size away somewhere, since
> free doesn't depend on the dimwit programmer telling it how big the
> block is. With that in mind, there's no conceivable reason why there
> isn't an msize() function for us comp.unix.dimwits.

There's another problem you've missed.  All too often, I find that I can't
remember how much I asked for, because I didn't ask for it.  True, if I
am writing the whole program, I can keep the size somewhere.  But suppose
I'm a library routine passed a pointer, and I want to make sure I don't
overflow the caller's data block.  The turkey didn't pass me its size, so
how the @#$*$&%^ am I supposed to discover it?

Of course, a good design would always pass a size along with a pointer.
Sure, and when you are writing your library sprintf() routine, do you
want to go out and modify all the calls in all the software in the world
so that there's a size parameter?  I mean, sprintf() is specified and 
cast in a huge chunk of concrete by now.  It doesn't include a size field.
How is a competent software engineer to guarantee that it doesn't overflow
the caller's array?

Open files are a similar problem.  You can say "Just remember the file
name, dimwit."  But if you're the poor library routine that has just read
garbage from a fd, and you want to give a sensible diagnostic rather than
the usual "garbage in input" sort of message, how DO you discover which
of the various character strings lying about in memory is the name of
that file?  Note that it's too late by now to request the file name from
the caller; the spec was already approved by management, and the name isn't
in your list of parameters.

Oh, well, maybe we should just be traditionalists, and not worry about
memory faults or useful diagnostics.


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

sarge@sting.Berkeley.EDU (Steven Sargent) (02/04/88)

You can (with fair effort) discover the names of many (not all)
disk files by fstat'ing the descriptor, then rooting around in
directories to find the <name,inumber> translation, then winding
up to the root.  (getwd(3), or pwd(1) for usg'ers, does something
like this, but it depends on being able to start from "."  This is
somewhat more complicated).  You can read the disk -- write a
separate program that has readonly permissions for the disk --
being sure that you turn off close-on-exec flags for your fd's
before running it.  Note:
	- fails for non-disk files (e.g., pipes); restarting your
		process in mid-IPC is problematical, anyway;
	- fails if your process has created, then unlinked, a file
		(standard trick for creating temp files; on last
		close, the bits are reclaimed);
You may not need read-disk permission (I'm too fuzzy right now
to be sure), and just replicate what getwd does; in which case
	- fails if you don't have read permission on any of the
		intermediate directories.

Salting away the names of files opened by open(2), &c. is ineffective
since you can't know the names of files inherited by I/O redirection.

I know of at least one implementation in which the full path name
associated with u.u_cdir is maintained by the operating system
(chdir(), &c. are never "fooled" by symbolic links).  I suppose
you could do the same thing with filenames ... but that way leads
VMS.


S.