[OpenAFS-devel] (patch) Adding utility to do a volume dump table of contents...
Marc Mengel
mengel@fnal.gov
Thu, 09 May 2002 14:32:34 -0500
--=-BI/zzuLtHCWVIp64i9RP
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
There is a utility (restorevol) in OpenAFS to unpack a vos dump image
into a file tree, but I wanted something to just give me a listing of
what files/directories were in the volume, so I hacked up the attached,
which adds "tocvol" to the OpenAFS tree to do a table of contents of a
vos dump image.
Why did I want this? I'm working on integrating AFS backups into
Amanda, and I wanted a table of contents of the volume dump so
I can have file level backup indexing...
Anyway, it's mostly restorevol with most of its guts replaced with
a (wimpy, horribly inefficient, but simple) vnode graph.
--=-BI/zzuLtHCWVIp64i9RP
Content-Disposition: inline; filename=openafs-tocvol-patch
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-patch; name=openafs-tocvol-patch; charset=ISO-8859-1
*** src/volser/Makefile.in.orig Thu May 9 11:43:41 2002
--- src/volser/Makefile.in Thu May 9 11:42:21 2002
***************
*** 8,14 ****
srcdir=3D@srcdir@
include @TOP_OBJDIR@/src/config/Makefile.config
=20
-=20
CFLAGS=3D-I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${T=
OP_INCDIR} ${XCFLAGS}
LDFLAGS=3D${DBG} ${OPTMZ} ${XLDFLAGS}
=20
--- 8,13 ----
***************
*** 48,54 ****
SOBJS=3Dvolmain.o volprocs.o physio.o common.o voltrans.o volerr.o \
volint.cs.o dumpstuff.o volint.ss.o volint.xdr.o
=20
! all: volserver vos restorevol \
${TOP_INCDIR}/afs/volser.h \
${TOP_INCDIR}/afs/volint.h \
${TOP_LIBDIR}/libvolser.a
--- 47,53 ----
SOBJS=3Dvolmain.o volprocs.o physio.o common.o voltrans.o volerr.o \
volint.cs.o dumpstuff.o volint.ss.o volint.xdr.o
=20
! all: volserver vos restorevol tocvol \
${TOP_INCDIR}/afs/volser.h \
${TOP_INCDIR}/afs/volint.h \
${TOP_LIBDIR}/libvolser.a
***************
*** 57,62 ****
--- 56,65 ----
${CC} ${CFLAGS} -o restorevol ${srcdir}/restorevol.c \
${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a
=20
+ tocvol: tocvol.c
+ ${CC} ${CFLAGS} -o tocvol ${srcdir}/tocvol.c \
+ ${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a
+=20
vos: vos.o ${VSOBJS} libvolser.a ${LIBS}
${CC} ${LDFLAGS} -o vos vos.o $(VSOBJS) libvolser.a ${LIBS} ${XLIBS}
=20
***************
*** 111,116 ****
--- 114,120 ----
#
install: \
${DESTDIR}${sbindir}/restorevol \
+ ${DESTDIR}${sbindir}/tocvol \
${DESTDIR}${includedir}/afs/volser.h \
${DESTDIR}${includedir}/afs/volint.h \
${DESTDIR}${sbindir}/vos \
***************
*** 126,131 ****
--- 130,138 ----
${INSTALL} $? $@
=20
${DEST}/etc/restorevol: restorevol
+ ${INSTALL} $? $@
+=20
+ ${DEST}/etc/tocvol: tocvol
${INSTALL} $? $@
=20
${DEST}/etc/vos ${DEST}/root.server/usr/afs/bin/vos: vos
*** src/volser/tocvol.c.orig Thu May 9 13:54:52 2002
--- src/volser/tocvol.c Thu May 9 13:58:11 2002
***************
*** 0 ****
--- 1,715 ----
+ /*
+ * Copyright 2000, International Business Machines Corporation and others=
.
+ * All Rights Reserved.
+ *=20
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+=20
+ /*
+ * Read a vos dump and print a table of contents
+ *
+ * tocvol [-file <dump file>]
+ * [-dir <restore dir>]
+ * [-extension <name extension>]
+ * [-mountpoint <mount point root>]
+ * [-umask <mode mask>]
+ * Based on restorevol, but with an internal index instead of symlinks.
+ *
+ */
+=20
+ #include <afsconfig.h>
+ #include <afs/param.h>
+=20
+ RCSID("$Header: /cvs/openafs/src/volser/restorevol.c,v 1.6 2001/08/08 00:=
04:26 shadow Exp $");
+=20
+ #include <afs/afsint.h>
+ #include <afs/nfs.h>
+ #include <lock.h>
+ #include <afs/ihandle.h>
+ #include <afs/vnode.h>
+ #include <afs/volume.h>
+ #include "volint.h"
+ #include "dump.h"
+ #include <afs/cmd.h>
+=20
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <sys/uio.h>
+ #include <stdio.h>
+ #include <errno.h>
+ #include <netinet/in.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <dirent.h>
+=20
+ struct vmapnode {
+ char *name;
+ int parent;
+ char printed;
+ char isset;
+ } *vnodemap =3D 0;
+ int vnodemaplen =3D 0;
+ int vnodemapmax =3D 0;
+=20
+ growvnodemap(int n) {
+ int i;
+ if (n > vnodemapmax) {
+ vnodemapmax =3D 2 * n;
+ /* fprintf(stderr,"growing map to %d\n", vnodemapmax); */
+ /* fflush(stderr); */
+ vnodemap =3D realloc(vnodemap, sizeof(struct vmapnode) * vnodemapmax );
+ for ( i =3D vnodemaplen+1; i < vnodemapmax; i++ )
+ vnodemap[i].isset =3D 0;
+ }
+ if (n > vnodemaplen)
+ vnodemaplen =3D n;
+ }
+=20
+ void
+ setvnode(int n, char *name, int parent) {
+ /* fprintf(stderr, "setting map for %d to %s parent %d\n", n, name, p=
arent); */
+ /* fflush(stderr); */
+ growvnodemap(n);
+ vnodemap[n].name =3D (char *)strdup(name);
+ vnodemap[n].parent =3D parent;
+ vnodemap[n].isset =3D 1;
+ }
+=20
+ int
+ getvnodename(int n, char *p, int max) {
+ int len, nlen;
+ /* printf("getvnodename(%d)\n", n); */
+ if( vnodemap[n].isset ) {
+ nlen =3D strlen(vnodemap[n].name);
+ if (n !=3D 1 && vnodemap[n].parent !=3D n ) {
+ len =3D getvnodename(vnodemap[n].parent, p, max);
+ } else {=20
+ /* root vnode */
+ p[0] =3D '.';
+ p[1] =3D 0;
+ return 1;
+ }
+ if (len !=3D 0 && len + nlen + 1 < max) {
+ strcat(p+len, "/");
+ strcat(p+len, vnodemap[n].name);
+ return len + nlen + 1;
+ }
+ } else {=20
+ /* printf("notset\n") */;
+ }
+ return 0;
+ }
+=20
+ int printvnode(int n) {
+ char buf[1024];
+ int len;
+ /* printf ("printvnode %d\n", n); */
+ if (!vnodemap[n].printed && vnodemap[n].isset) {
+ len =3D getvnodename(n, buf, 1024);
+ if( len !=3D 0 ) {
+ printf("%s\n", buf);
+ vnodemap[n].printed =3D 1;
+ } =20
+ }
+ }
+=20
+ int inc_dump =3D 0;
+=20
+ FILE *dumpfile;
+=20
+ afs_int32 readvalue(size)
+ {
+ afs_int32 value, s;
+ int code;
+ char *ptr;
+=20
+ value =3D 0;
+ ptr =3D (char *) &value;
+=20
+ s =3D sizeof(value) - size;
+ if (size < 0) {
+ fprintf (stderr, "Too much data in afs_int32\n");
+ return 0;
+ }
+ =20
+ code =3D fread (&ptr[s], 1, size, dumpfile);
+ if (code !=3D size) fprintf (stderr, "Code =3D %d; Errno =3D %d\n", cod=
e, errno);
+=20
+ return (value);
+ }
+=20
+ char readchar()
+ {
+ char value;
+ int code;
+ char *ptr;
+=20
+ value =3D '\0';
+ code =3D fread (&value, 1, 1, dumpfile);
+ if (code !=3D 1) fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code, =
errno);
+=20
+ return (value);
+ }
+=20
+ #define BUFSIZE 16384
+ char buf[BUFSIZE];
+=20
+ char readdata(buffer, size)
+ char *buffer;
+ afs_int32 size;
+ {
+ int code;
+ afs_int32 s;
+=20
+ if (!buffer) {
+ while (size > 0) {
+ s =3D ((size > BUFSIZE) ? BUFSIZE : size);
+ code =3D fread(buf, 1, s, dumpfile);
+ if (code !=3D s) fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code,=
errno);
+ size -=3D s;
+ }
+ }
+ else {
+ code =3D fread (buffer, 1, size, dumpfile);
+ if (code !=3D size) {
+ if (code < 0)
+ fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code, errno);
+ else=20
+ fprintf (stderr, "Read %d bytes out of %d\n", code, size);
+ }
+ if ((code >=3D 0) && (code < BUFSIZE))
+ buffer[size] =3D 0; /* Add null char at end */
+ }
+ }
+=20
+ afs_int32 ReadDumpHeader(dh)
+ struct DumpHeader *dh; /* Defined in dump.h */
+ {
+ int code, i, done;
+ char tag, c;
+ afs_int32 magic;
+=20
+ /* memset(&dh, 0, sizeof(dh)); */
+=20
+ magic =3D ntohl(readvalue(4));
+ dh->version =3D ntohl(readvalue(4));
+=20
+ done =3D 0;
+ while (!done) {
+ tag =3D readchar();
+ switch (tag) {
+ case 'v':
+ dh->volumeId =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'n':
+ for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ dh->volumeName[i] =3D c =3D readchar();
+ }
+ dh->volumeName[i] =3D c;
+ break;
+=20
+ case 't':
+ dh->nDumpTimes =3D ntohl(readvalue(2)) >> 1;
+ for (i=3D0; i<dh->nDumpTimes; i++) {
+ dh->dumpTimes[i].from =3D ntohl(readvalue(4));
+ dh->dumpTimes[i].to =3D ntohl(readvalue(4));
+ }
+ break;
+=20
+ default:
+ done =3D 1;
+ break;
+ }
+ }
+=20
+ return((afs_int32)tag);
+ }
+=20
+ struct volumeHeader
+ {
+ afs_int32 volumeId;
+ char volumeName[100];
+ afs_int32 volType;
+ afs_int32 uniquifier;
+ afs_int32 parentVol;
+ afs_int32 cloneId;
+ afs_int32 maxQuota;
+ afs_int32 minQuota;
+ afs_int32 diskUsed;
+ afs_int32 fileCount;
+ afs_int32 accountNumber;
+ afs_int32 owner;
+ afs_int32 creationDate;
+ afs_int32 accessDate;
+ afs_int32 updateDate;
+ afs_int32 expirationDate;
+ afs_int32 backupDate;
+ afs_int32 dayUseDate;
+ afs_int32 dayUse;
+ afs_int32 weekCount;
+ afs_int32 weekUse[100]; /* weekCount of these */
+ char motd[1024];
+ int inService;
+ int blessed;
+ char message[1024];
+ };
+=20
+ afs_int32 ReadVolumeHeader(count)
+ afs_int32 count;
+ {
+ struct volumeHeader vh;
+ int code, i, done, entries;
+ char tag, c;
+=20
+ /* memset(&vh, 0, sizeof(vh)); */
+=20
+ done =3D 0;
+ while (!done) {
+ tag =3D readchar();
+ switch (tag) {
+ case 'i':
+ vh.volumeId =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'v':
+ ntohl(readvalue(4)); /* version stamp - ignore */
+ break;
+=20
+ case 'n':
+ for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ vh.volumeName[i] =3D c =3D readchar();
+ }
+ vh.volumeName[i] =3D c;
+ break;
+=20
+ case 's':
+ vh.inService =3D ntohl(readvalue(1));
+ break;
+=20
+ case 'b':
+ vh.blessed =3D ntohl(readvalue(1));
+ break;
+=20
+ case 'u':
+ vh.uniquifier =3D ntohl(readvalue(4));
+ break;
+=20
+ case 't':
+ vh.volType =3D ntohl(readvalue(1));
+ break;
+=20
+ case 'p':
+ vh.parentVol =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'c':
+ vh.cloneId =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'q':
+ vh.maxQuota =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'm':
+ vh.minQuota =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'd':
+ vh.diskUsed =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'f':
+ vh.fileCount =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'a':
+ vh.accountNumber =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'o':
+ vh.owner =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'C':
+ vh.creationDate =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'A':
+ vh.accessDate =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'U':
+ vh.updateDate =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'E':
+ vh.expirationDate =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'B':
+ vh.backupDate =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'O':
+ for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ vh.message[i] =3D c =3D readchar();
+ }
+ vh.volumeName[i] =3D c;
+ break;
+=20
+ case 'W':
+ vh.weekCount =3D ntohl(readvalue(2));
+ for (i=3D0; i<vh.weekCount; i++) {
+ vh.weekUse[i] =3D ntohl(readvalue(4));
+ }
+ break;
+=20
+ case 'M':
+ for (i=3D0, c=3D'a'; c!=3D'\0'; i++) {
+ vh.motd[i] =3D c =3D readchar();
+ }
+ break;
+=20
+ case 'D':
+ vh.dayUseDate =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'Z':
+ vh.dayUse =3D ntohl(readvalue(4));
+ break;
+=20
+ default:
+ done =3D 1;
+ break;
+ }
+ }
+=20
+ return((afs_int32)tag);
+ }
+=20
+ struct vNode
+ {
+ afs_int32 vnode;
+ afs_int32 uniquifier;
+ afs_int32 type;
+ afs_int32 linkCount;
+ afs_int32 dataVersion;
+ afs_int32 unixModTime;
+ afs_int32 servModTime;
+ afs_int32 author;
+ afs_int32 owner;
+ afs_int32 group;
+ afs_int32 modebits;
+ afs_int32 parent;
+ char acl[192];
+ #ifdef notdef
+ struct acl_accessList=20
+ {
+ int size; /*size of this access list in bytes, including My=
Size itself*/ =20
+ int version; /*to deal with upward compatibility ; <=3D ACL_AC=
LVERSION*/
+ int total;
+ int positive; /* number of positive entries */
+ int negative; /* number of minus entries */
+ struct acl_accessEntry=20
+ {
+ int id; /*internally-used ID of user or group*/
+ int rights; /*mask*/
+ } entries[100];
+ } acl;
+ #endif
+ afs_int32 dataSize;
+ };
+=20
+ #define MAXNAMELEN 256
+=20
+ afs_int32 ReadVNode(count, tocflag)
+ afs_int32 count;
+ int tocflag;
+ {
+ struct vNode vn;
+ int code, i, done, entries;
+ char tag, c;
+ char dirname[MAXNAMELEN], linkname[MAXNAMELEN], lname[MAXN=
AMELEN];
+ char parentdir[MAXNAMELEN], vflink[MAXNAMELEN];
+ char filename[MAXNAMELEN], fname[MAXNAMELEN];
+ int len;
+ afs_int32 vnode;
+ afs_int32 mode=3D0;
+=20
+ /* memset(&vn, 0, sizeof(vn)); */
+ vn.dataSize =3D 0;
+ vn.vnode =3D 0;
+ vn.parent =3D 0;
+ vn.type =3D 0;
+=20
+ vn.vnode =3D ntohl(readvalue(4));
+ vn.uniquifier =3D ntohl(readvalue(4));
+ =20
+ done =3D 0;
+ while (!done) {
+ tag =3D readchar();
+ switch (tag) {
+ case 't':
+ vn.type =3D ntohl(readvalue(1));
+ break;
+=20
+ case 'l':
+ vn.linkCount =3D ntohl(readvalue(2));
+ break;
+=20
+ case 'v':
+ vn.dataVersion =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'm':
+ vn.unixModTime =3D ntohl(readvalue(4));
+ break;
+=20
+ case 's':
+ vn.servModTime =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'a':
+ vn.author =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'o':
+ vn.owner =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'g':
+ vn.group =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'b':
+ vn.modebits =3D ntohl(readvalue(2));
+ break;
+=20
+ case 'p':
+ vn.parent =3D ntohl(readvalue(4));
+ break;
+=20
+ case 'A':
+ readdata(vn.acl, 192); /* Skip ACL data */
+ break;
+=20
+ case 'f':
+ vn.dataSize =3D ntohl(readvalue(4));
+=20
+ /* parentdir is the name of this dir's vnode-file-link
+ * or this file's parent vnode-file-link.
+ * "./AFSDir-<#>". It's a symbolic link to its real dir.
+ * The parent dir and symbolic link to it must exist.
+ */
+ vnode =3D ((vn.type =3D=3D 2) ? vn.vnode : vn.parent);
+=20
+ if (vn.type =3D=3D 2) {
+ /*ITSADIR*/
+ /* We read the directory entries. If the entry is a
+ * directory, the subdir is created and the root dir
+ * will contain a link to it. If its a file, we only
+ * create a symlink in the dir to the file name.
+ */
+ char *buffer;
+ unsigned short j;
+ afs_int32 this_vn;
+ char *this_name;
+=20
+ struct DirEntry
+ {
+ char flag;
+ char length;
+ unsigned short next;
+ struct MKFid
+ {
+ afs_int32 vnode;
+ afs_int32 vunique;
+ } fid;
+ char name[20];
+ };
+=20
+ struct Pageheader
+ {
+ unsigned short pgcount;
+ unsigned short tag;
+ char freecount;
+ char freebitmap[8];
+ char padding[19];
+ };
+=20
+ struct DirHeader
+ {
+ struct Pageheader header;
+ char alloMap[128];
+ unsigned short hashTable[128];
+ };
+=20
+ struct Page0
+ {
+ struct DirHeader header;
+ struct DirEntry entry[1];
+ } *page0;
+ =20
+=20
+ buffer =3D (char *)0;
+ buffer =3D (char *)malloc(vn.dataSize);
+=20
+ readdata(buffer, vn.dataSize);
+ page0 =3D (struct Page0 *)buffer;
+=20
+ /* Step through each bucket in the hash table, i,
+ * and follow each element in the hash chain, j.
+ * This gives us each entry of the dir.
+ */
+ for (i=3D0; i<128; i++) {
+ for (j=3Dntohs(page0->header.hashTable[i]); j;
+ j=3Dntohs(page0->entry[j].next)) {
+ j -=3D 13;
+ this_vn =3D ntohl(page0->entry[j].fid.vnode);
+ this_name =3D page0->entry[j].name;
+=20
+ if ((strcmp(this_name,"." ) =3D=3D 0) ||
+ (strcmp(this_name,"..") =3D=3D 0))
+ continue; /* Skip these */
+=20
+ setvnode(this_vn,this_name, vnode);
+ printvnode(this_vn);
+ }
+ }
+ free(buffer);
+ } /*ITSADIR*/
+=20
+ else if (vn.type =3D=3D 1) {
+ /*ITSAFILE*/
+ /* A file vnode. So create it into the desired directory. A
+ * link should exist in the directory naming the file.
+ */
+ int fid;
+ int lfile;
+ afs_int32 size, s;
+=20
+ size =3D vn.dataSize;
+ while (size > 0) {
+ s =3D ((size > BUFSIZE) ? BUFSIZE : size);
+ code =3D fread(buf, 1, s, dumpfile);
+ if (code > 0) {
+ size -=3D code;
+ }
+ if (code !=3D s) {
+ if (code < 0)
+ fprintf (stderr, "Code =3D %d; Errno =3D %d\n", code, errno);
+ else=20
+ fprintf (stderr, "Read %d bytes out of %d\n",=20
+ (vn.dataSize - size), vn.dataSize);
+ break;
+ }
+ }
+ if (size !=3D 0) {
+ fprintf(stderr, " File %s (%s) is incomplete\n", filename, fname=
);
+ }
+=20
+ } /*ITSAFILE*/
+=20
+ else if (vn.type =3D=3D 3) {
+ /*ITSASYMLINK*/
+ /* A symlink vnode. So read it into the desired directory. This could
+ * also be a mount point. If the volume is being restored to AFS, thi=
s
+ * will become a mountpoint. If not, it becomes a symlink to no-where=
.
+ */
+ int fid;
+ afs_int32 size, s;
+=20
+ /* Check if its vnode-file-link exists and create pathname
+ * of the symbolic link. If it doesn't exist,
+ * then the link will be an orphaned link.
+ */
+ /* Read the link in */
+ readdata(buf, vn.dataSize);
+ } /*ITSASYMLINK*/
+ else {
+ fprintf (stderr, "Unknown Vnode block\n");
+ }
+ break;
+=20
+ default:
+ done =3D 1;
+ break;
+ }
+ }
+ if (vn.type =3D=3D 0)
+ inc_dump =3D 1;
+=20
+ return((afs_int32)tag);
+ }
+=20
+ WorkerBee(as, arock)
+ struct cmd_syndesc *as;
+ char *arock;
+ {
+ int code=3D0, c, len;
+ afs_int32 type, count, vcount;
+ DIR *dirP, *dirQ;
+ struct dirent *dirE, *dirF;
+ char fname[MAXNAMELEN], name[MAXNAMELEN], lname[MAXNAMELEN], mname[MA=
XNAMELEN];
+ char thisdir[MAXPATHLEN], *t;
+ struct DumpHeader dh; /* Defined in dump.h */
+ #if 0/*ndef HAVE_GETCWD*/ /* XXX enable when autoconf happens */
+ extern char *getwd();
+ #define getcwd(x,y) getwd(x)
+ #endif
+ =20
+ if (as->parms[0].items) { /* -file <dumpfile> *=
/
+ dumpfile =3D fopen(as->parms[0].items->data, "r");
+ if (!dumpfile) {
+ fprintf(stderr, "Cannot open '%s'. Code =3D %d\n",
+ as->parms[0].items->data, errno);
+ goto cleanup;
+ }
+ } else {
+ dumpfile =3D (FILE *)stdin; /* use stdin */
+ }
+=20
+ /* Read the dump header. From it we get the volume name */
+ type =3D ntohl(readvalue(1));
+ if (type !=3D 1) {
+ fprintf(stderr, "Expected DumpHeader\n");
+ code =3D -1;
+ goto cleanup;
+ }
+ type =3D ReadDumpHeader(&dh);
+=20
+ fprintf(stderr, "Table of Contents of volume dump of '%s':\n",
+ dh.volumeName);
+=20
+ for (count=3D1; type=3D=3D2; count++) {
+ type =3D ReadVolumeHeader(count);
+ for (vcount=3D1; type=3D=3D3; vcount++)
+ type =3D ReadVNode(vcount, as->parms[5].items);
+ }
+ for (count=3D1; count < vnodemaplen ; count++ ) {
+ printvnode(count);
+ }
+=20
+ cleanup:
+ return(code);
+ }
+=20
+ main(argc, argv)
+ int argc;
+ char **argv;
+ {
+ struct cmd_syndesc *ts;
+ struct cmd_item *ti;
+=20
+ setlinebuf(stdout);
+ setvnode(1,"/",1);
+ printvnode(1);
+=20
+ ts=3Dcmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "vldb check");
+ cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
+=20
+ return cmd_Dispatch(argc, argv);
+ }
--=-BI/zzuLtHCWVIp64i9RP--