[net.unix] Anything like getpwent

peter@BASKIN.UUCP (Peter Klosky) (10/23/86)

>>Is there a routine out there to read an inode?
>Yes, it's called stat().

Trying not to set a sarcastic tone, let me say it is a little
anxiety forming to find out that du() and ls() do not tell
the truth about files that have "holes" in them.  If you are on
a system that has a lot of files with this "feature," it will be
impossible to find out who is using what space in terms of systems
administration; the problem is that programs use stat() when they
should not.
One of my dearest relatives wrote a program to find out the true
file block usage of a file, hence the name for the utility, fbu().
It has been posted to net.sources in an alternate universe, but
it really should be a feature of du, kind of a "try harder" option.
It is also hard to stat a file when it is not referenced in a
directory, even though you know its inode number.
fbu() will also cat a file by inode number.
I have been trying to get this program to work on the 4.2 file
system layout, but I am confused about this new file system.  
Can anyone give me some hints about how a program to cat a file
by inode number might be written in the 4.2 world?  Does anyone have an 
inode reader that works under 4.2?  Am I really confused, and is 
the 4.2 file system layed out just like the historic file system?
I have lost my version of SuperPS, btw, and am wondering if anyone has
modified ofiles() to reveal not only the names of the files open by 
a given process, but also tell a few words about the state of
tcp/ip connections open.  Sort of like ps(), ofiles() and netstat()
merged together.  The system I am typing on now has such poor utilities
that it prints the WCHAN in non-symbolic form; a UNIX system that
can't tell between a wait() and a ttyread() makes me given to wonder.

guy@sun.uucp (Guy Harris) (10/24/86)

> Trying not to set a sarcastic tone, let me say it is a little
> anxiety forming to find out that du() and ls() do not tell
> the truth about files that have "holes" in them.  If you are on
> a system that has a lot of files with this "feature,"

I presume by putting "feature" in quotes you mean to imply that it causes
more problems than it solves and shouldn't be there.  If so, you're wrong;
several applications use files with "holes" in them, such as those using the
"dbm" library.  Since the "dbm" library, if I remember correctly, assigns
block addresses for records based on the hashed value of the key, being able
to treat the file as a sparse array is very useful.

> the problem is that programs use stat() when they should not.

As if they had a choice?  Are you saying that "du" and "ls" should be
set-UID root (so that they can read the raw disk), should have intimate
knowledge of the file system (so they can compute the number of blocks used
by a file based on its file map), and should be willing to spend a lot of
time working on each file reading the entire file map tree?

And once you've done that, what do you do if you're using NFS and the file
in question resides on an MS-DOS or VMS file system?

Life is full of tradeoffs, and I think you will find few people who would
say that the wrong tradeoffs were made in "ls" and "du".

> It is also hard to stat a file when it is not referenced in a
> directory, even though you know its inode number.

It is hard to do *anything* with a file when it is not referenced by a
directory.  The only reason there should be such files around is if 1) the
file is an unnamed pipe or 2) a file that has been removed but is still
being "kept around" because somebody still has it open or because it is a
shared-text executable that somebody is still running (yes, there *are*
systems that permit this; there is no point in forbidding it, so Berkeley
removed the check that gives ETXTBSY if you try to remove the last link to a
shared-text file).

> The system I am typing on now has such poor utilities that it prints the
> WCHAN in non-symbolic form; a UNIX system that can't tell between a wait()
> and a ttyread() makes me given to wonder.

I hope you realize that you have just described somewhere between 90% and
95% of the UNIX systems out there.  4.3BSD makes a small attempt at
improving this, and some more can be done.  The problem can *not* be solved
in general, since a routine in the kernel can sleep on any unique
"caddr_t"-sized cookie that it wishes; you'd have to do something like
modify "sleep" to take an extra argument that indicates the reason for
sleeping.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)

chris@umcp-cs.UUCP (Chris Torek) (10/28/86)

In article <117@BASKIN.UUCP> peter@BASKIN.UUCP (Peter Klosky) writes:
>I have been trying to get this [...] to work on the 4.2 file
>system layout, but I am confused about this new file system.  

Finding inodes is not too hard.  The main trick is that you must first
read the super-block:

	#include <sys/param.h>
	#ifdef sun		/* really NFS */
	#include <ufs/inode.h>
	#include <I forget, but it was obvious>
	#else
	#include <sys/inode.h>
	#endif
	#include <sys/fs.h>

	union {
		struct	fs sblk;
		char	pad[SBSIZE];
	} un;
	#define	sblock	un.sblk

	int diskfd;
	struct dinode *iget();
	...

		diskfd = open(rawdisk, 0);
		if (diskfd < 0)
			error...
		bread(SBLOCK, (char *)&sblock, SBSIZE);

	...
		ip = iget(inode_number);
	...

	struct dinode *
	iget(ino)
		ino_t ino;
	{
		static daddr_t iblk;
		static struct dinode *itab;
		static u_int itabsize;
		register daddr_t b;

	#ifdef fancy
		if (ino < ROOTINO)
			return (NULL);
	#endif
		if (itab == NULL) {
			/*
			 * Allocate a table of the appropriate size.
			 */
			iblk = (daddr_t) -1;
			itabsize = INOPB(&sblock) * sizeof (*itab);
			itab = (struct dinode *) malloc(itabsize);
			if (itab == NULL)
				error...
		}

		/*
		 * Inode is in block `File System Block to Disk Block' of
		 * file system block `Inode to Disk block' of inode.
		 */
		b = fsbtodb(&sblock, itod(&sblock, ino));
		if (b != iblk) {
			b = iblk;
			bread(b, (char *)itab, itabsize);
		}
		return (&itab[ino % INOPB(&sblock)]);
	}

	bread(bno, buf, cnt)
		daddr_t bno;
		char *buf;
	{

		lseek(diskfd, (off_t) dbtob(bno), 0);
		if (read(diskfd, buf, cnt) != cnt)
			error...
	}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu