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)
28 #else /* AFS_OSF_ENV */
29 #ifdef AFS_VFSINCL_ENV
32 #include <sys/fs/ufs_fs.h>
36 #else /* AFS_VFSINCL_ENV */
40 #endif /* AFS_VFSINCL_ENV */
41 #endif /* AFS_OSF_ENV */
42 #endif /* AFS_SGI_ENV */
43 #include <sys/errno.h>
47 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_BSD_ENV))
60 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
62 #include <sys/mnttab.h>
63 #include <sys/mntent.h>
68 #if defined(AFS_SGI_ENV)
73 #include <sys/fs/efs.h>
75 #include "efs.h" /* until 5.1 release */
77 #define ROOTINO EFS_ROOTINO
81 #endif /* AFS_SGI_ENV */
82 #endif /* AFS_HPUX_ENV */
85 #include <netinet/in.h>
90 #endif /* ITIMER_REAL */
93 #include <afs/errors.h>
99 #include "partition.h"
100 #include "filesignal.h"
102 #include "daemon_com.h"
104 #include <afs/auxinode.h>
109 extern void *calloc(), *realloc();
113 int VolumeChanged; /* to satisfy library libdir use */
115 #include "listVicepx.h"
116 char *orphan_NoVnode = "ORPHANED_NoVnode";
117 char *orphan_NoUnique = "ORPHANED_NoUnique";
120 #define allFiles 0x01 /* equivalent to /bin/ls */
121 #define lFlag 0x02 /* equivalent to /bin/ls -l */
122 #define allDirs 0x04 /* equivalent to /bin/ls -ld */
123 #define contentsDInode 0x08 /* list contents of dir inode */
124 #define volInfo 0x10 /* list info from vol header */
126 extern DirEnt *lookup();
127 extern char *getFileName(), *getDirName(), *printStack();
128 extern DirEnt *hash[];
136 ("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n",
138 printf("-ls : lists all files\n");
139 printf("-lsl : lists all files along with its properties\n");
140 printf("-ld : lists all directories\n");
141 printf("-volInfo : lists volume header \n");
142 printf("-dir <inode number>: prints contents of directory inode\n");
151 char fullName[32 + VNAMESIZE + sizeof(VHDREXT) + 4];
152 char partition[32], volume[VNAMESIZE];
154 struct VolumeHeader volumeHeader;
155 int fd, i, sawPart = 0, sawVolume = 0, sawDirContents = 0;
156 char option = allNull; /* no default options */
157 Inode dirInode; /* list contents of this dir Inode */
159 for (i = 1; i < argc; i++) {
160 if (!strcmp(argv[i], "-p")) {
163 assert(strlen(argv[i + 1]) < 32);
164 strcpy(partition, argv[++i]);
166 } else if (!strcmp(argv[i], "-v")) {
169 assert(strlen(argv[i + 1]) < VNAMESIZE);
170 strcpy(volume, argv[++i]);
172 } else if (!strcmp(argv[i], "-dir")) {
175 dirInode = atoi(argv[++i]);
176 option |= contentsDInode;
178 } else if (!strcmp(argv[i], "-ls"))
180 else if (!strcmp(argv[i], "-lsl"))
181 option |= (allFiles | lFlag);
182 else if (!strcmp(argv[i], "-ld"))
184 else if (!strcmp(argv[i], "-volInfo"))
189 /* check input parameters */
190 if (!sawPart || !sawVolume)
193 /* extract volume id */
194 volumeId = atoi(volume);
196 /* construct unix file name */
197 strcpy(fullName, partition);
198 strcat(fullName, "/V");
199 strcat(fullName, volume);
200 strcat(fullName, VHDREXT);
202 /* check to see that volume exists */
203 if (stat(fullName, &statBuf) < 0) {
204 printf("Error in stat(%s) : %d\n", fullName, errno);
208 /* read volume header */
209 if ((fd = open(fullName, O_RDONLY)) < 0) {
210 printf("Error in open(%s) : %d\n", fullName, errno);
213 if (read(fd, &volumeHeader, sizeof(struct VolumeHeader)) <
214 sizeof(struct VolumeHeader)) {
215 printf("Error in reading Volume Header : %d\n", errno);
220 case volInfo: /* volume header info */
222 ("VolId:%d VolInfo:%d mag:%x vers:%d smallVnodeIndex:%d largeVnodeIndex:%d VoAcl:%d volMntTab:%d\n",
223 volumeHeader.id, volumeHeader.volumeInfo,
224 volumeHeader.stamp.magic, volumeHeader.stamp.version,
225 volumeHeader.smallVnodeIndex, volumeHeader.largeVnodeIndex,
226 volumeHeader.volumeAcl, volumeHeader.volumeMountTable);
229 case contentsDInode: /* list directory entries */
230 printContentsOfDirInode(statBuf.st_dev, dirInode, fullName, option);
234 scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName,
236 if (option & allDirs)
239 if (option & allFiles)
240 scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName,
246 scanLargeVnode(dev, node, partitionName, option)
250 char option; /* user options */
252 afs_int32 diskSize = SIZEOF_LARGEDISKVNODE;
253 int nVnodes, fdi, vnodeIndex, offset = 0;
254 char buf[SIZEOF_LARGEDISKVNODE];
255 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
259 /* open this largeVodeIndex */
260 if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
261 printf("Error in reading node : %d\n", errno);
265 /* get a FILE pointer */
266 if ((file = fdopen(fdi, "r")) == 0) {
267 printf("fdopen failed : %d\n", errno);
271 /*find out how many directories are there in this volume */
272 if (fstat(fdi, &statBuf) < 0) {
273 printf("Error in stat(fd=%d): %d\n", fdi, errno);
276 nVnodes = (statBuf.st_size / diskSize) - 1;
278 fseek(file, diskSize, 0);
282 /* scan all entries in this volume */
283 DInit(10); /* initialise directory buffer */
285 for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
286 nVnodes--, vnodeIndex++, offset += diskSize) {
287 /* scan this directory */
289 if ((vnode->type == vDirectory) && (vnode->inodeNumber)) {
293 dir.volume = volumeId;
296 dir.inode = vnode->inodeNumber;
299 ("Directory inode %d (parent vnode = %d) contains the entries :\n",
300 vnode->inodeNumber, vnode->parent);
303 assert(dirEntry = (DirEnt *) malloc(sizeof(DirEnt)));
304 dirEntry->inode = vnode->inodeNumber;
305 dirEntry->numEntries = 0;
306 dirEntry->vnodeName = NULL;
307 EnumerateDir(&dir, &createDirEnt, dirEntry);
308 insertHash(dirEntry); /* insert in hash table */
320 createDirEnt(dirEntry, fileName, vnode, unique)
330 /* fil up special fields for itself and parent */
331 if (strcmp(fileName, ".") == 0) {
332 dirEntry->vnode = vnode;
335 if (strcmp(fileName, "..") == 0) {
336 dirEntry->vnodeParent = vnode;
340 (dirEntry->numEntries)++;
341 assert(dirEntry->vnodeName =
342 realloc(dirEntry->vnodeName,
343 dirEntry->numEntries * sizeof(VnodeName)));
344 dirEntry->vnodeName[dirEntry->numEntries - 1].vnode = vnode;
345 dirEntry->vnodeName[dirEntry->numEntries - 1].vunique = unique;
346 dirEntry->vnodeName[dirEntry->numEntries - 1].name = strdup(fileName);
347 assert(dirEntry->vnodeName[dirEntry->numEntries - 1].name);
352 scanSmallVnode(dev, node, partitionName, option)
356 char option; /* user options */
358 afs_int32 diskSize = SIZEOF_SMALLDISKVNODE;
359 int nVnodes, fdi, vnodeIndex, offset = 0;
360 char buf[SIZEOF_LARGEDISKVNODE];
361 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
365 /* open this smallVodeIndex */
366 if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
367 printf("Error in reading node : %d\n", errno);
371 /* get a FILE pointer */
372 if ((file = fdopen(fdi, "r")) == 0) {
373 printf("fdopen failed : %d\n", errno);
377 /*find out how many files are there in this volume */
378 if (fstat(fdi, &statBuf) < 0) {
379 printf("Error in stat(fd=%d): %d\n", fdi, errno);
382 nVnodes = (statBuf.st_size / diskSize) - 1;
384 fseek(file, diskSize, 0);
388 /* scan all entries in this volume */
389 for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
390 nVnodes--, vnodeIndex++, offset += 1)
391 if ((vnode->type == vFile) || (vnode->type == vSymlink)) {
392 char *name, *fullPathName;
393 int pNode, nNode, orphan = 0;
396 printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
400 if ((dir = lookup(vnode->parent)) == 0) /* orphaned */
401 orphan = 1, pushStack(orphan_NoVnode);
403 name = getFileName(dir, vnode->uniquifier);
405 orphan = 1, pushStack(orphan_NoUnique);
408 /* push the file name on stack */
410 pNode = vnode->parent;
411 nNode = dir->vnodeParent;
413 while (!orphan && (pNode != nNode)) {
414 if ((dir = lookup(nNode)) == 0) {
415 orphan = 1, pushStack(orphan_NoVnode);
418 if ((name = getDirName(dir, pNode)) == 0) {
419 orphan = 1, pushStack(orphan_NoVnode);
424 nNode = dir->vnodeParent;
426 fullPathName = printStack(); /* full name of file or symLink */
427 if (vnode->type == vSymlink) { /* check if mount point */
428 /* read contents of link */
429 struct stat statLink;
432 if ((fdLink = iopen(dev, vnode->inodeNumber, O_RDONLY)) < 0) {
433 printf("Error in opening symbolic link : %d\n", errno);
436 if (fstat(fdLink, &statLink) < 0) {
437 printf("Error in symLink stat(fd=%d): %d\n", fdLink,
441 assert(symLink = (char *)malloc(statLink.st_size + 1));
442 if (read(fdLink, symLink, statLink.st_size) < 0) {
443 printf("Error in reading symbolic link : %d\n", errno);
446 symLink[statLink.st_size] = 0; /* null termination */
447 if (symLink[0] == '#') /* this is a mount point */
448 printf("Volume %s mounted on %s%s\n", symLink,
449 partitionName, fullPathName);
453 if (option & allFiles) {
454 if (option & lFlag) {
455 switch (vnode->type) {
469 printf("Ind:%d ", vnode->inodeNumber);
470 printf("Mod:%x ", vnode->modeBits);
471 printf("Lnk:%d ", vnode->linkCount);
472 printf("Own:%d ", vnode->owner);
473 printf("Grp:%d ", vnode->group);
474 printf("Siz:%d ", vnode->length);
476 printf("~%s\n", fullPathName);
483 /* Lists all directories in the volume */
484 printDirs(partitionName)
487 int i, j, vnode, inode;
488 DirEnt *ptr, *dir, *tmpDir;
490 /* The root level vnode for this volume */
491 tmpDir = lookup(1); /* root vnode is 1 */
493 printf("Root vnode(1) does not exists :%s\n", partitionName);
495 printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
497 for (i = 0; i < MAX_HASH_SIZE; i++)
498 for (ptr = (DirEnt *) hash[i]; ptr; ptr = ptr->next)
499 for (j = 0; j < ptr->numEntries; j++) {
501 char *fullPathName, *name;
503 pVnode = ptr->vnodeParent; /* parent vnode */
504 nVnode = ptr->vnode; /* this dir vnode */
505 vnode = ptr->vnodeName[j].vnode; /* my Vnode */
507 /* directory vnode numbers are odd */
508 if ((vnode % 2) == 0)
511 tmpDir = lookup(vnode);
512 if (!tmpDir) { /* orphaned directory */
513 printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
516 inode = tmpDir->inode; /* the inode for this vnode */
518 pushStack(ptr->vnodeName[j].name);
520 while (pVnode != 1) {
521 dir = lookup(pVnode);
522 if (dir == 0) { /* orphan */
523 pushStack(orphan_NoVnode);
526 name = getDirName(dir, nVnode);
528 pushStack(orphan_NoVnode);
533 pVnode = dir->vnodeParent;
535 fullPathName = printStack(); /* full path name of directory */
536 printf("D Ind:%d Vnd:%d ~%s\n", inode, vnode, fullPathName);
540 /* figure out how many pages in use in a directory, given ptr to its (locked) he
543 ComputeUsedPages(dhp)
544 struct DirHeader *dhp;
546 afs_int32 usedPages, i;
548 if (dhp->header.pgcount != 0) {
550 usedPages = ntohs(dhp->header.pgcount);
554 for (i = 0; i < MAXPAGES; i++) {
555 if (dhp->alloMap[i] == EPP) {
561 usedPages = MAXPAGES;
566 printContentsOfDirInode(device, dirInode, fullName, options)
572 int fd, i, j, usedPages, pages;
576 struct DirHeader *dhp = (struct DirHeader *)&dirPage[0];
578 struct PageHeader *pg;
580 fd = iopen(device, dirInode, O_RDONLY);
582 printf("Cannot open direcory inode %d\n", dirInode);
585 if ((file = fdopen(fd, "r")) == 0) { /* for buffered read */
586 printf("fdopen failed : %d\n", errno);
590 if (fstat(fd, &statBuf) < 0) {
591 printf("Error in stat(fd=%d): %d\n", fd, errno);
594 /* read first page */
595 if (fread(&dirPage, sizeof(dirPage), 1, file) != 1) {
596 printf("Cannot read dir header from inode %d(errno %d)\n", dirInode,
601 usedPages = ComputeUsedPages(dhp);
603 printf("Alloc map: ");
604 for (i = 0; i < MAXPAGES; i++) {
607 printf("%.2x ", (unsigned char)dhp->alloMap[i]);
609 printf("\nHash table:");
610 for (i = 0; i < NHASHENT; i++) {
613 printf("%.2d ", dhp->hashTable[i]);
617 /* print header of first page */
618 printf("--------------- Page 0 ---------------\n");
619 printf("pgcnt :%d\n", usedPages);
620 printf("tag :%d\n", dhp->header.tag);
621 printf("freecnt :%d(not used)\n", dhp->header.freecount);
622 printf("freebitmap :");
623 for (i = 0; i < EPP / 8; i++)
624 printf("%.2x ", (unsigned char)(dhp->header.freebitmap[i]));
627 /* print slots in the first page of this directory */
628 de = ((struct DirPage0 *)dirPage)->entry;
629 for (i = DHE + 1; i < EPP; i++, de = (struct DirEntry *)((char *)de + 32))
630 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n", i, de->flag,
631 de->length, de->next, de->fid.vnode, de->fid.vunique,
634 /* read all succeeding pages of this directory */
635 for (pages = 1; pages < usedPages; pages++) {
636 if (fread(&dirPage, sizeof(dirPage), 1, file) != 1) {
637 printf("Cannot read %s page from inode %d(errno %d)\n", pages,
642 pg = &((struct DirPage1 *)dirPage)->header; /* page header */
643 de = ((struct DirPage1 *)dirPage)->entry;
645 /* print page header info */
646 printf("--------------- Page %d ---------------\n", pages);
647 printf("pgcnt :%d\n", pg->pgcount);
648 printf("tag :%d\n", pg->tag);
649 printf("freecnt :%d(not used)\n", pg->freecount);
650 printf("freebitmap :");
651 for (i = 0; i < EPP / 8; i++)
652 printf("%.2x ", (unsigned char)(pg->freebitmap[i]));
655 /* print slots in this page */
656 for (i = 1; i < EPP; i++, de = (struct DirEntry *)((char *)de + 32))
657 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n", i,
658 de->flag, de->length, de->next, de->fid.vnode,
659 de->fid.vunique, de->name);