fileserver & friends: Don't cast from malloc()
[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 "filesignal.h"
101 #include "vutils.h"
102 #include "daemon_com.h"
103 #include "fssync.h"
104 #include <afs/auxinode.h>
105 #include <afs/dir.h>
106 #include <unistd.h>
107
108 #ifdef  AFS_OSF_ENV
109 extern void *calloc(), *realloc();
110 #endif
111 #include "salvage.h"
112 int volumeId;
113 int VolumeChanged;              /* to satisfy library libdir use */
114
115 #include "listVicepx.h"
116 char *orphan_NoVnode = "ORPHANED_NoVnode";
117 char *orphan_NoUnique = "ORPHANED_NoUnique";
118
119 #define allNull         0x00
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 */
125
126 extern DirEnt *lookup();
127 extern char *getFileName(), *getDirName(), *printStack();
128 extern DirEnt *hash[];
129
130 int
131 Usage(name)
132      char *name;
133 {
134     assert(name);
135     printf
136         ("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n",
137          name);
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");
143     exit(1);
144 }
145
146
147 main(argc, argv)
148      int argc;
149      char *argv[];
150 {
151     char fullName[32 + VNAMESIZE + sizeof(VHDREXT) + 4];
152     char partition[32], volume[VNAMESIZE];
153     struct stat statBuf;
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 */
158
159     for (i = 1; i < argc; i++) {
160         if (!strcmp(argv[i], "-p")) {
161             if ((i + 1) >= argc)
162                 Usage(argv[0]);
163             assert(strlen(argv[i + 1]) < 32);
164             strcpy(partition, argv[++i]);
165             sawPart = 1;
166         } else if (!strcmp(argv[i], "-v")) {
167             if ((i + 1) >= argc)
168                 Usage(argv[0]);
169             assert(strlen(argv[i + 1]) < VNAMESIZE);
170             strcpy(volume, argv[++i]);
171             sawVolume = 1;
172         } else if (!strcmp(argv[i], "-dir")) {
173             if ((i + 1) >= argc)
174                 Usage(argv[0]);
175             dirInode = atoi(argv[++i]);
176             option |= contentsDInode;
177             sawDirContents = 1;
178         } else if (!strcmp(argv[i], "-ls"))
179             option |= allFiles;
180         else if (!strcmp(argv[i], "-lsl"))
181             option |= (allFiles | lFlag);
182         else if (!strcmp(argv[i], "-ld"))
183             option |= allDirs;
184         else if (!strcmp(argv[i], "-volInfo"))
185             option |= volInfo;
186         else
187             Usage(argv[0]);
188     }
189     /* check input parameters */
190     if (!sawPart || !sawVolume)
191         Usage(argv[0]);
192
193     /* extract volume id */
194     volumeId = atoi(volume);
195
196     /* construct  unix file name */
197     strcpy(fullName, partition);
198     strcat(fullName, "/V");
199     strcat(fullName, volume);
200     strcat(fullName, VHDREXT);
201
202     /* check to see that volume exists */
203     if (stat(fullName, &statBuf) < 0) {
204         printf("Error in stat(%s) : %d\n", fullName, errno);
205         exit(2);
206     }
207
208     /* read volume header */
209     if ((fd = open(fullName, O_RDONLY)) < 0) {
210         printf("Error in open(%s) : %d\n", fullName, errno);
211         exit(3);
212     }
213     if (read(fd, &volumeHeader, sizeof(struct VolumeHeader)) <
214         sizeof(struct VolumeHeader)) {
215         printf("Error in reading Volume Header : %d\n", errno);
216         exit(4);
217     }
218
219     switch (option) {
220     case volInfo:               /* volume header info */
221         printf
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);
227         break;
228
229     case contentsDInode:        /* list directory entries */
230         printContentsOfDirInode(statBuf.st_dev, dirInode, fullName, option);
231         break;
232     }
233
234     scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName,
235                    option);
236     if (option & allDirs)
237         printDirs(fullName);
238
239     if (option & allFiles)
240         scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName,
241                        option);
242     close(fd);
243 }
244
245 int
246 scanLargeVnode(dev, node, partitionName, option)
247      dev_t dev;
248      Inode node;
249      char *partitionName;
250      char option;               /* user options */
251 {
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;
256     FILE *file;
257     struct stat statBuf;
258
259     /* open this largeVodeIndex */
260     if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
261         printf("Error in reading node : %d\n", errno);
262         exit(5);
263     }
264
265     /* get a FILE pointer */
266     if ((file = fdopen(fdi, "r")) == 0) {
267         printf("fdopen failed : %d\n", errno);
268         exit(6);
269     }
270
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);
274         exit(6);
275     }
276     nVnodes = (statBuf.st_size / diskSize) - 1;
277     if (nVnodes > 0)
278         fseek(file, diskSize, 0);
279     else
280         nVnodes = 0;
281
282     /* scan all entries in this volume */
283     DInit(10);                  /* initialise directory buffer */
284
285     for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
286          nVnodes--, vnodeIndex++, offset += diskSize) {
287         /* scan this directory */
288         int createDirEnt();
289         if ((vnode->type == vDirectory) && (vnode->inodeNumber)) {
290             DirHandle dir;
291             DirEnt *dirEntry;
292
293             dir.volume = volumeId;
294             dir.device = dev;
295             dir.cacheCheck = 0;
296             dir.inode = vnode->inodeNumber;
297 #ifdef  DEBUG
298             printf
299                 ("Directory inode %d (parent vnode = %d) contains the entries :\n",
300                  vnode->inodeNumber, vnode->parent);
301 #endif
302
303             assert(dirEntry = 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 */
309         }
310     }
311     fclose(file);
312 #ifdef DEBUG
313     printHash();
314 #endif
315 }
316
317
318
319 int
320 createDirEnt(dirEntry, fileName, vnode, unique)
321      DirEnt *dirEntry;
322      char *fileName;
323      afs_int32 vnode;
324      afs_int32 unique;
325 {
326     int fdi;
327     FILE *file;
328     struct stat statBuf;
329
330     /* fil up special fields for itself and parent */
331     if (strcmp(fileName, ".") == 0) {
332         dirEntry->vnode = vnode;
333         return;
334     }
335     if (strcmp(fileName, "..") == 0) {
336         dirEntry->vnodeParent = vnode;
337         return;
338     }
339
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);
348 }
349
350
351 int
352 scanSmallVnode(dev, node, partitionName, option)
353      dev_t dev;
354      Inode node;
355      char *partitionName;
356      char option;               /* user options */
357 {
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;
362     FILE *file;
363     struct stat statBuf;
364
365     /* open this smallVodeIndex */
366     if ((fdi = iopen(dev, node, O_RDONLY)) < 0) {
367         printf("Error in reading node : %d\n", errno);
368         exit(5);
369     }
370
371     /* get a FILE pointer */
372     if ((file = fdopen(fdi, "r")) == 0) {
373         printf("fdopen failed : %d\n", errno);
374         exit(6);
375     }
376
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);
380         exit(6);
381     }
382     nVnodes = (statBuf.st_size / diskSize) - 1;
383     if (nVnodes > 0)
384         fseek(file, diskSize, 0);
385     else
386         nVnodes = 0;
387
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;
394             DirEnt *dir;
395 #ifdef FILE_DEBUG
396             printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
397                    vnode->parent);
398 #endif
399
400             if ((dir = lookup(vnode->parent)) == 0)     /* orphaned */
401                 orphan = 1, pushStack(orphan_NoVnode);
402             if (!orphan) {
403                 name = getFileName(dir, vnode->uniquifier);
404                 if (name == 0)
405                     orphan = 1, pushStack(orphan_NoUnique);
406             }
407             if (!orphan) {
408                 /* push the file name on stack */
409                 pushStack(name);
410                 pNode = vnode->parent;
411                 nNode = dir->vnodeParent;
412             }
413             while (!orphan && (pNode != nNode)) {
414                 if ((dir = lookup(nNode)) == 0) {
415                     orphan = 1, pushStack(orphan_NoVnode);
416                     break;
417                 }
418                 if ((name = getDirName(dir, pNode)) == 0) {
419                     orphan = 1, pushStack(orphan_NoVnode);
420                     break;
421                 }
422                 pushStack(name);
423                 pNode = nNode;
424                 nNode = dir->vnodeParent;
425             }
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;
430                 int fdLink;
431                 char *symLink;
432                 if ((fdLink = iopen(dev, vnode->inodeNumber, O_RDONLY)) < 0) {
433                     printf("Error in opening symbolic link : %d\n", errno);
434                     exit(10);
435                 }
436                 if (fstat(fdLink, &statLink) < 0) {
437                     printf("Error in symLink stat(fd=%d): %d\n", fdLink,
438                            errno);
439                     exit(12);
440                 }
441                 assert(symLink = malloc(statLink.st_size + 1));
442                 if (read(fdLink, symLink, statLink.st_size) < 0) {
443                     printf("Error in reading symbolic link : %d\n", errno);
444                     exit(11);
445                 }
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);
450                 free(symLink);
451                 close(fdLink);
452             }
453             if (option & allFiles) {
454                 if (option & lFlag) {
455                     switch (vnode->type) {
456                     case vFile:
457                         printf("F ");
458                         break;
459                     case vDirectory:
460                         printf("D ");
461                         break;
462                     case vSymlink:
463                         printf("S ");
464                         break;
465                     default:
466                         printf("U ");
467                         break;
468                     }
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);
475                 }
476                 printf("~%s\n", fullPathName);
477             }
478         }
479
480     fclose(file);
481 }
482
483 /* Lists all directories in the volume */
484 printDirs(partitionName)
485      char *partitionName;
486 {
487     int i, j, vnode, inode;
488     DirEnt *ptr, *dir, *tmpDir;
489
490     /* The root level vnode for this volume */
491     tmpDir = lookup(1);         /* root vnode is 1 */
492     if (tmpDir == 0)
493         printf("Root vnode(1) does not exists :%s\n", partitionName);
494     else
495         printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
496
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++) {
500                 int nVnode, pVnode;
501                 char *fullPathName, *name;
502
503                 pVnode = ptr->vnodeParent;      /* parent vnode */
504                 nVnode = ptr->vnode;    /* this dir vnode */
505                 vnode = ptr->vnodeName[j].vnode;        /* my Vnode */
506
507                 /* directory vnode numbers are odd */
508                 if ((vnode % 2) == 0)
509                     continue;
510
511                 tmpDir = lookup(vnode);
512                 if (!tmpDir) {  /* orphaned directory */
513                     printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
514                     continue;
515                 }
516                 inode = tmpDir->inode;  /* the inode for this vnode */
517
518                 pushStack(ptr->vnodeName[j].name);
519
520                 while (pVnode != 1) {
521                     dir = lookup(pVnode);
522                     if (dir == 0) {     /* orphan */
523                         pushStack(orphan_NoVnode);
524                         break;
525                     }
526                     name = getDirName(dir, nVnode);
527                     if (name == 0) {
528                         pushStack(orphan_NoVnode);
529                         break;
530                     }
531                     pushStack(name);
532                     nVnode = pVnode;
533                     pVnode = dir->vnodeParent;
534                 }
535                 fullPathName = printStack();    /* full path name of directory */
536                 printf("D Ind:%d Vnd:%d ~%s\n", inode, vnode, fullPathName);
537             }
538 }
539
540 /* figure out how many pages in use in a directory, given ptr to its (locked) he
541 ader */
542 static
543 ComputeUsedPages(dhp)
544      struct DirHeader *dhp;
545 {
546     afs_int32 usedPages, i;
547
548     if (dhp->header.pgcount != 0) {
549         /* new style */
550         usedPages = ntohs(dhp->header.pgcount);
551     } else {
552         /* old style */
553         usedPages = 0;
554         for (i = 0; i < MAXPAGES; i++) {
555             if (dhp->alloMap[i] == EPP) {
556                 usedPages = i;
557                 break;
558             }
559         }
560         if (usedPages == 0)
561             usedPages = MAXPAGES;
562     }
563     return usedPages;
564 }
565
566 printContentsOfDirInode(device, dirInode, fullName, options)
567      dev_t device;
568      Inode dirInode;
569      char *fullName;
570      char options;
571 {
572     int fd, i, j, usedPages, pages;
573     FILE *file;
574     struct stat statBuf;
575     char dirPage[2048];
576     struct DirHeader *dhp = (struct DirHeader *)&dirPage[0];
577     struct DirEntry *de;
578     struct PageHeader *pg;
579
580     fd = iopen(device, dirInode, O_RDONLY);
581     if (fd <= 0) {
582         printf("Cannot open direcory inode %d\n", dirInode);
583         return -1;
584     }
585     if ((file = fdopen(fd, "r")) == 0) {        /* for buffered read */
586         printf("fdopen failed : %d\n", errno);
587         close(fd);
588         return -1;
589     }
590     if (fstat(fd, &statBuf) < 0) {
591         printf("Error in stat(fd=%d): %d\n", fd, errno);
592         return -1;
593     }
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,
597                errno);
598         fclose(file);
599         return -1;
600     }
601     usedPages = ComputeUsedPages(dhp);
602
603     printf("Alloc map: ");
604     for (i = 0; i < MAXPAGES; i++) {
605         if ((i % 16) == 0)
606             printf("\n");
607         printf("%.2x ", (unsigned char)dhp->alloMap[i]);
608     }
609     printf("\nHash table:");
610     for (i = 0; i < NHASHENT; i++) {
611         if ((i % 16) == 0)
612             printf("\n");
613         printf("%.2d ", dhp->hashTable[i]);
614     }
615     printf("\n");
616
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]));
625     printf("\n");
626
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,
632                de->name);
633
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,
638                    dirInode, errno);
639             fclose(file);
640             return -1;
641         }
642         pg = &((struct DirPage1 *)dirPage)->header;     /* page header */
643         de = ((struct DirPage1 *)dirPage)->entry;
644
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]));
653         printf("\n");
654
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);
660     }
661
662     fclose(file);
663     return 0;
664 }