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>
22 #include <afs/afsint.h>
24 #include <sys/param.h>
25 #if !defined(AFS_SGI_ENV)
26 #ifdef AFS_VFSINCL_ENV
29 #include <sys/fs/ufs_fs.h>
33 #else /* AFS_VFSINCL_ENV */
37 #endif /* AFS_VFSINCL_ENV */
38 #endif /* AFS_SGI_ENV */
39 #include <sys/errno.h>
43 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_BSD_ENV))
56 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
58 #include <sys/mnttab.h>
59 #include <sys/mntent.h>
64 #if defined(AFS_SGI_ENV)
69 #include <sys/fs/efs.h>
71 #include "efs.h" /* until 5.1 release */
73 #define ROOTINO EFS_ROOTINO
77 #endif /* AFS_SGI_ENV */
78 #endif /* AFS_HPUX_ENV */
81 #include <netinet/in.h>
86 #endif /* ITIMER_REAL */
89 #include <afs/errors.h>
95 #include "partition.h"
96 #include "filesignal.h"
98 #include "daemon_com.h"
100 #include <afs/auxinode.h>
106 int VolumeChanged; /* to satisfy library libdir use */
108 #include "listVicepx.h"
109 char *orphan_NoVnode = "ORPHANED_NoVnode";
110 char *orphan_NoUnique = "ORPHANED_NoUnique";
113 #define allFiles 0x01 /* equivalent to /bin/ls */
114 #define lFlag 0x02 /* equivalent to /bin/ls -l */
115 #define allDirs 0x04 /* equivalent to /bin/ls -ld */
116 #define contentsDInode 0x08 /* list contents of dir inode */
117 #define volInfo 0x10 /* list info from vol header */
119 extern DirEnt *lookup();
120 extern char *getFileName(), *getDirName(), *printStack();
121 extern DirEnt *hash[];
129 ("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n",
131 printf("-ls : lists all files\n");
132 printf("-lsl : lists all files along with its properties\n");
133 printf("-ld : lists all directories\n");
134 printf("-volInfo : lists volume header \n");
135 printf("-dir <inode number>: prints contents of directory inode\n");
144 char fullName[32 + VNAMESIZE + sizeof(VHDREXT) + 4];
145 char partition[32], volume[VNAMESIZE];
147 struct VolumeHeader volumeHeader;
148 int fd, i, sawPart = 0, sawVolume = 0, sawDirContents = 0;
149 char option = allNull; /* no default options */
150 Inode dirInode; /* list contents of this dir Inode */
152 for (i = 1; i < argc; i++) {
153 if (!strcmp(argv[i], "-p")) {
156 assert(strlen(argv[i + 1]) < 32);
157 strcpy(partition, argv[++i]);
159 } else if (!strcmp(argv[i], "-v")) {
162 assert(strlen(argv[i + 1]) < VNAMESIZE);
163 strcpy(volume, argv[++i]);
165 } else if (!strcmp(argv[i], "-dir")) {
168 dirInode = atoi(argv[++i]);
169 option |= contentsDInode;
171 } else if (!strcmp(argv[i], "-ls"))
173 else if (!strcmp(argv[i], "-lsl"))
174 option |= (allFiles | lFlag);
175 else if (!strcmp(argv[i], "-ld"))
177 else if (!strcmp(argv[i], "-volInfo"))
182 /* check input parameters */
183 if (!sawPart || !sawVolume)
186 /* extract volume id */
187 volumeId = atoi(volume);
189 /* construct unix file name */
190 strcpy(fullName, partition);
191 strcat(fullName, "/V");
192 strcat(fullName, volume);
193 strcat(fullName, VHDREXT);
195 /* check to see that volume exists */
196 if (stat(fullName, &statBuf) < 0) {
197 printf("Error in stat(%s) : %d\n", fullName, errno);
201 /* read volume header */
202 if ((fd = open(fullName, O_RDONLY)) < 0) {
203 printf("Error in open(%s) : %d\n", fullName, errno);
206 if (read(fd, &volumeHeader, sizeof(struct VolumeHeader)) <
207 sizeof(struct VolumeHeader)) {
208 printf("Error in reading Volume Header : %d\n", errno);
213 case volInfo: /* volume header info */
215 ("VolId:%d VolInfo:%d mag:%x vers:%d smallVnodeIndex:%d largeVnodeIndex:%d VoAcl:%d volMntTab:%d\n",
216 volumeHeader.id, volumeHeader.volumeInfo,
217 volumeHeader.stamp.magic, volumeHeader.stamp.version,
218 volumeHeader.smallVnodeIndex, volumeHeader.largeVnodeIndex,
219 volumeHeader.volumeAcl, volumeHeader.volumeMountTable);
222 case contentsDInode: /* list directory entries */
223 printContentsOfDirInode(statBuf.st_dev, dirInode, fullName, option);
227 scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName,
229 if (option & allDirs)
232 if (option & allFiles)
233 scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName,
239 scanLargeVnode(dev, node, partitionName, option)
243 char option; /* user options */
245 afs_int32 diskSize = SIZEOF_LARGEDISKVNODE;
246 int nVnodes, fdi, vnodeIndex, offset = 0;
247 char buf[SIZEOF_LARGEDISKVNODE];
248 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
252 /* open this largeVodeIndex */
253 if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
254 printf("Error in reading node : %d\n", errno);
258 /* get a FILE pointer */
259 if ((file = fdopen(fdi, "r")) == 0) {
260 printf("fdopen failed : %d\n", errno);
264 /*find out how many directories are there in this volume */
265 if (fstat(fdi, &statBuf) < 0) {
266 printf("Error in stat(fd=%d): %d\n", fdi, errno);
269 nVnodes = (statBuf.st_size / diskSize) - 1;
271 fseek(file, diskSize, 0);
275 /* scan all entries in this volume */
276 DInit(10); /* initialise directory buffer */
278 for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
279 nVnodes--, vnodeIndex++, offset += diskSize) {
280 /* scan this directory */
282 if ((vnode->type == vDirectory) && (vnode->inodeNumber)) {
286 dir.volume = volumeId;
289 dir.inode = vnode->inodeNumber;
292 ("Directory inode %d (parent vnode = %d) contains the entries :\n",
293 vnode->inodeNumber, vnode->parent);
296 assert(dirEntry = malloc(sizeof(DirEnt)));
297 dirEntry->inode = vnode->inodeNumber;
298 dirEntry->numEntries = 0;
299 dirEntry->vnodeName = NULL;
300 EnumerateDir(&dir, &createDirEnt, dirEntry);
301 insertHash(dirEntry); /* insert in hash table */
313 createDirEnt(dirEntry, fileName, vnode, unique)
323 /* fil up special fields for itself and parent */
324 if (strcmp(fileName, ".") == 0) {
325 dirEntry->vnode = vnode;
328 if (strcmp(fileName, "..") == 0) {
329 dirEntry->vnodeParent = vnode;
333 (dirEntry->numEntries)++;
334 assert(dirEntry->vnodeName =
335 realloc(dirEntry->vnodeName,
336 dirEntry->numEntries * sizeof(VnodeName)));
337 dirEntry->vnodeName[dirEntry->numEntries - 1].vnode = vnode;
338 dirEntry->vnodeName[dirEntry->numEntries - 1].vunique = unique;
339 dirEntry->vnodeName[dirEntry->numEntries - 1].name = strdup(fileName);
340 assert(dirEntry->vnodeName[dirEntry->numEntries - 1].name);
345 scanSmallVnode(dev, node, partitionName, option)
349 char option; /* user options */
351 afs_int32 diskSize = SIZEOF_SMALLDISKVNODE;
352 int nVnodes, fdi, vnodeIndex, offset = 0;
353 char buf[SIZEOF_LARGEDISKVNODE];
354 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
358 /* open this smallVodeIndex */
359 if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
360 printf("Error in reading node : %d\n", errno);
364 /* get a FILE pointer */
365 if ((file = fdopen(fdi, "r")) == 0) {
366 printf("fdopen failed : %d\n", errno);
370 /*find out how many files are there in this volume */
371 if (fstat(fdi, &statBuf) < 0) {
372 printf("Error in stat(fd=%d): %d\n", fdi, errno);
375 nVnodes = (statBuf.st_size / diskSize) - 1;
377 fseek(file, diskSize, 0);
381 /* scan all entries in this volume */
382 for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
383 nVnodes--, vnodeIndex++, offset += 1)
384 if ((vnode->type == vFile) || (vnode->type == vSymlink)) {
385 char *name, *fullPathName;
386 int pNode, nNode, orphan = 0;
389 printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
393 if ((dir = lookup(vnode->parent)) == 0) /* orphaned */
394 orphan = 1, pushStack(orphan_NoVnode);
396 name = getFileName(dir, vnode->uniquifier);
398 orphan = 1, pushStack(orphan_NoUnique);
401 /* push the file name on stack */
403 pNode = vnode->parent;
404 nNode = dir->vnodeParent;
406 while (!orphan && (pNode != nNode)) {
407 if ((dir = lookup(nNode)) == 0) {
408 orphan = 1, pushStack(orphan_NoVnode);
411 if ((name = getDirName(dir, pNode)) == 0) {
412 orphan = 1, pushStack(orphan_NoVnode);
417 nNode = dir->vnodeParent;
419 fullPathName = printStack(); /* full name of file or symLink */
420 if (vnode->type == vSymlink) { /* check if mount point */
421 /* read contents of link */
422 struct stat statLink;
425 if ((fdLink = iopen(dev, vnode->inodeNumber, O_RDONLY)) < 0) {
426 printf("Error in opening symbolic link : %d\n", errno);
429 if (fstat(fdLink, &statLink) < 0) {
430 printf("Error in symLink stat(fd=%d): %d\n", fdLink,
434 assert(symLink = malloc(statLink.st_size + 1));
435 if (read(fdLink, symLink, statLink.st_size) < 0) {
436 printf("Error in reading symbolic link : %d\n", errno);
439 symLink[statLink.st_size] = 0; /* null termination */
440 if (symLink[0] == '#') /* this is a mount point */
441 printf("Volume %s mounted on %s%s\n", symLink,
442 partitionName, fullPathName);
446 if (option & allFiles) {
447 if (option & lFlag) {
448 switch (vnode->type) {
462 printf("Ind:%d ", vnode->inodeNumber);
463 printf("Mod:%x ", vnode->modeBits);
464 printf("Lnk:%d ", vnode->linkCount);
465 printf("Own:%d ", vnode->owner);
466 printf("Grp:%d ", vnode->group);
467 printf("Siz:%d ", vnode->length);
469 printf("~%s\n", fullPathName);
476 /* Lists all directories in the volume */
477 printDirs(partitionName)
480 int i, j, vnode, inode;
481 DirEnt *ptr, *dir, *tmpDir;
483 /* The root level vnode for this volume */
484 tmpDir = lookup(1); /* root vnode is 1 */
486 printf("Root vnode(1) does not exists :%s\n", partitionName);
488 printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
490 for (i = 0; i < MAX_HASH_SIZE; i++)
491 for (ptr = (DirEnt *) hash[i]; ptr; ptr = ptr->next)
492 for (j = 0; j < ptr->numEntries; j++) {
494 char *fullPathName, *name;
496 pVnode = ptr->vnodeParent; /* parent vnode */
497 nVnode = ptr->vnode; /* this dir vnode */
498 vnode = ptr->vnodeName[j].vnode; /* my Vnode */
500 /* directory vnode numbers are odd */
501 if ((vnode % 2) == 0)
504 tmpDir = lookup(vnode);
505 if (!tmpDir) { /* orphaned directory */
506 printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
509 inode = tmpDir->inode; /* the inode for this vnode */
511 pushStack(ptr->vnodeName[j].name);
513 while (pVnode != 1) {
514 dir = lookup(pVnode);
515 if (dir == 0) { /* orphan */
516 pushStack(orphan_NoVnode);
519 name = getDirName(dir, nVnode);
521 pushStack(orphan_NoVnode);
526 pVnode = dir->vnodeParent;
528 fullPathName = printStack(); /* full path name of directory */
529 printf("D Ind:%d Vnd:%d ~%s\n", inode, vnode, fullPathName);
533 /* figure out how many pages in use in a directory, given ptr to its (locked) he
536 ComputeUsedPages(dhp)
537 struct DirHeader *dhp;
539 afs_int32 usedPages, i;
541 if (dhp->header.pgcount != 0) {
543 usedPages = ntohs(dhp->header.pgcount);
547 for (i = 0; i < MAXPAGES; i++) {
548 if (dhp->alloMap[i] == EPP) {
554 usedPages = MAXPAGES;
559 printContentsOfDirInode(device, dirInode, fullName, options)
565 int fd, i, j, usedPages, pages;
569 struct DirHeader *dhp = (struct DirHeader *)&dirPage[0];
571 struct PageHeader *pg;
573 fd = iopen(device, dirInode, O_RDONLY);
575 printf("Cannot open direcory inode %d\n", dirInode);
578 if ((file = fdopen(fd, "r")) == 0) { /* for buffered read */
579 printf("fdopen failed : %d\n", errno);
583 if (fstat(fd, &statBuf) < 0) {
584 printf("Error in stat(fd=%d): %d\n", fd, errno);
587 /* read first page */
588 if (fread(&dirPage, sizeof(dirPage), 1, file) != 1) {
589 printf("Cannot read dir header from inode %d(errno %d)\n", dirInode,
594 usedPages = ComputeUsedPages(dhp);
596 printf("Alloc map: ");
597 for (i = 0; i < MAXPAGES; i++) {
600 printf("%.2x ", (unsigned char)dhp->alloMap[i]);
602 printf("\nHash table:");
603 for (i = 0; i < NHASHENT; i++) {
606 printf("%.2d ", dhp->hashTable[i]);
610 /* print header of first page */
611 printf("--------------- Page 0 ---------------\n");
612 printf("pgcnt :%d\n", usedPages);
613 printf("tag :%d\n", dhp->header.tag);
614 printf("freecnt :%d(not used)\n", dhp->header.freecount);
615 printf("freebitmap :");
616 for (i = 0; i < EPP / 8; i++)
617 printf("%.2x ", (unsigned char)(dhp->header.freebitmap[i]));
620 /* print slots in the first page of this directory */
621 de = ((struct DirPage0 *)dirPage)->entry;
622 for (i = DHE + 1; i < EPP; i++, de = (struct DirEntry *)((char *)de + 32))
623 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n", i, de->flag,
624 de->length, de->next, de->fid.vnode, de->fid.vunique,
627 /* read all succeeding pages of this directory */
628 for (pages = 1; pages < usedPages; pages++) {
629 if (fread(&dirPage, sizeof(dirPage), 1, file) != 1) {
630 printf("Cannot read %s page from inode %d(errno %d)\n", pages,
635 pg = &((struct DirPage1 *)dirPage)->header; /* page header */
636 de = ((struct DirPage1 *)dirPage)->entry;
638 /* print page header info */
639 printf("--------------- Page %d ---------------\n", pages);
640 printf("pgcnt :%d\n", pg->pgcount);
641 printf("tag :%d\n", pg->tag);
642 printf("freecnt :%d(not used)\n", pg->freecount);
643 printf("freebitmap :");
644 for (i = 0; i < EPP / 8; i++)
645 printf("%.2x ", (unsigned char)(pg->freebitmap[i]));
648 /* print slots in this page */
649 for (i = 1; i < EPP; i++, de = (struct DirEntry *)((char *)de + 32))
650 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n", i,
651 de->flag, de->length, de->next, de->fid.vnode,
652 de->fid.vunique, de->name);