death to register
[openafs.git] / src / vol / test / listVicepx.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
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. 
15 **
16 */
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20
21 #include <rx/xdr.h>
22 #include <afs/afsint.h>
23 #include <ctype.h>
24 #include <sys/param.h>
25 #if !defined(AFS_SGI_ENV)
26 #ifdef  AFS_OSF_ENV
27 #include <ufs/fs.h>
28 #else /* AFS_OSF_ENV */
29 #ifdef AFS_VFSINCL_ENV
30 #define VFS
31 #ifdef  AFS_SUN5_ENV
32 #include <sys/fs/ufs_fs.h>
33 #else
34 #include <ufs/fs.h>
35 #endif
36 #else /* AFS_VFSINCL_ENV */
37 #ifndef AFS_AIX_ENV
38 #include <sys/fs.h>
39 #endif
40 #endif /* AFS_VFSINCL_ENV */
41 #endif /* AFS_OSF_ENV */
42 #endif /* AFS_SGI_ENV */
43 #include <sys/errno.h>
44 #include <sys/stat.h>
45 #include <stdio.h>
46 #include <sys/file.h>
47 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_BSD_ENV))
48 #include <dirent.h>
49 #else
50 #include <sys/dir.h>
51 #endif
52 #ifdef  AFS_AIX_ENV
53 #include <sys/vfs.h>
54 #include <fcntl.h>
55 #else
56 #ifdef  AFS_HPUX_ENV
57 #include <fcntl.h>
58 #include <mntent.h>
59 #else
60 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
61 #ifdef  AFS_SUN5_ENV
62 #include <sys/mnttab.h>
63 #include <sys/mntent.h>
64 #else
65 #include <mntent.h>
66 #endif
67 #else
68 #if defined(AFS_SGI_ENV)
69 #include <fcntl.h>
70 #include <mntent.h>
71
72 /*
73 #include <sys/fs/efs.h>
74 */
75 #include "efs.h"                /* until 5.1 release */
76
77 #define ROOTINO EFS_ROOTINO
78 #else
79 #include <fstab.h>
80 #endif
81 #endif /* AFS_SGI_ENV */
82 #endif /* AFS_HPUX_ENV */
83 #endif
84 #include <netdb.h>
85 #include <netinet/in.h>
86 #include <sys/wait.h>
87 #include <setjmp.h>
88 #ifndef ITIMER_REAL
89 #include <sys/time.h>
90 #endif /* ITIMER_REAL */
91
92 #include "nfs.h"
93 #include <afs/errors.h>
94 #include "lock.h"
95 #include "lwp.h"
96 #include "vnode.h"
97 #include "volume.h"
98 #include "vldb.h"
99 #include "partition.h"
100 #include "afs/assert.h"
101 #include "filesignal.h"
102 #include "vutils.h"
103 #include "daemon_com.h"
104 #include "fssync.h"
105 #include <afs/auxinode.h>
106 #include <afs/dir.h>
107 #include <unistd.h>
108
109 #ifdef  AFS_OSF_ENV
110 extern void *calloc(), *realloc();
111 #endif
112 #include "salvage.h"
113 int volumeId;
114 int VolumeChanged;              /* to satisfy library libdir use */
115
116 #include "listVicepx.h"
117 char *orphan_NoVnode = "ORPHANED_NoVnode";
118 char *orphan_NoUnique = "ORPHANED_NoUnique";
119
120 #define allNull         0x00
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 */
126
127 extern DirEnt *lookup();
128 extern char *getFileName(), *getDirName(), *printStack();
129 extern DirEnt *hash[];
130
131 int
132 Usage(name)
133      char *name;
134 {
135     assert(name);
136     printf
137         ("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n",
138          name);
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");
144     exit(1);
145 }
146
147
148 main(argc, argv)
149      int argc;
150      char *argv[];
151 {
152     char fullName[32 + VNAMESIZE + sizeof(VHDREXT) + 4];
153     char partition[32], volume[VNAMESIZE];
154     struct stat statBuf;
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 */
159
160     for (i = 1; i < argc; i++) {
161         if (!strcmp(argv[i], "-p")) {
162             if ((i + 1) >= argc)
163                 Usage(argv[0]);
164             assert(strlen(argv[i + 1]) < 32);
165             strcpy(partition, argv[++i]);
166             sawPart = 1;
167         } else if (!strcmp(argv[i], "-v")) {
168             if ((i + 1) >= argc)
169                 Usage(argv[0]);
170             assert(strlen(argv[i + 1]) < VNAMESIZE);
171             strcpy(volume, argv[++i]);
172             sawVolume = 1;
173         } else if (!strcmp(argv[i], "-dir")) {
174             if ((i + 1) >= argc)
175                 Usage(argv[0]);
176             dirInode = atoi(argv[++i]);
177             option |= contentsDInode;
178             sawDirContents = 1;
179         } else if (!strcmp(argv[i], "-ls"))
180             option |= allFiles;
181         else if (!strcmp(argv[i], "-lsl"))
182             option |= (allFiles | lFlag);
183         else if (!strcmp(argv[i], "-ld"))
184             option |= allDirs;
185         else if (!strcmp(argv[i], "-volInfo"))
186             option |= volInfo;
187         else
188             Usage(argv[0]);
189     }
190     /* check input parameters */
191     if (!sawPart || !sawVolume)
192         Usage(argv[0]);
193
194     /* extract volume id */
195     volumeId = atoi(volume);
196
197     /* construct  unix file name */
198     strcpy(fullName, partition);
199     strcat(fullName, "/V");
200     strcat(fullName, volume);
201     strcat(fullName, VHDREXT);
202
203     /* check to see that volume exists */
204     if (stat(fullName, &statBuf) < 0) {
205         printf("Error in stat(%s) : %d\n", fullName, errno);
206         exit(2);
207     }
208
209     /* read volume header */
210     if ((fd = open(fullName, O_RDONLY)) < 0) {
211         printf("Error in open(%s) : %d\n", fullName, errno);
212         exit(3);
213     }
214     if (read(fd, &volumeHeader, sizeof(struct VolumeHeader)) <
215         sizeof(struct VolumeHeader)) {
216         printf("Error in reading Volume Header : %d\n", errno);
217         exit(4);
218     }
219
220     switch (option) {
221     case volInfo:               /* volume header info */
222         printf
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);
228         break;
229
230     case contentsDInode:        /* list directory entries */
231         printContentsOfDirInode(statBuf.st_dev, dirInode, fullName, option);
232         break;
233     }
234
235     scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName,
236                    option);
237     if (option & allDirs)
238         printDirs(fullName);
239
240     if (option & allFiles)
241         scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName,
242                        option);
243     close(fd);
244 }
245
246 int
247 scanLargeVnode(dev, node, partitionName, option)
248      dev_t dev;
249      Inode node;
250      char *partitionName;
251      char option;               /* user options */
252 {
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;
257     FILE *file;
258     struct stat statBuf;
259
260     /* open this largeVodeIndex */
261     if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
262         printf("Error in reading node : %d\n", errno);
263         exit(5);
264     }
265
266     /* get a FILE pointer */
267     if ((file = fdopen(fdi, "r")) == 0) {
268         printf("fdopen failed : %d\n", errno);
269         exit(6);
270     }
271
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);
275         exit(6);
276     }
277     nVnodes = (statBuf.st_size / diskSize) - 1;
278     if (nVnodes > 0)
279         fseek(file, diskSize, 0);
280     else
281         nVnodes = 0;
282
283     /* scan all entries in this volume */
284     DInit(10);                  /* initialise directory buffer */
285
286     for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
287          nVnodes--, vnodeIndex++, offset += diskSize) {
288         /* scan this directory */
289         int createDirEnt();
290         if ((vnode->type == vDirectory) && (vnode->inodeNumber)) {
291             DirHandle dir;
292             DirEnt *dirEntry;
293
294             dir.volume = volumeId;
295             dir.device = dev;
296             dir.cacheCheck = 0;
297             dir.inode = vnode->inodeNumber;
298 #ifdef  DEBUG
299             printf
300                 ("Directory inode %d (parent vnode = %d) contains the entries :\n",
301                  vnode->inodeNumber, vnode->parent);
302 #endif
303
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 */
310         }
311     }
312     fclose(file);
313 #ifdef DEBUG
314     printHash();
315 #endif
316 }
317
318
319
320 int
321 createDirEnt(dirEntry, fileName, vnode, unique)
322      DirEnt *dirEntry;
323      char *fileName;
324      afs_int32 vnode;
325      afs_int32 unique;
326 {
327     int fdi;
328     FILE *file;
329     struct stat statBuf;
330
331     /* fil up special fields for itself and parent */
332     if (strcmp(fileName, ".") == 0) {
333         dirEntry->vnode = vnode;
334         return;
335     }
336     if (strcmp(fileName, "..") == 0) {
337         dirEntry->vnodeParent = vnode;
338         return;
339     }
340
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);
351 }
352
353
354 int
355 scanSmallVnode(dev, node, partitionName, option)
356      dev_t dev;
357      Inode node;
358      char *partitionName;
359      char option;               /* user options */
360 {
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;
365     FILE *file;
366     struct stat statBuf;
367
368     /* open this smallVodeIndex */
369     if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
370         printf("Error in reading node : %d\n", errno);
371         exit(5);
372     }
373
374     /* get a FILE pointer */
375     if ((file = fdopen(fdi, "r")) == 0) {
376         printf("fdopen failed : %d\n", errno);
377         exit(6);
378     }
379
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);
383         exit(6);
384     }
385     nVnodes = (statBuf.st_size / diskSize) - 1;
386     if (nVnodes > 0)
387         fseek(file, diskSize, 0);
388     else
389         nVnodes = 0;
390
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;
397             DirEnt *dir;
398 #ifdef FILE_DEBUG
399             printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
400                    vnode->parent);
401 #endif
402
403             if ((dir = lookup(vnode->parent)) == 0)     /* orphaned */
404                 orphan = 1, pushStack(orphan_NoVnode);
405             if (!orphan) {
406                 name = getFileName(dir, vnode->uniquifier);
407                 if (name == 0)
408                     orphan = 1, pushStack(orphan_NoUnique);
409             }
410             if (!orphan) {
411                 /* push the file name on stack */
412                 pushStack(name);
413                 pNode = vnode->parent;
414                 nNode = dir->vnodeParent;
415             }
416             while (!orphan && (pNode != nNode)) {
417                 if ((dir = lookup(nNode)) == 0) {
418                     orphan = 1, pushStack(orphan_NoVnode);
419                     break;
420                 }
421                 if ((name = getDirName(dir, pNode)) == 0) {
422                     orphan = 1, pushStack(orphan_NoVnode);
423                     break;
424                 }
425                 pushStack(name);
426                 pNode = nNode;
427                 nNode = dir->vnodeParent;
428             }
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;
433                 int fdLink;
434                 char *symLink;
435                 if ((fdLink = iopen(dev, vnode->inodeNumber, O_RDONLY)) < 0) {
436                     printf("Error in opening symbolic link : %d\n", errno);
437                     exit(10);
438                 }
439                 if (fstat(fdLink, &statLink) < 0) {
440                     printf("Error in symLink stat(fd=%d): %d\n", fdLink,
441                            errno);
442                     exit(12);
443                 }
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);
447                     exit(11);
448                 }
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);
453                 free(symLink);
454                 close(fdLink);
455             }
456             if (option & allFiles) {
457                 if (option & lFlag) {
458                     switch (vnode->type) {
459                     case vFile:
460                         printf("F ");
461                         break;
462                     case vDirectory:
463                         printf("D ");
464                         break;
465                     case vSymlink:
466                         printf("S ");
467                         break;
468                     default:
469                         printf("U ");
470                         break;
471                     }
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);
478                 }
479                 printf("~%s\n", fullPathName);
480             }
481         }
482
483     fclose(file);
484 }
485
486 /* Lists all directories in the volume */
487 printDirs(partitionName)
488      char *partitionName;
489 {
490     int i, j, vnode, inode;
491     DirEnt *ptr, *dir, *tmpDir;
492
493     /* The root level vnode for this volume */
494     tmpDir = lookup(1);         /* root vnode is 1 */
495     if (tmpDir == 0)
496         printf("Root vnode(1) does not exists :%s\n", partitionName);
497     else
498         printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
499
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++) {
503                 int nVnode, pVnode;
504                 char *fullPathName, *name;
505
506                 pVnode = ptr->vnodeParent;      /* parent vnode */
507                 nVnode = ptr->vnode;    /* this dir vnode */
508                 vnode = ptr->vnodeName[j].vnode;        /* my Vnode */
509
510                 /* directory vnode numbers are odd */
511                 if ((vnode % 2) == 0)
512                     continue;
513
514                 tmpDir = lookup(vnode);
515                 if (!tmpDir) {  /* orphaned directory */
516                     printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
517                     continue;
518                 }
519                 inode = tmpDir->inode;  /* the inode for this vnode */
520
521                 pushStack(ptr->vnodeName[j].name);
522
523                 while (pVnode != 1) {
524                     dir = lookup(pVnode);
525                     if (dir == 0) {     /* orphan */
526                         pushStack(orphan_NoVnode);
527                         break;
528                     }
529                     name = getDirName(dir, nVnode);
530                     if (name == 0) {
531                         pushStack(orphan_NoVnode);
532                         break;
533                     }
534                     pushStack(name);
535                     nVnode = pVnode;
536                     pVnode = dir->vnodeParent;
537                 }
538                 fullPathName = printStack();    /* full path name of directory */
539                 printf("D Ind:%d Vnd:%d ~%s\n", inode, vnode, fullPathName);
540             }
541 }
542
543 /* figure out how many pages in use in a directory, given ptr to its (locked) he
544 ader */
545 static
546 ComputeUsedPages(dhp)
547      struct DirHeader *dhp;
548 {
549     afs_int32 usedPages, i;
550
551     if (dhp->header.pgcount != 0) {
552         /* new style */
553         usedPages = ntohs(dhp->header.pgcount);
554     } else {
555         /* old style */
556         usedPages = 0;
557         for (i = 0; i < MAXPAGES; i++) {
558             if (dhp->alloMap[i] == EPP) {
559                 usedPages = i;
560                 break;
561             }
562         }
563         if (usedPages == 0)
564             usedPages = MAXPAGES;
565     }
566     return usedPages;
567 }
568
569 printContentsOfDirInode(device, dirInode, fullName, options)
570      dev_t device;
571      Inode dirInode;
572      char *fullName;
573      char options;
574 {
575     int fd, i, j, usedPages, pages;
576     FILE *file;
577     struct stat statBuf;
578     char dirPage[2048];
579     struct DirHeader *dhp = (struct DirHeader *)&dirPage[0];
580     struct DirEntry *de;
581     struct PageHeader *pg;
582
583     fd = iopen(device, dirInode, O_RDONLY);
584     if (fd <= 0) {
585         printf("Cannot open direcory inode %d\n", dirInode);
586         return -1;
587     }
588     if ((file = fdopen(fd, "r")) == 0) {        /* for buffered read */
589         printf("fdopen failed : %d\n", errno);
590         close(fd);
591         return -1;
592     }
593     if (fstat(fd, &statBuf) < 0) {
594         printf("Error in stat(fd=%d): %d\n", fd, errno);
595         return -1;
596     }
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,
600                errno);
601         fclose(file);
602         return -1;
603     }
604     usedPages = ComputeUsedPages(dhp);
605
606     printf("Alloc map: ");
607     for (i = 0; i < MAXPAGES; i++) {
608         if ((i % 16) == 0)
609             printf("\n");
610         printf("%.2x ", (unsigned char)dhp->alloMap[i]);
611     }
612     printf("\nHash table:");
613     for (i = 0; i < NHASHENT; i++) {
614         if ((i % 16) == 0)
615             printf("\n");
616         printf("%.2d ", dhp->hashTable[i]);
617     }
618     printf("\n");
619
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]));
628     printf("\n");
629
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,
635                de->name);
636
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,
641                    dirInode, errno);
642             fclose(file);
643             return -1;
644         }
645         pg = &((struct DirPage1 *)dirPage)->header;     /* page header */
646         de = ((struct DirPage1 *)dirPage)->entry;
647
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]));
656         printf("\n");
657
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);
663     }
664
665     fclose(file);
666     return 0;
667 }