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 "afs/afs_assert.h"
101 #include "filesignal.h"
103 #include "daemon_com.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
[];
137 ("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n",
139 printf("-ls : lists all files\n");
140 printf("-lsl : lists all files along with its properties\n");
141 printf("-ld : lists all directories\n");
142 printf("-volInfo : lists volume header \n");
143 printf("-dir <inode number>: prints contents of directory inode\n");
152 char fullName
[32 + VNAMESIZE
+ sizeof(VHDREXT
) + 4];
153 char partition
[32], volume
[VNAMESIZE
];
155 struct VolumeHeader volumeHeader
;
156 int fd
, i
, sawPart
= 0, sawVolume
= 0, sawDirContents
= 0;
157 char option
= allNull
; /* no default options */
158 Inode dirInode
; /* list contents of this dir Inode */
160 for (i
= 1; i
< argc
; i
++) {
161 if (!strcmp(argv
[i
], "-p")) {
164 assert(strlen(argv
[i
+ 1]) < 32);
165 strcpy(partition
, argv
[++i
]);
167 } else if (!strcmp(argv
[i
], "-v")) {
170 assert(strlen(argv
[i
+ 1]) < VNAMESIZE
);
171 strcpy(volume
, argv
[++i
]);
173 } else if (!strcmp(argv
[i
], "-dir")) {
176 dirInode
= atoi(argv
[++i
]);
177 option
|= contentsDInode
;
179 } else if (!strcmp(argv
[i
], "-ls"))
181 else if (!strcmp(argv
[i
], "-lsl"))
182 option
|= (allFiles
| lFlag
);
183 else if (!strcmp(argv
[i
], "-ld"))
185 else if (!strcmp(argv
[i
], "-volInfo"))
190 /* check input parameters */
191 if (!sawPart
|| !sawVolume
)
194 /* extract volume id */
195 volumeId
= atoi(volume
);
197 /* construct unix file name */
198 strcpy(fullName
, partition
);
199 strcat(fullName
, "/V");
200 strcat(fullName
, volume
);
201 strcat(fullName
, VHDREXT
);
203 /* check to see that volume exists */
204 if (stat(fullName
, &statBuf
) < 0) {
205 printf("Error in stat(%s) : %d\n", fullName
, errno
);
209 /* read volume header */
210 if ((fd
= open(fullName
, O_RDONLY
)) < 0) {
211 printf("Error in open(%s) : %d\n", fullName
, errno
);
214 if (read(fd
, &volumeHeader
, sizeof(struct VolumeHeader
)) <
215 sizeof(struct VolumeHeader
)) {
216 printf("Error in reading Volume Header : %d\n", errno
);
221 case volInfo
: /* volume header info */
223 ("VolId:%d VolInfo:%d mag:%x vers:%d smallVnodeIndex:%d largeVnodeIndex:%d VoAcl:%d volMntTab:%d\n",
224 volumeHeader
.id
, volumeHeader
.volumeInfo
,
225 volumeHeader
.stamp
.magic
, volumeHeader
.stamp
.version
,
226 volumeHeader
.smallVnodeIndex
, volumeHeader
.largeVnodeIndex
,
227 volumeHeader
.volumeAcl
, volumeHeader
.volumeMountTable
);
230 case contentsDInode
: /* list directory entries */
231 printContentsOfDirInode(statBuf
.st_dev
, dirInode
, fullName
, option
);
235 scanLargeVnode(statBuf
.st_dev
, volumeHeader
.largeVnodeIndex
, fullName
,
237 if (option
& allDirs
)
240 if (option
& allFiles
)
241 scanSmallVnode(statBuf
.st_dev
, volumeHeader
.smallVnodeIndex
, fullName
,
247 scanLargeVnode(dev
, node
, partitionName
, option
)
251 char option
; /* user options */
253 afs_int32 diskSize
= SIZEOF_LARGEDISKVNODE
;
254 int nVnodes
, fdi
, vnodeIndex
, offset
= 0;
255 char buf
[SIZEOF_LARGEDISKVNODE
];
256 struct VnodeDiskObject
*vnode
= (struct VnodeDiskObject
*)buf
;
260 /* open this largeVodeIndex */
261 if ((fdi
= iopen(dev
, node
, O_RDONLY
)) < 0) {
262 printf("Error in reading node : %d\n", errno
);
266 /* get a FILE pointer */
267 if ((file
= fdopen(fdi
, "r")) == 0) {
268 printf("fdopen failed : %d\n", errno
);
272 /*find out how many directories are there in this volume */
273 if (fstat(fdi
, &statBuf
) < 0) {
274 printf("Error in stat(fd=%d): %d\n", fdi
, errno
);
277 nVnodes
= (statBuf
.st_size
/ diskSize
) - 1;
279 fseek(file
, diskSize
, 0);
283 /* scan all entries in this volume */
284 DInit(10); /* initialise directory buffer */
286 for (vnodeIndex
= 0; nVnodes
&& fread(vnode
, diskSize
, 1, file
) == 1;
287 nVnodes
--, vnodeIndex
++, offset
+= diskSize
) {
288 /* scan this directory */
290 if ((vnode
->type
== vDirectory
) && (vnode
->inodeNumber
)) {
294 dir
.volume
= volumeId
;
297 dir
.inode
= vnode
->inodeNumber
;
300 ("Directory inode %d (parent vnode = %d) contains the entries :\n",
301 vnode
->inodeNumber
, vnode
->parent
);
304 assert(dirEntry
= (DirEnt
*) malloc(sizeof(DirEnt
)));
305 dirEntry
->inode
= vnode
->inodeNumber
;
306 dirEntry
->numEntries
= 0;
307 dirEntry
->vnodeName
= NULL
;
308 EnumerateDir(&dir
, &createDirEnt
, dirEntry
);
309 insertHash(dirEntry
); /* insert in hash table */
321 createDirEnt(dirEntry
, fileName
, vnode
, unique
)
331 /* fil up special fields for itself and parent */
332 if (strcmp(fileName
, ".") == 0) {
333 dirEntry
->vnode
= vnode
;
336 if (strcmp(fileName
, "..") == 0) {
337 dirEntry
->vnodeParent
= vnode
;
341 (dirEntry
->numEntries
)++;
342 assert(dirEntry
->vnodeName
=
343 (VnodeName
*) realloc(dirEntry
->vnodeName
,
344 dirEntry
->numEntries
* sizeof(VnodeName
)));
345 dirEntry
->vnodeName
[dirEntry
->numEntries
- 1].vnode
= vnode
;
346 dirEntry
->vnodeName
[dirEntry
->numEntries
- 1].vunique
= unique
;
347 dirEntry
->vnodeName
[dirEntry
->numEntries
- 1].name
=
348 (char *)malloc(strlen(fileName
) + 1);
349 assert(dirEntry
->vnodeName
[dirEntry
->numEntries
- 1].name
);
350 strcpy(dirEntry
->vnodeName
[dirEntry
->numEntries
- 1].name
, fileName
);
355 scanSmallVnode(dev
, node
, partitionName
, option
)
359 char option
; /* user options */
361 afs_int32 diskSize
= SIZEOF_SMALLDISKVNODE
;
362 int nVnodes
, fdi
, vnodeIndex
, offset
= 0;
363 char buf
[SIZEOF_LARGEDISKVNODE
];
364 struct VnodeDiskObject
*vnode
= (struct VnodeDiskObject
*)buf
;
368 /* open this smallVodeIndex */
369 if ((fdi
= iopen(dev
, node
, O_RDONLY
)) < 0) {
370 printf("Error in reading node : %d\n", errno
);
374 /* get a FILE pointer */
375 if ((file
= fdopen(fdi
, "r")) == 0) {
376 printf("fdopen failed : %d\n", errno
);
380 /*find out how many files are there in this volume */
381 if (fstat(fdi
, &statBuf
) < 0) {
382 printf("Error in stat(fd=%d): %d\n", fdi
, errno
);
385 nVnodes
= (statBuf
.st_size
/ diskSize
) - 1;
387 fseek(file
, diskSize
, 0);
391 /* scan all entries in this volume */
392 for (vnodeIndex
= 0; nVnodes
&& fread(vnode
, diskSize
, 1, file
) == 1;
393 nVnodes
--, vnodeIndex
++, offset
+= 1)
394 if ((vnode
->type
== vFile
) || (vnode
->type
== vSymlink
)) {
395 char *name
, *fullPathName
;
396 int pNode
, nNode
, orphan
= 0;
399 printf(" File Inode = %d parent vnode=%d ", vnode
->inodeNumber
,
403 if ((dir
= lookup(vnode
->parent
)) == 0) /* orphaned */
404 orphan
= 1, pushStack(orphan_NoVnode
);
406 name
= getFileName(dir
, vnode
->uniquifier
);
408 orphan
= 1, pushStack(orphan_NoUnique
);
411 /* push the file name on stack */
413 pNode
= vnode
->parent
;
414 nNode
= dir
->vnodeParent
;
416 while (!orphan
&& (pNode
!= nNode
)) {
417 if ((dir
= lookup(nNode
)) == 0) {
418 orphan
= 1, pushStack(orphan_NoVnode
);
421 if ((name
= getDirName(dir
, pNode
)) == 0) {
422 orphan
= 1, pushStack(orphan_NoVnode
);
427 nNode
= dir
->vnodeParent
;
429 fullPathName
= printStack(); /* full name of file or symLink */
430 if (vnode
->type
== vSymlink
) { /* check if mount point */
431 /* read contents of link */
432 struct stat statLink
;
435 if ((fdLink
= iopen(dev
, vnode
->inodeNumber
, O_RDONLY
)) < 0) {
436 printf("Error in opening symbolic link : %d\n", errno
);
439 if (fstat(fdLink
, &statLink
) < 0) {
440 printf("Error in symLink stat(fd=%d): %d\n", fdLink
,
444 assert(symLink
= (char *)malloc(statLink
.st_size
+ 1));
445 if (read(fdLink
, symLink
, statLink
.st_size
) < 0) {
446 printf("Error in reading symbolic link : %d\n", errno
);
449 symLink
[statLink
.st_size
] = 0; /* null termination */
450 if (symLink
[0] == '#') /* this is a mount point */
451 printf("Volume %s mounted on %s%s\n", symLink
,
452 partitionName
, fullPathName
);
456 if (option
& allFiles
) {
457 if (option
& lFlag
) {
458 switch (vnode
->type
) {
472 printf("Ind:%d ", vnode
->inodeNumber
);
473 printf("Mod:%x ", vnode
->modeBits
);
474 printf("Lnk:%d ", vnode
->linkCount
);
475 printf("Own:%d ", vnode
->owner
);
476 printf("Grp:%d ", vnode
->group
);
477 printf("Siz:%d ", vnode
->length
);
479 printf("~%s\n", fullPathName
);
486 /* Lists all directories in the volume */
487 printDirs(partitionName
)
490 int i
, j
, vnode
, inode
;
491 DirEnt
*ptr
, *dir
, *tmpDir
;
493 /* The root level vnode for this volume */
494 tmpDir
= lookup(1); /* root vnode is 1 */
496 printf("Root vnode(1) does not exists :%s\n", partitionName
);
498 printf("D Ind:%d Vnd:1 ~\n", tmpDir
->inode
);
500 for (i
= 0; i
< MAX_HASH_SIZE
; i
++)
501 for (ptr
= (DirEnt
*) hash
[i
]; ptr
; ptr
= ptr
->next
)
502 for (j
= 0; j
< ptr
->numEntries
; j
++) {
504 char *fullPathName
, *name
;
506 pVnode
= ptr
->vnodeParent
; /* parent vnode */
507 nVnode
= ptr
->vnode
; /* this dir vnode */
508 vnode
= ptr
->vnodeName
[j
].vnode
; /* my Vnode */
510 /* directory vnode numbers are odd */
511 if ((vnode
% 2) == 0)
514 tmpDir
= lookup(vnode
);
515 if (!tmpDir
) { /* orphaned directory */
516 printf("%s : vnode:%d \n", orphan_NoVnode
, vnode
);
519 inode
= tmpDir
->inode
; /* the inode for this vnode */
521 pushStack(ptr
->vnodeName
[j
].name
);
523 while (pVnode
!= 1) {
524 dir
= lookup(pVnode
);
525 if (dir
== 0) { /* orphan */
526 pushStack(orphan_NoVnode
);
529 name
= getDirName(dir
, nVnode
);
531 pushStack(orphan_NoVnode
);
536 pVnode
= dir
->vnodeParent
;
538 fullPathName
= printStack(); /* full path name of directory */
539 printf("D Ind:%d Vnd:%d ~%s\n", inode
, vnode
, fullPathName
);
543 /* figure out how many pages in use in a directory, given ptr to its (locked) he
546 ComputeUsedPages(dhp
)
547 struct DirHeader
*dhp
;
549 afs_int32 usedPages
, i
;
551 if (dhp
->header
.pgcount
!= 0) {
553 usedPages
= ntohs(dhp
->header
.pgcount
);
557 for (i
= 0; i
< MAXPAGES
; i
++) {
558 if (dhp
->alloMap
[i
] == EPP
) {
564 usedPages
= MAXPAGES
;
569 printContentsOfDirInode(device
, dirInode
, fullName
, options
)
575 int fd
, i
, j
, usedPages
, pages
;
579 struct DirHeader
*dhp
= (struct DirHeader
*)&dirPage
[0];
581 struct PageHeader
*pg
;
583 fd
= iopen(device
, dirInode
, O_RDONLY
);
585 printf("Cannot open direcory inode %d\n", dirInode
);
588 if ((file
= fdopen(fd
, "r")) == 0) { /* for buffered read */
589 printf("fdopen failed : %d\n", errno
);
593 if (fstat(fd
, &statBuf
) < 0) {
594 printf("Error in stat(fd=%d): %d\n", fd
, errno
);
597 /* read first page */
598 if (fread(&dirPage
, sizeof(dirPage
), 1, file
) != 1) {
599 printf("Cannot read dir header from inode %d(errno %d)\n", dirInode
,
604 usedPages
= ComputeUsedPages(dhp
);
606 printf("Alloc map: ");
607 for (i
= 0; i
< MAXPAGES
; i
++) {
610 printf("%.2x ", (unsigned char)dhp
->alloMap
[i
]);
612 printf("\nHash table:");
613 for (i
= 0; i
< NHASHENT
; i
++) {
616 printf("%.2d ", dhp
->hashTable
[i
]);
620 /* print header of first page */
621 printf("--------------- Page 0 ---------------\n");
622 printf("pgcnt :%d\n", usedPages
);
623 printf("tag :%d\n", dhp
->header
.tag
);
624 printf("freecnt :%d(not used)\n", dhp
->header
.freecount
);
625 printf("freebitmap :");
626 for (i
= 0; i
< EPP
/ 8; i
++)
627 printf("%.2x ", (unsigned char)(dhp
->header
.freebitmap
[i
]));
630 /* print slots in the first page of this directory */
631 de
= ((struct DirPage0
*)dirPage
)->entry
;
632 for (i
= DHE
+ 1; i
< EPP
; i
++, de
= (struct DirEntry
*)((char *)de
+ 32))
633 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n", i
, de
->flag
,
634 de
->length
, de
->next
, de
->fid
.vnode
, de
->fid
.vunique
,
637 /* read all succeeding pages of this directory */
638 for (pages
= 1; pages
< usedPages
; pages
++) {
639 if (fread(&dirPage
, sizeof(dirPage
), 1, file
) != 1) {
640 printf("Cannot read %s page from inode %d(errno %d)\n", pages
,
645 pg
= &((struct DirPage1
*)dirPage
)->header
; /* page header */
646 de
= ((struct DirPage1
*)dirPage
)->entry
;
648 /* print page header info */
649 printf("--------------- Page %d ---------------\n", pages
);
650 printf("pgcnt :%d\n", pg
->pgcount
);
651 printf("tag :%d\n", pg
->tag
);
652 printf("freecnt :%d(not used)\n", pg
->freecount
);
653 printf("freebitmap :");
654 for (i
= 0; i
< EPP
/ 8; i
++)
655 printf("%.2x ", (unsigned char)(pg
->freebitmap
[i
]));
658 /* print slots in this page */
659 for (i
= 1; i
< EPP
; i
++, de
= (struct DirEntry
*)((char *)de
+ 32))
660 printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n", i
,
661 de
->flag
, de
->length
, de
->next
, de
->fid
.vnode
,
662 de
->fid
.vunique
, de
->name
);