2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 ** Lists all files in a /vicepX partition. This started as an
12 ** exercise to know the layout of AFS data in a fileserver
13 ** partition. Later on, it proved useful in debugging problems
14 ** at customer sites too.
17 #include <afsconfig.h>
18 #include <afs/param.h>
23 #include <afs/afsint.h>
25 #include <sys/param.h>
26 #if !defined(AFS_SGI_ENV)
29 #else /* AFS_OSF_ENV */
30 #ifdef AFS_VFSINCL_ENV
33 #include <sys/fs/ufs_fs.h>
37 #else /* AFS_VFSINCL_ENV */
41 #endif AFS_VFSINCL_ENV
42 #endif /* AFS_OSF_ENV */
43 #endif /* AFS_SGI_ENV */
44 #include <sys/errno.h>
48 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_BSD_ENV))
61 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
63 #include <sys/mnttab.h>
64 #include <sys/mntent.h>
69 #if defined(AFS_SGI_ENV)
74 #include <sys/fs/efs.h>
76 #include "efs.h" /* until 5.1 release */
78 #define ROOTINO EFS_ROOTINO
82 #endif /* AFS_SGI_ENV */
83 #endif /* AFS_HPUX_ENV */
86 #include <netinet/in.h>
91 #endif /* ITIMER_REAL */
94 #include <afs/errors.h>
100 #include "partition.h"
101 #include "afs/assert.h"
102 #include "filesignal.h"
105 #include <afs/auxinode.h>
110 extern void *calloc(), *realloc();
114 int VolumeChanged; /* to satisfy library libdir use */
116 #include "listVicepx.h"
117 char* orphan_NoVnode = "ORPHANED_NoVnode";
118 char* orphan_NoUnique = "ORPHANED_NoUnique";
121 #define allFiles 0x01 /* equivalent to /bin/ls */
122 #define lFlag 0x02 /* equivalent to /bin/ls -l */
123 #define allDirs 0x04 /* equivalent to /bin/ls -ld */
124 #define contentsDInode 0x08 /* list contents of dir inode */
125 #define volInfo 0x10 /* list info from vol header */
127 extern DirEnt *lookup();
128 extern char *getFileName(), *getDirName(), *printStack();
129 extern DirEnt* hash[];
136 printf("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n", name);
137 printf("-ls : lists all files\n");
138 printf("-lsl : lists all files along with its properties\n");
139 printf("-ld : lists all directories\n");
140 printf("-volInfo : lists volume header \n");
141 printf("-dir <inode number>: prints contents of directory inode\n");
150 char fullName[32+VNAMESIZE+sizeof(VHDREXT)+4];
151 char partition[32], volume[VNAMESIZE];
153 struct VolumeHeader volumeHeader;
154 int fd,i, sawPart=0, sawVolume=0, sawDirContents=0;
155 char option = allNull; /* no default options */
156 Inode dirInode; /* list contents of this dir Inode */
158 for (i = 1; i < argc; i++)
160 if (!strcmp(argv[i], "-p"))
164 assert(strlen(argv[i+1]) < 32 );
165 strcpy( partition, argv[++i]);
168 else if ( !strcmp(argv[i], "-v"))
172 assert(strlen(argv[i+1]) < VNAMESIZE );
173 strcpy( volume, argv[++i]);
176 else if ( !strcmp(argv[i], "-dir"))
180 dirInode = atoi(argv[++i]);
181 option |= contentsDInode;
184 else if ( !strcmp(argv[i], "-ls"))
186 else if ( !strcmp(argv[i], "-lsl"))
187 option |= ( allFiles | lFlag );
188 else if ( !strcmp(argv[i], "-ld"))
190 else if ( !strcmp(argv[i], "-volInfo"))
195 /* check input parameters */
196 if ( !sawPart || !sawVolume)
199 /* extract volume id */
200 volumeId = atoi(volume);
202 /* construct unix file name */
203 strcpy(fullName, partition);
204 strcat(fullName,"/V");
205 strcat(fullName,volume);
206 strcat(fullName, VHDREXT);
208 /* check to see that volume exists */
209 if ( stat(fullName, &statBuf) < 0 )
211 printf("Error in stat(%s) : %d\n", fullName, errno);
215 /* read volume header */
216 if ( (fd=open(fullName, O_RDONLY)) < 0 )
218 printf("Error in open(%s) : %d\n", fullName, errno);
221 if ( read(fd, &volumeHeader, sizeof(struct VolumeHeader)) < sizeof(struct VolumeHeader))
223 printf("Error in reading Volume Header : %d\n", errno);
229 case volInfo: /* volume header info */
230 printf("VolId:%d VolInfo:%d mag:%x vers:%d smallVnodeIndex:%d largeVnodeIndex:%d VoAcl:%d volMntTab:%d\n",
231 volumeHeader.id, volumeHeader.volumeInfo,
232 volumeHeader.stamp.magic, volumeHeader.stamp.version,
233 volumeHeader.smallVnodeIndex, volumeHeader.largeVnodeIndex,
234 volumeHeader.volumeAcl, volumeHeader.volumeMountTable);
237 case contentsDInode: /* list directory entries */
238 printContentsOfDirInode(statBuf.st_dev, dirInode,
243 scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName, option);
244 if ( option & allDirs )
247 if ( option & allFiles )
248 scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName, option);
253 scanLargeVnode(dev, node, partitionName, option)
257 char option; /* user options */
259 afs_int32 diskSize = SIZEOF_LARGEDISKVNODE;
260 int nVnodes, fdi, vnodeIndex, offset=0;
261 char buf[SIZEOF_LARGEDISKVNODE];
262 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
266 /* open this largeVodeIndex */
267 if ( (fdi = iopen(dev, node, O_RDONLY)) < 0 )
269 printf("Error in reading node : %d\n", errno);
273 /* get a FILE pointer */
274 if ( (file = fdopen(fdi, "r")) == 0 )
276 printf("fdopen failed : %d\n", errno);
280 /*find out how many directories are there in this volume */
281 if ( fstat(fdi, &statBuf) < 0 )
283 printf("Error in stat(fd=%d): %d\n", fdi, errno);
286 nVnodes = (statBuf.st_size / diskSize) - 1;
288 fseek(file, diskSize, 0);
291 /* scan all entries in this volume */
292 DInit(10); /* initialise directory buffer */
294 for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
295 nVnodes--, vnodeIndex++, offset += diskSize)
297 /* scan this directory */
299 if ( (vnode->type == vDirectory ) && (vnode->inodeNumber ) )
304 dir.volume = volumeId;
307 dir.inode = vnode->inodeNumber;
309 printf("Directory inode %d (parent vnode = %d) contains the entries :\n",
310 vnode->inodeNumber, vnode->parent );
313 assert(dirEntry = (DirEnt*) malloc(sizeof(DirEnt)));
314 dirEntry->inode = vnode->inodeNumber;
315 dirEntry->numEntries = 0;
316 dirEntry->vnodeName = NULL;
317 EnumerateDir(&dir, &createDirEnt, dirEntry );
318 insertHash(dirEntry); /* insert in hash table */
330 createDirEnt(dirEntry, fileName, vnode, unique)
340 /* fil up special fields for itself and parent */
341 if ( strcmp(fileName,".") == 0 )
343 dirEntry->vnode = vnode;
346 if ( strcmp(fileName,"..") == 0 )
348 dirEntry->vnodeParent = vnode;
352 (dirEntry->numEntries)++;
353 assert( dirEntry->vnodeName = (VnodeName *)realloc(dirEntry->vnodeName,
354 dirEntry->numEntries*sizeof(VnodeName)));
355 dirEntry->vnodeName[dirEntry->numEntries-1].vnode = vnode;
356 dirEntry->vnodeName[dirEntry->numEntries-1].vunique = unique;
357 dirEntry->vnodeName[dirEntry->numEntries-1].name = (char *)malloc(strlen(fileName)+1);
358 assert(dirEntry->vnodeName[dirEntry->numEntries-1].name);
359 strcpy(dirEntry->vnodeName[dirEntry->numEntries-1].name, fileName);
364 scanSmallVnode(dev, node, partitionName, option )
368 char option; /* user options */
370 afs_int32 diskSize = SIZEOF_SMALLDISKVNODE;
371 int nVnodes, fdi, vnodeIndex, offset=0;
372 char buf[SIZEOF_LARGEDISKVNODE];
373 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
377 /* open this smallVodeIndex */
378 if ( (fdi = iopen(dev, node, O_RDONLY)) < 0 )
380 printf("Error in reading node : %d\n", errno);
384 /* get a FILE pointer */
385 if ( (file = fdopen(fdi, "r")) == 0 )
387 printf("fdopen failed : %d\n", errno);
391 /*find out how many files are there in this volume */
392 if ( fstat(fdi, &statBuf) < 0 )
394 printf("Error in stat(fd=%d): %d\n", fdi, errno);
397 nVnodes = (statBuf.st_size / diskSize) - 1;
399 fseek(file, diskSize, 0);
402 /* scan all entries in this volume */
403 for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
404 nVnodes--, vnodeIndex++, offset += 1)
405 if ( (vnode->type == vFile) || ( vnode->type == vSymlink) )
407 char* name, *fullPathName;
408 int pNode, nNode, orphan = 0;
411 printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
415 if ( (dir = lookup(vnode->parent)) == 0 )/* orphaned*/
416 orphan = 1, pushStack ( orphan_NoVnode );
419 name=getFileName(dir,vnode->uniquifier);
421 orphan = 1, pushStack(orphan_NoUnique );
425 /* push the file name on stack */
427 pNode = vnode->parent;
428 nNode = dir->vnodeParent;
430 while ( !orphan && (pNode != nNode) )
432 if( (dir= lookup(nNode)) == 0 )
434 orphan = 1, pushStack(orphan_NoVnode);
437 if( (name = getDirName(dir, pNode)) == 0 )
439 orphan = 1, pushStack(orphan_NoVnode);
444 nNode = dir->vnodeParent;
446 fullPathName = printStack(); /* full name of file or symLink */
447 if ( vnode->type == vSymlink ) /* check if mount point */
449 /* read contents of link */
450 struct stat statLink;
453 if ( (fdLink=iopen( dev, vnode->inodeNumber, O_RDONLY)) < 0 )
455 printf("Error in opening symbolic link : %d\n", errno);
458 if ( fstat(fdLink, &statLink) < 0 )
460 printf("Error in symLink stat(fd=%d): %d\n", fdLink, errno);
463 assert( symLink = (char*)malloc(statLink.st_size+1) );
464 if (read(fdLink, symLink, statLink.st_size) < 0 )
466 printf("Error in reading symbolic link : %d\n", errno);
469 symLink[statLink.st_size] = 0; /* null termination */
470 if ( symLink[0] == '#' ) /* this is a mount point */
471 printf("Volume %s mounted on %s%s\n",
472 symLink, partitionName, fullPathName);
476 if ( option & allFiles)
478 if ( option & lFlag )
480 switch ( vnode->type )
482 case vFile: printf("F ");
484 case vDirectory:printf("D ");
486 case vSymlink: printf("S ");
488 default: printf("U ");
491 printf("Ind:%d ", vnode->inodeNumber);
492 printf("Mod:%x ", vnode->modeBits);
493 printf("Lnk:%d ", vnode->linkCount);
494 printf("Own:%d ", vnode->owner);
495 printf("Grp:%d ", vnode->group);
496 printf("Siz:%d ", vnode->length);
498 printf("~%s\n", fullPathName);
505 /* Lists all directories in the volume */
506 printDirs(partitionName)
509 int i, j, vnode, inode;
510 DirEnt *ptr, *dir, *tmpDir;
512 /* The root level vnode for this volume */
513 tmpDir = lookup(1); /* root vnode is 1 */
515 printf("Root vnode(1) does not exists :%s\n", partitionName);
517 printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
519 for ( i=0; i < MAX_HASH_SIZE; i++)
520 for ( ptr = (DirEnt*)hash[i]; ptr; ptr = ptr->next)
521 for ( j=0; j < ptr->numEntries; j++)
524 char *fullPathName, *name;
526 pVnode = ptr->vnodeParent; /* parent vnode */
527 nVnode = ptr->vnode; /* this dir vnode */
528 vnode = ptr->vnodeName[j].vnode; /* my Vnode */
530 /* directory vnode numbers are odd */
531 if ( (vnode % 2) == 0 )
534 tmpDir = lookup(vnode);
535 if ( !tmpDir ) /* orphaned directory */
537 printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
540 inode = tmpDir->inode; /* the inode for this vnode */
542 pushStack(ptr->vnodeName[j].name);
544 while ( pVnode != 1 )
546 dir = lookup( pVnode );
547 if ( dir == 0 ) /* orphan */
549 pushStack(orphan_NoVnode);
552 name = getDirName( dir, nVnode );
555 pushStack(orphan_NoVnode);
560 pVnode = dir->vnodeParent;
562 fullPathName = printStack();/* full path name of directory*/
563 printf("D Ind:%d Vnd:%d ~%s\n",
564 inode, vnode, fullPathName);
568 /* figure out how many pages in use in a directory, given ptr to its (locked) he
570 static ComputeUsedPages(dhp)
571 register struct DirHeader *dhp; {
572 register afs_int32 usedPages, i;
574 if (dhp->header.pgcount != 0) {
576 usedPages = ntohs(dhp->header.pgcount);
581 for(i=0; i<MAXPAGES; i++) {
582 if (dhp->alloMap[i] == EPP) {
587 if (usedPages == 0) usedPages = MAXPAGES;
592 printContentsOfDirInode(device, dirInode, fullName, options)
598 int fd, i, j, usedPages, pages;
602 struct DirHeader *dhp= (struct DirHeader*)&dirPage[0];
604 struct PageHeader *pg;
606 fd = iopen(device, dirInode, O_RDONLY);
609 printf("Cannot open direcory inode %d\n", dirInode);
612 if ( (file = fdopen(fd, "r")) == 0 ) /* for buffered read */
614 printf("fdopen failed : %d\n", errno);
618 if ( fstat(fd, &statBuf) < 0 )
620 printf("Error in stat(fd=%d): %d\n", fd, errno);
623 /* read first page */
624 if ( fread(&dirPage, sizeof(dirPage), 1, file ) != 1)
626 printf("Cannot read dir header from inode %d(errno %d)\n",
631 usedPages = ComputeUsedPages(dhp);
633 printf("Alloc map: ");
634 for ( i=0; i < MAXPAGES; i++)
638 printf("%.2x ", (unsigned char)dhp->alloMap[i]);
640 printf("\nHash table:");
641 for ( i=0; i < NHASHENT; i++)
645 printf("%.2d ", dhp->hashTable[i]);
649 /* print header of first page */
650 printf("--------------- Page 0 ---------------\n");
651 printf("pgcnt :%d\n", usedPages);
652 printf("tag :%d\n", dhp->header.tag);
653 printf("freecnt :%d(not used)\n", dhp->header.freecount);
654 printf("freebitmap :");
655 for ( i=0; i < EPP/8; i++)
656 printf("%.2x ", (unsigned char)(dhp->header.freebitmap[i]));
659 /* print slots in the first page of this directory */
660 de = ((struct DirPage0 *)dirPage)->entry;
661 for(i=DHE+1; i<EPP; i++, de = (struct DirEntry*)((char *)de+32))
662 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n",
663 i, de->flag, de->length, de->next,
664 de->fid.vnode, de->fid.vunique, de->name);
666 /* read all succeeding pages of this directory */
667 for ( pages=1; pages < usedPages; pages++)
669 if ( fread(&dirPage, sizeof(dirPage), 1, file ) != 1)
671 printf("Cannot read %s page from inode %d(errno %d)\n",
672 pages, dirInode, errno);
676 pg = &((struct DirPage1 *)dirPage)->header; /* page header */
677 de = ((struct DirPage1 *)dirPage)->entry;
679 /* print page header info */
680 printf("--------------- Page %d ---------------\n", pages);
681 printf("pgcnt :%d\n", pg->pgcount);
682 printf("tag :%d\n", pg->tag);
683 printf("freecnt :%d(not used)\n", pg->freecount);
684 printf("freebitmap :");
685 for ( i=0; i < EPP/8; i++)
686 printf("%.2x ", (unsigned char)(pg->freebitmap[i]));
689 /* print slots in this page */
690 for(i=1; i<EPP; i++, de = (struct DirEntry*)((char *)de+32))
691 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n",
692 i, de->flag, de->length, de->next,
693 de->fid.vnode, de->fid.vunique, de->name);