c4f535f41366ea54bf3cc069a3ed22b2bddfb184
[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_VFSINCL_ENV
27 #define VFS
28 #ifdef  AFS_SUN5_ENV
29 #include <sys/fs/ufs_fs.h>
30 #else
31 #include <ufs/fs.h>
32 #endif
33 #else /* AFS_VFSINCL_ENV */
34 #ifndef AFS_AIX_ENV
35 #include <sys/fs.h>
36 #endif
37 #endif /* AFS_VFSINCL_ENV */
38 #endif /* AFS_SGI_ENV */
39 #include <sys/errno.h>
40 #include <sys/stat.h>
41 #include <stdio.h>
42 #include <sys/file.h>
43 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_BSD_ENV))
44 #include <dirent.h>
45 #else
46 #include <sys/dir.h>
47 #endif
48 #ifdef  AFS_AIX_ENV
49 #include <sys/vfs.h>
50 #include <fcntl.h>
51 #else
52 #ifdef  AFS_HPUX_ENV
53 #include <fcntl.h>
54 #include <mntent.h>
55 #else
56 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
57 #ifdef  AFS_SUN5_ENV
58 #include <sys/mnttab.h>
59 #include <sys/mntent.h>
60 #else
61 #include <mntent.h>
62 #endif
63 #else
64 #if defined(AFS_SGI_ENV)
65 #include <fcntl.h>
66 #include <mntent.h>
67
68 /*
69 #include <sys/fs/efs.h>
70 */
71 #include "efs.h"                /* until 5.1 release */
72
73 #define ROOTINO EFS_ROOTINO
74 #else
75 #include <fstab.h>
76 #endif
77 #endif /* AFS_SGI_ENV */
78 #endif /* AFS_HPUX_ENV */
79 #endif
80 #include <netdb.h>
81 #include <netinet/in.h>
82 #include <sys/wait.h>
83 #include <setjmp.h>
84 #ifndef ITIMER_REAL
85 #include <sys/time.h>
86 #endif /* ITIMER_REAL */
87
88 #include "nfs.h"
89 #include <afs/errors.h>
90 #include "lock.h"
91 #include "lwp.h"
92 #include "vnode.h"
93 #include "volume.h"
94 #include "vldb.h"
95 #include "partition.h"
96 #include "filesignal.h"
97 #include "vutils.h"
98 #include "daemon_com.h"
99 #include "fssync.h"
100 #include <afs/auxinode.h>
101 #include <afs/dir.h>
102 #include <unistd.h>
103
104 #include "salvage.h"
105 int volumeId;
106 int VolumeChanged;              /* to satisfy library libdir use */
107
108 #include "listVicepx.h"
109 char *orphan_NoVnode = "ORPHANED_NoVnode";
110 char *orphan_NoUnique = "ORPHANED_NoUnique";
111
112 #define allNull         0x00
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 */
118
119 extern DirEnt *lookup();
120 extern char *getFileName(), *getDirName(), *printStack();
121 extern DirEnt *hash[];
122
123 int
124 Usage(name)
125      char *name;
126 {
127     assert(name);
128     printf
129         ("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n",
130          name);
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");
136     exit(1);
137 }
138
139
140 main(argc, argv)
141      int argc;
142      char *argv[];
143 {
144     char fullName[32 + VNAMESIZE + sizeof(VHDREXT) + 4];
145     char partition[32], volume[VNAMESIZE];
146     struct stat statBuf;
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 */
151
152     for (i = 1; i < argc; i++) {
153         if (!strcmp(argv[i], "-p")) {
154             if ((i + 1) >= argc)
155                 Usage(argv[0]);
156             assert(strlen(argv[i + 1]) < 32);
157             strcpy(partition, argv[++i]);
158             sawPart = 1;
159         } else if (!strcmp(argv[i], "-v")) {
160             if ((i + 1) >= argc)
161                 Usage(argv[0]);
162             assert(strlen(argv[i + 1]) < VNAMESIZE);
163             strcpy(volume, argv[++i]);
164             sawVolume = 1;
165         } else if (!strcmp(argv[i], "-dir")) {
166             if ((i + 1) >= argc)
167                 Usage(argv[0]);
168             dirInode = atoi(argv[++i]);
169             option |= contentsDInode;
170             sawDirContents = 1;
171         } else if (!strcmp(argv[i], "-ls"))
172             option |= allFiles;
173         else if (!strcmp(argv[i], "-lsl"))
174             option |= (allFiles | lFlag);
175         else if (!strcmp(argv[i], "-ld"))
176             option |= allDirs;
177         else if (!strcmp(argv[i], "-volInfo"))
178             option |= volInfo;
179         else
180             Usage(argv[0]);
181     }
182     /* check input parameters */
183     if (!sawPart || !sawVolume)
184         Usage(argv[0]);
185
186     /* extract volume id */
187     volumeId = atoi(volume);
188
189     /* construct  unix file name */
190     strcpy(fullName, partition);
191     strcat(fullName, "/V");
192     strcat(fullName, volume);
193     strcat(fullName, VHDREXT);
194
195     /* check to see that volume exists */
196     if (stat(fullName, &statBuf) < 0) {
197         printf("Error in stat(%s) : %d\n", fullName, errno);
198         exit(2);
199     }
200
201     /* read volume header */
202     if ((fd = open(fullName, O_RDONLY)) < 0) {
203         printf("Error in open(%s) : %d\n", fullName, errno);
204         exit(3);
205     }
206     if (read(fd, &volumeHeader, sizeof(struct VolumeHeader)) <
207         sizeof(struct VolumeHeader)) {
208         printf("Error in reading Volume Header : %d\n", errno);
209         exit(4);
210     }
211
212     switch (option) {
213     case volInfo:               /* volume header info */
214         printf
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);
220         break;
221
222     case contentsDInode:        /* list directory entries */
223         printContentsOfDirInode(statBuf.st_dev, dirInode, fullName, option);
224         break;
225     }
226
227     scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName,
228                    option);
229     if (option & allDirs)
230         printDirs(fullName);
231
232     if (option & allFiles)
233         scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName,
234                        option);
235     close(fd);
236 }
237
238 int
239 scanLargeVnode(dev, node, partitionName, option)
240      dev_t dev;
241      Inode node;
242      char *partitionName;
243      char option;               /* user options */
244 {
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;
249     FILE *file;
250     struct stat statBuf;
251
252     /* open this largeVodeIndex */
253     if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
254         printf("Error in reading node : %d\n", errno);
255         exit(5);
256     }
257
258     /* get a FILE pointer */
259     if ((file = fdopen(fdi, "r")) == 0) {
260         printf("fdopen failed : %d\n", errno);
261         exit(6);
262     }
263
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);
267         exit(6);
268     }
269     nVnodes = (statBuf.st_size / diskSize) - 1;
270     if (nVnodes > 0)
271         fseek(file, diskSize, 0);
272     else
273         nVnodes = 0;
274
275     /* scan all entries in this volume */
276     DInit(10);                  /* initialise directory buffer */
277
278     for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
279          nVnodes--, vnodeIndex++, offset += diskSize) {
280         /* scan this directory */
281         int createDirEnt();
282         if ((vnode->type == vDirectory) && (vnode->inodeNumber)) {
283             DirHandle dir;
284             DirEnt *dirEntry;
285
286             dir.volume = volumeId;
287             dir.device = dev;
288             dir.cacheCheck = 0;
289             dir.inode = vnode->inodeNumber;
290 #ifdef  DEBUG
291             printf
292                 ("Directory inode %d (parent vnode = %d) contains the entries :\n",
293                  vnode->inodeNumber, vnode->parent);
294 #endif
295
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 */
302         }
303     }
304     fclose(file);
305 #ifdef DEBUG
306     printHash();
307 #endif
308 }
309
310
311
312 int
313 createDirEnt(dirEntry, fileName, vnode, unique)
314      DirEnt *dirEntry;
315      char *fileName;
316      afs_int32 vnode;
317      afs_int32 unique;
318 {
319     int fdi;
320     FILE *file;
321     struct stat statBuf;
322
323     /* fil up special fields for itself and parent */
324     if (strcmp(fileName, ".") == 0) {
325         dirEntry->vnode = vnode;
326         return;
327     }
328     if (strcmp(fileName, "..") == 0) {
329         dirEntry->vnodeParent = vnode;
330         return;
331     }
332
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);
341 }
342
343
344 int
345 scanSmallVnode(dev, node, partitionName, option)
346      dev_t dev;
347      Inode node;
348      char *partitionName;
349      char option;               /* user options */
350 {
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;
355     FILE *file;
356     struct stat statBuf;
357
358     /* open this smallVodeIndex */
359     if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
360         printf("Error in reading node : %d\n", errno);
361         exit(5);
362     }
363
364     /* get a FILE pointer */
365     if ((file = fdopen(fdi, "r")) == 0) {
366         printf("fdopen failed : %d\n", errno);
367         exit(6);
368     }
369
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);
373         exit(6);
374     }
375     nVnodes = (statBuf.st_size / diskSize) - 1;
376     if (nVnodes > 0)
377         fseek(file, diskSize, 0);
378     else
379         nVnodes = 0;
380
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;
387             DirEnt *dir;
388 #ifdef FILE_DEBUG
389             printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
390                    vnode->parent);
391 #endif
392
393             if ((dir = lookup(vnode->parent)) == 0)     /* orphaned */
394                 orphan = 1, pushStack(orphan_NoVnode);
395             if (!orphan) {
396                 name = getFileName(dir, vnode->uniquifier);
397                 if (name == 0)
398                     orphan = 1, pushStack(orphan_NoUnique);
399             }
400             if (!orphan) {
401                 /* push the file name on stack */
402                 pushStack(name);
403                 pNode = vnode->parent;
404                 nNode = dir->vnodeParent;
405             }
406             while (!orphan && (pNode != nNode)) {
407                 if ((dir = lookup(nNode)) == 0) {
408                     orphan = 1, pushStack(orphan_NoVnode);
409                     break;
410                 }
411                 if ((name = getDirName(dir, pNode)) == 0) {
412                     orphan = 1, pushStack(orphan_NoVnode);
413                     break;
414                 }
415                 pushStack(name);
416                 pNode = nNode;
417                 nNode = dir->vnodeParent;
418             }
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;
423                 int fdLink;
424                 char *symLink;
425                 if ((fdLink = iopen(dev, vnode->inodeNumber, O_RDONLY)) < 0) {
426                     printf("Error in opening symbolic link : %d\n", errno);
427                     exit(10);
428                 }
429                 if (fstat(fdLink, &statLink) < 0) {
430                     printf("Error in symLink stat(fd=%d): %d\n", fdLink,
431                            errno);
432                     exit(12);
433                 }
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);
437                     exit(11);
438                 }
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);
443                 free(symLink);
444                 close(fdLink);
445             }
446             if (option & allFiles) {
447                 if (option & lFlag) {
448                     switch (vnode->type) {
449                     case vFile:
450                         printf("F ");
451                         break;
452                     case vDirectory:
453                         printf("D ");
454                         break;
455                     case vSymlink:
456                         printf("S ");
457                         break;
458                     default:
459                         printf("U ");
460                         break;
461                     }
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);
468                 }
469                 printf("~%s\n", fullPathName);
470             }
471         }
472
473     fclose(file);
474 }
475
476 /* Lists all directories in the volume */
477 printDirs(partitionName)
478      char *partitionName;
479 {
480     int i, j, vnode, inode;
481     DirEnt *ptr, *dir, *tmpDir;
482
483     /* The root level vnode for this volume */
484     tmpDir = lookup(1);         /* root vnode is 1 */
485     if (tmpDir == 0)
486         printf("Root vnode(1) does not exists :%s\n", partitionName);
487     else
488         printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
489
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++) {
493                 int nVnode, pVnode;
494                 char *fullPathName, *name;
495
496                 pVnode = ptr->vnodeParent;      /* parent vnode */
497                 nVnode = ptr->vnode;    /* this dir vnode */
498                 vnode = ptr->vnodeName[j].vnode;        /* my Vnode */
499
500                 /* directory vnode numbers are odd */
501                 if ((vnode % 2) == 0)
502                     continue;
503
504                 tmpDir = lookup(vnode);
505                 if (!tmpDir) {  /* orphaned directory */
506                     printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
507                     continue;
508                 }
509                 inode = tmpDir->inode;  /* the inode for this vnode */
510
511                 pushStack(ptr->vnodeName[j].name);
512
513                 while (pVnode != 1) {
514                     dir = lookup(pVnode);
515                     if (dir == 0) {     /* orphan */
516                         pushStack(orphan_NoVnode);
517                         break;
518                     }
519                     name = getDirName(dir, nVnode);
520                     if (name == 0) {
521                         pushStack(orphan_NoVnode);
522                         break;
523                     }
524                     pushStack(name);
525                     nVnode = pVnode;
526                     pVnode = dir->vnodeParent;
527                 }
528                 fullPathName = printStack();    /* full path name of directory */
529                 printf("D Ind:%d Vnd:%d ~%s\n", inode, vnode, fullPathName);
530             }
531 }
532
533 /* figure out how many pages in use in a directory, given ptr to its (locked) he
534 ader */
535 static
536 ComputeUsedPages(dhp)
537      struct DirHeader *dhp;
538 {
539     afs_int32 usedPages, i;
540
541     if (dhp->header.pgcount != 0) {
542         /* new style */
543         usedPages = ntohs(dhp->header.pgcount);
544     } else {
545         /* old style */
546         usedPages = 0;
547         for (i = 0; i < MAXPAGES; i++) {
548             if (dhp->alloMap[i] == EPP) {
549                 usedPages = i;
550                 break;
551             }
552         }
553         if (usedPages == 0)
554             usedPages = MAXPAGES;
555     }
556     return usedPages;
557 }
558
559 printContentsOfDirInode(device, dirInode, fullName, options)
560      dev_t device;
561      Inode dirInode;
562      char *fullName;
563      char options;
564 {
565     int fd, i, j, usedPages, pages;
566     FILE *file;
567     struct stat statBuf;
568     char dirPage[2048];
569     struct DirHeader *dhp = (struct DirHeader *)&dirPage[0];
570     struct DirEntry *de;
571     struct PageHeader *pg;
572
573     fd = iopen(device, dirInode, O_RDONLY);
574     if (fd <= 0) {
575         printf("Cannot open direcory inode %d\n", dirInode);
576         return -1;
577     }
578     if ((file = fdopen(fd, "r")) == 0) {        /* for buffered read */
579         printf("fdopen failed : %d\n", errno);
580         close(fd);
581         return -1;
582     }
583     if (fstat(fd, &statBuf) < 0) {
584         printf("Error in stat(fd=%d): %d\n", fd, errno);
585         return -1;
586     }
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,
590                errno);
591         fclose(file);
592         return -1;
593     }
594     usedPages = ComputeUsedPages(dhp);
595
596     printf("Alloc map: ");
597     for (i = 0; i < MAXPAGES; i++) {
598         if ((i % 16) == 0)
599             printf("\n");
600         printf("%.2x ", (unsigned char)dhp->alloMap[i]);
601     }
602     printf("\nHash table:");
603     for (i = 0; i < NHASHENT; i++) {
604         if ((i % 16) == 0)
605             printf("\n");
606         printf("%.2d ", dhp->hashTable[i]);
607     }
608     printf("\n");
609
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]));
618     printf("\n");
619
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,
625                de->name);
626
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,
631                    dirInode, errno);
632             fclose(file);
633             return -1;
634         }
635         pg = &((struct DirPage1 *)dirPage)->header;     /* page header */
636         de = ((struct DirPage1 *)dirPage)->entry;
637
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]));
646         printf("\n");
647
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);
653     }
654
655     fclose(file);
656     return 0;
657 }