From: curt@hoptoad.uucp (Curt Mayer)
Newsgroups: comp.unix.bsd
Subject: Almost Free Symbolic Links (source code)
Date: 13 Dec 92 02:45:58 GMT
Distribution: world
Organization: kernel hackers R us
Keywords: symlink data in inode block list
Summary: cute hack

---------cut anywhere near here----------
: To unbundle, sh this file
#!/bin/sh
mkdir .
echo ./README
cat >./README <<'@@@ Fin de ./README'
this cruddy but complete hack answers one of the objections to symlinks:
that they are slow, and cost an entire frag. symlinks of less than length
60 are stored in the inode itself. symlinks longer than this are still
in the inode. to make the illusion of normality complete, dump and fsck
are hacked. additionally, I made dumpfs verbose to excess.

stability is perfect, having been in since 0.1 came out.

to create fast symlinks, just put FASTLINKS in your kernel options, reconfig
and rebuild.
if you try to read a filesystem containing fast links with a kernel not built
for them, you just get an einval when you reference any fast link. I call that
a soft failure. a floppy boot disk needn't contain any symlinks anyway.

share and enjoy.

legalese:
hack, slash, and redistribute all you want, just don't claim you wrote it.

@@@ Fin de ./README
echo ./dump.diffs
cat >./dump.diffs <<'@@@ Fin de ./dump.diffs'
diff -c /usr/src/sbin/dump/dumptraverse.c /usr/src/sbin/dump.new/dumptraverse.c
*** /usr/src/sbin/dump/dumptraverse.c	Wed Apr 24 17:55:03 1991
--- /usr/src/sbin/dump.new/dumptraverse.c	Mon Nov  2 21:50:31 1992
***************
*** 308,313 ****
--- 308,320 ----
  		writeheader(ino);
  		return;
  	}
+ 	if (DFASTLINK(*dp)) {
+ 		spcl.c_addr[0] = 1;
+ 		spcl.c_count = 1;
+ 		writeheader(ino);
+ 		writerec(dp->di_symlink);
+ 		return;
+ 	}
  	if (dp->di_size > NDADDR * sblock->fs_bsize)
  		cnt = NDADDR * sblock->fs_frag;
  	else
@@@ Fin de ./dump.diffs
echo ./fsck.diffs
cat >./fsck.diffs <<'@@@ Fin de ./fsck.diffs'
diff -c /usr/src/sbin/fsck/inode.c /usr/src/sbin/fsck.new/inode.c
*** /usr/src/sbin/fsck/inode.c	Sat Apr 20 14:39:03 1991
--- /usr/src/sbin/fsck.new/inode.c	Thu Oct 29 23:43:25 1992
***************
*** 58,64 ****
  		idesc->id_fix = DONTKNOW;
  	idesc->id_entryno = 0;
  	idesc->id_filesize = dp->di_size;
! 	if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR)
  		return (KEEPON);
  	dino = *dp;
  	ndb = howmany(dino.di_size, sblock.fs_bsize);
--- 58,65 ----
  		idesc->id_fix = DONTKNOW;
  	idesc->id_entryno = 0;
  	idesc->id_filesize = dp->di_size;
! 	if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR ||
! 		DFASTLINK(*dp))
  		return (KEEPON);
  	dino = *dp;
  	ndb = howmany(dino.di_size, sblock.fs_bsize);
diff -c /usr/src/sbin/fsck/pass1.c /usr/src/sbin/fsck.new/pass1.c
*** /usr/src/sbin/fsck/pass1.c	Sat Apr 20 14:39:04 1991
--- /usr/src/sbin/fsck.new/pass1.c	Tue Nov  3 02:24:23 1992
***************
*** 101,106 ****
--- 101,113 ----
  				continue;
  			}
  			lastino = inumber;
+ 			/* is fast symlink? */
+ 			if (DFASTLINK(*dp)) {
+ 				lncntp[inumber] = dp->di_nlink;
+ 				statemap[inumber] = FSTATE;
+ 				n_files++;
+ 				continue;
+ 			}
  			if (/* dp->di_size < 0 || */
  			    dp->di_size + sblock.fs_bsize - 1 < dp->di_size) {
  				if (debug)
diff -c /usr/src/sbin/fsck/pass5.c /usr/src/sbin/fsck.new/pass5.c
*** /usr/src/sbin/fsck/pass5.c	Sat Apr 20 14:39:05 1991
--- /usr/src/sbin/fsck.new/pass5.c	Fri Oct 30 02:20:20 1992
***************
*** 109,118 ****
--- 109,122 ----
  		dmax = dbase + fs->fs_fpg;
  		if (dmax > fs->fs_size)
  			dmax = fs->fs_size;
+ #ifdef notdef
  		if (now > cg->cg_time)
  			newcg->cg_time = cg->cg_time;
  		else
  			newcg->cg_time = now;
+ #else
+ 		newcg->cg_time = cg->cg_time;
+ #endif
  		newcg->cg_cgx = c;
  		if (c == fs->fs_ncg - 1)
  			newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg;
@@@ Fin de ./fsck.diffs
echo ./ufs.diffs
cat >./ufs.diffs <<'@@@ Fin de ./ufs.diffs'
diff -c /usr/src/sys.386bsd/ufs/dinode.h /usr/src/sys.386bsd/ufs.new/dinode.h
*** /usr/src/sys.386bsd/ufs/dinode.h	Tue Dec 24 14:24:20 1991
--- /usr/src/sys.386bsd/ufs.new/dinode.h	Thu Oct 29 21:17:53 1992
***************
*** 41,46 ****
--- 41,48 ----
  #define	NDADDR	12		/* direct addresses in inode */
  #define	NIADDR	3		/* indirect addresses in inode */
  
+ #define	MAXFASTLINK	(((NDADDR+NIADDR) * sizeof(daddr_t)) - 1)
+ 
  struct dinode {
  	u_short	di_mode;	/*  0: mode and type of file */
  	short	di_nlink;	/*  2: number of links to file */
***************
*** 53,60 ****
  	long	di_mtspare;
  	time_t	di_ctime;	/* 32: last time inode changed */
  	long	di_ctspare;
! 	daddr_t	di_db[NDADDR];	/* 40: disk block addresses */
! 	daddr_t	di_ib[NIADDR];	/* 88: indirect blocks */
  	long	di_flags;	/* 100: status, currently unused */
  	long	di_blocks;	/* 104: blocks actually held */
  	long	di_gen;		/* 108: generation number */
--- 55,67 ----
  	long	di_mtspare;
  	time_t	di_ctime;	/* 32: last time inode changed */
  	long	di_ctspare;
! 	union {
! 		struct {
! 			daddr_t	di_udb[NDADDR];	/* 40: disk block addresses */
! 			daddr_t	di_uib[NIADDR];	/* 88: indirect blocks */
! 		} di_addr;
! 		char di_usymlink[MAXFASTLINK];
! 	} di_un;
  	long	di_flags;	/* 100: status, currently unused */
  	long	di_blocks;	/* 104: blocks actually held */
  	long	di_gen;		/* 108: generation number */
***************
*** 61,66 ****
--- 68,77 ----
  	long	di_spare[4];	/* 112: reserved, currently unused */
  };
  
+ #define	di_db		di_un.di_addr.di_udb
+ #define	di_ib		di_un.di_addr.di_uib
+ #define	di_symlink	di_un.di_usymlink
+ 
  #if BYTE_ORDER == LITTLE_ENDIAN || defined(tahoe) /* ugh! -- must be fixed */
  #define	di_size		di_qsize.val[0]
  #else /* BYTE_ORDER == BIG_ENDIAN */
***************
*** 84,86 ****
--- 95,103 ----
  #define	IREAD		0400		/* read permission */
  #define	IWRITE		0200		/* write permission */
  #define	IEXEC		0100		/* execute permission */
+ 
+ #define	DFASTLINK(di) \
+ 	((((di).di_mode & IFMT) == IFLNK) && \
+ 		((di).di_size <= MAXFASTLINK) && \
+ 		((di).di_size == (di).di_spare[0]))
+ 
diff -c /usr/src/sys.386bsd/ufs/inode.h /usr/src/sys.386bsd/ufs.new/inode.h
*** /usr/src/sys.386bsd/ufs/inode.h	Tue Dec 24 14:24:20 1991
--- /usr/src/sys.386bsd/ufs.new/inode.h	Thu Oct 29 21:17:15 1992
***************
*** 67,72 ****
--- 67,74 ----
  	struct	dinode i_din;	/* the on-disk dinode */
  };
  
+ #define	FASTLINK(ip)	(DFASTLINK((ip)->i_din))
+ #define	i_symlink	i_din.di_symlink
  #define	i_mode		i_din.di_mode
  #define	i_nlink		i_din.di_nlink
  #define	i_uid		i_din.di_uid
diff -c /usr/src/sys.386bsd/ufs/ufs_inode.c /usr/src/sys.386bsd/ufs.new/ufs_inode.c
*** /usr/src/sys.386bsd/ufs/ufs_inode.c	Tue Dec 24 14:24:20 1991
--- /usr/src/sys.386bsd/ufs.new/ufs_inode.c	Thu Oct 29 21:16:02 1992
***************
*** 406,411 ****
--- 406,418 ----
  	struct inode tip;
  
  	vnode_pager_setsize(ITOV(oip), length);
+ 	if (FASTLINK(oip)) {
+ 		if (length != 0)
+ 			panic("itrunc fastlink to non-zero");
+ 		bzero(oip->i_symlink, MAXFASTLINK);
+ 		oip->i_size = 0;
+ 		oip->i_din.di_spare[0] = 0;
+ 	}
  	if (oip->i_size <= length) {
  		oip->i_flag |= ICHG|IUPD;
  		error = iupdat(oip, &time, &time, 1);
diff -c /usr/src/sys.386bsd/ufs/ufs_vnops.c /usr/src/sys.386bsd/ufs.new/ufs_vnops.c
*** /usr/src/sys.386bsd/ufs/ufs_vnops.c	Tue Dec 24 14:24:21 1991
--- /usr/src/sys.386bsd/ufs.new/ufs_vnops.c	Thu Oct 29 21:28:34 1992
***************
*** 31,36 ****
--- 31,44 ----
   * SUCH DAMAGE.
   *
   *	@(#)ufs_vnops.c	7.64 (Berkeley) 5/16/91
+  *
+  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
+  * --------------------         -----   ----------------------
+  * CURRENT PATCH LEVEL:         1       00007
+  * --------------------         -----   ----------------------
+  *
+  * 20 Aug 92	David Greenman		Fixed incorrect setting of B_AGE after
+  *					each read to improve cache performance
   */
  
  #include "param.h"
***************
*** 497,504 ****
--- 505,514 ----
  			return (error);
  		}
  		error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
+ #if OMIT	/* 20 Aug 92*/
  		if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
  			bp->b_flags |= B_AGE;
+ #endif	/* OMIT*/
  		brelse(bp);
  	} while (error == 0 && uio->uio_resid > 0 && n != 0);
  	return (error);
***************
*** 1267,1278 ****
  	struct proc *p;
  {
  	struct inode *ip;
  	int error;
  
  	error = maknode(IFLNK | vap->va_mode, ndp, &ip);
  	if (error)
  		return (error);
! 	error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0,
  		UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0,
  		(struct proc *)0);
  	iput(ip);
--- 1277,1298 ----
  	struct proc *p;
  {
  	struct inode *ip;
+ 	int len = strlen(target);
  	int error;
  
  	error = maknode(IFLNK | vap->va_mode, ndp, &ip);
  	if (error)
  		return (error);
! #ifdef FASTLINKS
! 	if (len <= MAXFASTLINK) {
! 		ip->i_din.di_spare[0] = len;
! 		ip->i_size = len;
! 		bcopy(target, ip->i_symlink, len);
! 		ip->i_flag |= ICHG;
! 		error = iupdat(ip, &time, &time, 1);
! 	} else
! #endif
! 	error = vn_rdwr(UIO_WRITE, ITOV(ip), target, len, (off_t)0,
  		UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0,
  		(struct proc *)0);
  	iput(ip);
***************
*** 1314,1321 ****
  	struct uio *uiop;
  	struct ucred *cred;
  {
! 
! 	return (ufs_read(vp, uiop, 0, cred));
  }
  
  /*
--- 1334,1344 ----
  	struct uio *uiop;
  	struct ucred *cred;
  {
! 	struct inode *ip = VTOI(vp);
! 	if (FASTLINK(ip))
! 		return (uiomove(ip->i_symlink, ip->i_size, uiop));
! 	else
! 		return (ufs_read(vp, uiop, 0, cred));
  }
  
  /*
@@@ Fin de ./ufs.diffs
mkdir ./usr
mkdir ./usr/src
mkdir ./usr/src/sbin
mkdir ./usr/src/sbin/dumpfs
echo ./usr/src/sbin/dumpfs/dumpfs.c
cat >./usr/src/sbin/dumpfs/dumpfs.c <<'@@@ Fin de ./usr/src/sbin/dumpfs/dumpfs.c'
#define	EXTREME
/*
 * Copyright (c) 1983 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * added much verbose hackery in conjunction with fast symlinks.
 * curt mayer, 11 Dec 1992
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)dumpfs.c	5.10 (Berkeley) 6/1/90";
#endif /* not lint */

#include <sys/param.h>
#include <ufs/dinode.h>
#include <ufs/dir.h>
#include <ufs/fs.h>

#include <stdio.h>
#include <fstab.h>

/*
 * dumpfs
 */

union {
	struct fs fs;
	char pad[MAXBSIZE];
} fsun;
#define	afs	fsun.fs

union {
	struct cg cg;
	char pad[MAXBSIZE];
} cgun;
#define	acg	cgun.cg

struct dinode *din;

extern char *malloc();

long	dev_bsize = 1;

main(argc, argv)
	char **argv;
{
	register struct fstab *fs;

	argc--, argv++;
	if (argc < 1) {
		fprintf(stderr, "usage: dumpfs fs ...\n");
		exit(1);
	}
	for (; argc > 0; argv++, argc--) {
		fs = getfsfile(*argv);
		if (fs == 0)
			dumpfs(*argv);
		else
			dumpfs(fs->fs_spec);
	}
}

dumpfs(name)
	char *name;
{
	int c, i, j, k, size;

	close(0);
	if (open(name, 0) != 0) {
		perror(name);
		return;
	}
	lseek(0, SBOFF, 0);
	if (read(0, &afs, SBSIZE) != SBSIZE) {
		perror(name);
		return;
	}
	if (afs.fs_postblformat == FS_42POSTBLFMT)
		afs.fs_nrpos = 8;
	dev_bsize = afs.fs_fsize / fsbtodb(&afs, 1);
	if (afs.fs_inopb > 0 && afs.fs_inopb <= 1024) {
		din = (struct dinode *)
			malloc(afs.fs_inopb * sizeof(struct dinode));
	}
	printf("magic\t%x\tformat\t%s\ttime\t%s", afs.fs_magic,
	    afs.fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
	    ctime(&afs.fs_time));
	printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
	    afs.fs_cstotal.cs_nbfree, afs.fs_cstotal.cs_ndir,
	    afs.fs_cstotal.cs_nifree, afs.fs_cstotal.cs_nffree);
	printf("ncg\t%d\tncyl\t%d\tsize\t%d\tblocks\t%d\n",
	    afs.fs_ncg, afs.fs_ncyl, afs.fs_size, afs.fs_dsize);
	printf("bsize\t%d\tshift\t%d\tmask\t0x%08x\n",
	    afs.fs_bsize, afs.fs_bshift, afs.fs_bmask);
	printf("fsize\t%d\tshift\t%d\tmask\t0x%08x\n",
	    afs.fs_fsize, afs.fs_fshift, afs.fs_fmask);
	printf("frag\t%d\tshift\t%d\tfsbtodb\t%d\n",
	    afs.fs_frag, afs.fs_fragshift, afs.fs_fsbtodb);
	printf("cpg\t%d\tbpg\t%d\tfpg\t%d\tipg\t%d\n",
	    afs.fs_cpg, afs.fs_fpg / afs.fs_frag, afs.fs_fpg, afs.fs_ipg);
	printf("minfree\t%d%%\toptim\t%s\tmaxcontig %d\tmaxbpg\t%d\n",
	    afs.fs_minfree, afs.fs_optim == FS_OPTSPACE ? "space" : "time",
	    afs.fs_maxcontig, afs.fs_maxbpg);
	printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
	    afs.fs_rotdelay, afs.fs_headswitch, afs.fs_trkseek, afs.fs_rps);
	printf("ntrak\t%d\tnsect\t%d\tnpsect\t%d\tspc\t%d\n",
	    afs.fs_ntrak, afs.fs_nsect, afs.fs_npsect, afs.fs_spc);
	printf("trackskew %d\tinterleave %d\n",
	    afs.fs_trackskew, afs.fs_interleave);
	printf("nindir\t%d\tinopb\t%d\tnspf\t%d\n",
	    afs.fs_nindir, afs.fs_inopb, afs.fs_nspf);
	printf("sblkno\t%d\tcblkno\t%d\tiblkno\t%d\tdblkno\t%d\n",
	    afs.fs_sblkno, afs.fs_cblkno, afs.fs_iblkno, afs.fs_dblkno);
	printf("sbsize\t%d\tcgsize\t%d\tcgoffset %d\tcgmask\t0x%08x\n",
	    afs.fs_sbsize, afs.fs_cgsize, afs.fs_cgoffset, afs.fs_cgmask);
	printf("csaddr\t%d\tcssize\t%d\tshift\t%d\tmask\t0x%08x\n",
	    afs.fs_csaddr, afs.fs_cssize, afs.fs_csshift, afs.fs_csmask);
	printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\n",
	    afs.fs_cgrotor, afs.fs_fmod, afs.fs_ronly);
	if (afs.fs_cpc != 0)
		printf("blocks available in each of %d rotational positions",
		     afs.fs_nrpos);
	else
		printf("insufficient space to maintain rotational tables\n");
	for (c = 0; c < afs.fs_cpc; c++) {
		printf("\ncylinder number %d:", c);
		for (i = 0; i < afs.fs_nrpos; i++) {
			if (fs_postbl(&afs, c)[i] == -1)
				continue;
			printf("\n   position %d:\t", i);
			for (j = fs_postbl(&afs, c)[i], k = 1; ;
			     j += fs_rotbl(&afs)[j], k++) {
				printf("%5d", j);
				if (k % 12 == 0)
					printf("\n\t\t");
				if (fs_rotbl(&afs)[j] == 0)
					break;
			}
		}
	}
	printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
	for (i = 0, j = 0; i < afs.fs_cssize; i += afs.fs_bsize, j++) {
		size = afs.fs_cssize - i < afs.fs_bsize ?
		    afs.fs_cssize - i : afs.fs_bsize;
		afs.fs_csp[j] = (struct csum *)calloc(1, size);
		lseek(0, fsbtodb(&afs, (afs.fs_csaddr + j * afs.fs_frag)) *
		    dev_bsize, 0);
		if (read(0, afs.fs_csp[j], size) != size) {
			perror(name);
			return;
		}
	}
	for (i = 0; i < afs.fs_ncg; i++) {
		struct csum *cs = &afs.fs_cs(&afs, i);
		if (i && i % 4 == 0)
			printf("\n\t");
		printf("(%d,%d,%d,%d) ",
		    cs->cs_nbfree, cs->cs_ndir, cs->cs_nifree, cs->cs_nffree);
	}
	printf("\n");
	if (afs.fs_ncyl % afs.fs_cpg) {
		printf("cylinders in last group %d\n",
		    i = afs.fs_ncyl % afs.fs_cpg);
		printf("blocks in last group %d\n",
		    i * afs.fs_spc / NSPB(&afs));
	}
	printf("\n");
	for (i = 0; i < afs.fs_ncg; i++)
		dumpcg(name, i);
	close(0);
};

static char xxbuf[11];

char *
modestr(k)
unsigned short k;
{
	int type, i, mode;

	type = ((k & IFMT) >> 12) & 0xf;
	xxbuf[0] = ".=c.d.b.-.l.s..."[type];
	for (i = 0; i < 3; i++) {
		mode = (k << (i * 3)) & (IREAD | IWRITE | IEXEC);
		xxbuf[1 + (i * 3) + 0] = (mode & IREAD) ? 'r' : '-';
		xxbuf[1 + (i * 3) + 1] = (mode & IWRITE) ? 'w' : '-';
		xxbuf[1 + (i * 3) + 2] = (mode & IEXEC) ? 'x' : '-';
	}
	if (k & ISUID) xxbuf[1 + (0 * 3) + 2] = 's';
	if (k & ISGID) xxbuf[1 + (1 * 3) + 2] = 's';
	if (k & ISVTX) xxbuf[1 + (2 * 3) + 2] = 's';
	xxbuf[10] = '\0';
	return (xxbuf);	
}

dumpcg(name, c)
	char *name;
	int c;
{
	int i, j;

	printf("\ncg %d:\n", c);
	lseek(0, fsbtodb(&afs, cgtod(&afs, c)) * dev_bsize, 0);
	i = lseek(0, 0, 1);
	if (read(0, (char *)&acg, afs.fs_bsize) != afs.fs_bsize) {
		printf("dumpfs: %s: error reading cg\n", name);
		return;
	}
	printf("magic\t%x\ttell\t%x\ttime\t%s",
	    afs.fs_postblformat == FS_42POSTBLFMT ?
	    ((struct ocg *)&acg)->cg_magic : acg.cg_magic,
	    i, ctime(&acg.cg_time));
	printf("cgx\t%d\tncyl\t%d\tniblk\t%d\tndblk\t%d\n",
	    acg.cg_cgx, acg.cg_ncyl, acg.cg_niblk, acg.cg_ndblk);
	printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
	    acg.cg_cs.cs_nbfree, acg.cg_cs.cs_ndir,
	    acg.cg_cs.cs_nifree, acg.cg_cs.cs_nffree);
	printf("rotor\t%d\tirotor\t%d\tfrotor\t%d\nfrsum",
	    acg.cg_rotor, acg.cg_irotor, acg.cg_frotor);
	for (i = 1, j = 0; i < afs.fs_frag; i++) {
		printf("\t%d", acg.cg_frsum[i]);
		j += i * acg.cg_frsum[i];
	}
	printf("\nsum of frsum: %d\niused:\t", j);
	pbits(c * afs.fs_ipg, cg_inosused(&acg), afs.fs_ipg);
	printf("free:\t");
	pbits(c * afs.fs_fpg, cg_blksfree(&acg), afs.fs_fpg);
	printf("b:\n");
	for (i = 0; i < afs.fs_cpg; i++) {
		if (cg_blktot(&acg)[i] == 0)
			continue;
		printf("   c%d:\t(%d)\t", i, cg_blktot(&acg)[i]);
		for (j = 0; j < afs.fs_nrpos; j++) {
			if (afs.fs_cpc > 0 &&
			    fs_postbl(&afs, i % afs.fs_cpc)[j] == -1)
				continue;
			printf(" %d", cg_blks(&afs, &acg, i)[j]);
		}
		printf("\n");
	}
	if (din)
		dumpinodes(c, name);
};

dumpinodes(c, name)
int c;
char *name;
{
	int i, j, k, l, m;

	printf("inum\tmode\t\tlinks\tuid\tgid\tblocks\tsize\n");
	for (i = 0; i < acg.cg_niblk; i += INOPB(&afs)) {
		j = (afs.fs_ipg * c) + i;
		lseek(0, (fsbtodb(&afs, itod(&afs, j)) * dev_bsize), 0);
		if (read(0, (char *)din, INOPB(&afs) * sizeof(struct dinode)) != 
		    INOPB(&afs) * sizeof(struct dinode)) {
			printf("dumpfs: %s: error reading inode\n", name);
			return;
		}
		for (k = 0; k < INOPB(&afs); k++) {
#ifdef EXTREME
			int l, m;
			char *p;
			char c;
#endif
			if (!din[k].di_mode)
				continue;
#ifdef EXTREME
			p = (char *)&din[k];
			for (l = 0; l < sizeof(din[k]); l += 16) {
				for (m = 0; m < 16; m++) {
					printf("%02x ", p[l+m] & 0xff);
				}
				printf("  ");
				for (m = 0; m < 16; m++) {
					c = p[l+m];
					if (c < 0x20 || c > 0x7e) c = '.';
					printf("%c", c);
				}
				printf("\n");
			}
			printf("\n");
#endif
			printf("%d\t%s\t%d\t%d\t%d\t%d\t%d\n\t",
				j + k, modestr(din[k].di_mode),
				din[k].di_nlink, 
				din[k].di_uid,  din[k].di_gid, 
				din[k].di_blocks, din[k].di_size);

			/* dump fast symlink */
			if (((din[k].di_mode & IFMT) == IFLNK) &&
			    (din[k].di_size <= MAXFASTLINK) &&
			    (din[k].di_size == din[k].di_spare[0])) {
				printf("%s\n\n", din[k].di_symlink);
				continue;
			}

			/* dump cdev/bdev */
			if (((din[k].di_mode & IFMT) == IFCHR) ||
			    ((din[k].di_mode & IFMT) == IFBLK)) {
				printf("major %d minor %d (0x%x)\n\n", 
					major(din[k].di_rdev),
					minor(din[k].di_rdev),
					minor(din[k].di_rdev));
				continue;
			}
			
			/* dump normal symlink */
			if (((din[k].di_mode & IFMT) == IFLNK) &&
			    ((din[k].di_size > MAXFASTLINK) ||
			     (din[k].di_size != din[k].di_spare[0]))) {
				dumpsymlink(din[k].di_db[0], din[k].di_size, 
					name);
			}

			/* dump directory */
			if (((din[k].di_mode & IFMT) == IFDIR)) {
				printf("ino\tname\n\t");
				for (l = 0; l < NDADDR; l++) {
					dumpdirblk(din[k].di_db[l], 
						dblksize(&afs,&din[k], l), 
						name);
				}
				if (din[k].di_ib[0]) {
					printf("huge directory\n");
				}
				printf("\n\t");
			}

			/* dump direct blocks */
			for (m = NDADDR - 1; m >= 0; m--) {
				if (din[k].di_db[m] != 0)
					break;
			}
			for (l = 0 ; l <= m; l++) {
				printf("%d\t", din[k].di_db[l]);
				if (((l + 1) % 8) == 0) printf("\n\t");
			}
			if ((l % 8) != 0)
				printf("\n");
			printf("\n");

			/* dump indirect blocks */
			for (m = NIADDR - 1; m >= 0; m--) {
				if (din[k].di_ib[m] != 0)
					break;
			}
			for (l = 0 ; l <= m; l++) {
				dumpindir(l, din[k].di_ib[l], name);
			}
		}
	}
}

dumpdirblk(b, bs, name)
int b;
int bs;
char *name;
{
	char *s, *p;
	struct direct *d;

	if (!b)
		return;

	lseek(0, fsbtodb(&afs, b) * dev_bsize, 0);
	s = malloc(bs);
	if (!s) {
		printf("malloc failed\n");
		return;
	}
	if (read(0, s, bs) != bs) {
		printf("dumpfs: %s: error reading directory block\n", name);
	}
	for (p = s; p < &s[bs]; p += d->d_reclen) {
		d = (struct direct *)p;
		if (d->d_reclen > DIRSIZ(d))
			continue;
		printf("%d\t%s\n\t", d->d_ino, d->d_name);
	}
}

dumpsymlink(b, len, name)
int b;
int len;
char *name;
{
	int i;
	int m;
	char *s;

	lseek(0, fsbtodb(&afs, b) * dev_bsize, 0);
	s = malloc(afs.fs_bsize);
	if (!s) {
		printf("malloc failed\n");
		return;
	}
	if (read(0, s, afs.fs_bsize) != afs.fs_bsize) {
		printf("dumpfs: %s: error reading symlink block\n", name);
	}
	s[len] = '\0';
	printf("%s\n\t", s);
	free(s);
}

dumpindir(d, b, name)
int d;
int b;
char *name;
{
	daddr_t *indirs;
	int i;
	int m;

	printf("\tI%d %d:\n", d, b);
	if (b == 0)
		return;

	indirs = (daddr_t *)malloc(afs.fs_nindir * sizeof(daddr_t));
	lseek(0, fsbtodb(&afs, b) * dev_bsize, 0);
	if (read(0, (char *)indirs, afs.fs_nindir * sizeof(daddr_t)) != 
	    afs.fs_nindir * sizeof(daddr_t)) {
		printf("dumpfs: %s: error reading indirect block\n", name);
	}
	if (d == 0) {
		printf("\t");
		
		for (m = afs.fs_nindir - 1; m >= 0; m--) {
			if (indirs[m] != 0)
				break;
		}
		for (i = 0; i <= m; i++) {
			printf("%d\t", indirs[i]);
			if (((i + 1) % 8) == 0) printf("\n\t");
		}
		if ((i % 8) != 0)
			printf("\n");
		printf("\n");
	} else {
		for (m = afs.fs_nindir - 1; m >= 0; m--) {
			if (indirs[m] != 0)
				break;
		}
		for (i = 0; i <= m; i++) {
			dumpindir(d - 1, indirs[i], name);
		}
	}
	free((char *)indirs);
}

pbits(base, cp, max)
	int base;
	register char *cp;
	int max;
{
	register int i;
	int count = 0, j;
	int width = 0;

	for (i = 0; i < max; i++)
		if (isset(cp, i)) {
			if (count) {
				width += printf(",");
				if (width > 55) {
					printf("\n\t");
					width = 0;
				}
			}
			count++;
			width += printf("%d", i+base);
			j = i;
			while ((i+1)<max && isset(cp, i+1))
				i++;
			if (i != j)
				width += printf("-%d", i+base);
		}
	printf("\n");
}
@@@ Fin de ./usr/src/sbin/dumpfs/dumpfs.c
exit 0
---------cut anywhere near here----------
-- 
	curt mayer
        curt@toad.com
        415-387-0217 home