misc-build-cleanup-20010917
[openafs.git] / src / vlserver / vldb_check.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 /* Read a VLDB file and verify it for correctness */
11
12 #define VL  0x001      /* good volume entry */
13 #define FR  0x002      /* free volume entry */
14 #define MH  0x004      /* multi-homed entry */
15
16 #define RWH 0x010      /* on rw hash chain */
17 #define ROH 0x020      /* on ro hash chain */
18 #define BKH 0x040      /* on bk hash chain */
19 #define NH  0x080      /* on name hash chain */
20
21 #define MHC 0x100      /* on multihomed chain */
22 #define FRC 0x200      /* on free chain */
23
24 #include <afsconfig.h>
25 #include <afs/param.h>
26
27 RCSID("$Header$");
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #ifdef AFS_NT40_ENV
34 #include <winsock2.h>
35 #include <WINNT/afsevent.h>
36 #include <io.h>
37 #else
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #include <netinet/in.h>
41 #endif
42 #include "vlserver.h"
43 #include "vldbint.h"
44 #include <ubik.h>
45 #include <afs/afsutil.h>
46 #include <afs/cmd.h>
47
48 int fd;
49 int listentries, listservers, listheader, listuheader, verbose;
50
51 struct er {
52   long addr;
53   int  type;
54 } *record;
55 int serveraddrs[MAXSERVERID+2];
56   
57
58 #define HDRSIZE 64
59 int readUbikHeader()
60 {
61   int offset, r;
62   struct ubik_hdr uheader;
63
64   offset = lseek(fd, 0, 0);
65   if (offset != 0) {
66      printf("error: lseek to 0 failed: %d %d\n", offset, errno);
67      return(-1);
68   }
69
70   /* now read the info */
71   r = read(fd, &uheader, sizeof(uheader));
72   if (r != sizeof(uheader)) {
73      printf("error: read of %d bytes failed: %d %d\n", sizeof(uheader), r, errno);
74      return(-1);
75   }
76
77   uheader.magic = ntohl(uheader.magic);
78   uheader.size  = ntohl(uheader.size);
79   uheader.version.epoch   = ntohl(uheader.version.epoch);
80   uheader.version.counter = ntohl(uheader.version.counter);
81
82   if (listuheader) {
83      printf("Ubik Header\n");
84      printf("   Magic           = 0x%x\n", uheader.magic);
85      printf("   Size            = %u\n",   uheader.size);
86      printf("   Version.epoch   = %u\n",   uheader.version.epoch);
87      printf("   Version.counter = %u\n",   uheader.version.counter);
88   }
89
90   if (uheader.size != HDRSIZE)
91      printf("Ubik header size is %u (should be %u)\n", uheader.size, HDRSIZE);
92   if (uheader.magic != UBIK_MAGIC)
93      printf("Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic, UBIK_MAGIC);
94
95   return(0);
96 }
97
98 int vldbread(position,buffer,size)
99   int position;
100   char *buffer;
101   int size;
102 {
103   int offset, r, p;
104
105   /* seek to the correct spot. skip ubik stuff */
106   p = position + HDRSIZE;
107   offset = lseek(fd, p, 0);
108   if (offset != p) {
109      printf("error: lseek to %d failed: %d %d\n", p, offset, errno);
110      return(-1);
111   }
112
113   /* now read the info */
114   r = read(fd, buffer, size);
115   if (r != size) {
116      printf("error: read of %d bytes failed: %d %d\n", size, r, errno);
117      return(-1);
118   }
119   return(0);
120 }
121
122 char *vtype(type)
123   int type;
124 {
125   static char Type[3];
126
127   if      (type == 0) strcpy(Type,"rw");
128   else if (type == 1) strcpy(Type,"ro");
129   else if (type == 2) strcpy(Type,"bk");
130   else                strcpy(Type,"??");
131   return(Type);
132 }
133
134 afs_int32 NameHash(volname)
135    char *volname;
136 {
137    unsigned int hash;
138    char *vchar;
139
140    hash = 0;
141    for (vchar=volname+strlen(volname)-1; vchar >= volname; vchar--)
142       hash = (hash*63) + (*((unsigned char *)vchar) - 63);
143    return(hash % HASHSIZE);
144 }
145
146 afs_int32 IdHash(volid)
147    afs_int32 volid;
148 {
149    return((abs(volid)) % HASHSIZE);
150 }
151
152 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
153 int InvalidVolname(volname)
154   char *volname;
155 {
156   char *map;
157   size_t slen;
158
159   map = LEGALCHARS;
160   slen = strlen(volname);
161   if (slen >= VL_MAXNAMELEN) return 1;
162   return (slen != strspn(volname, map));
163 }
164
165 readheader(headerp)
166   struct vlheader *headerp;
167 {
168   int i,j;
169
170   vldbread(0, headerp, sizeof(*headerp));
171
172   headerp->vital_header.vldbversion = ntohl(headerp->vital_header.vldbversion);
173   headerp->vital_header.headersize  = ntohl(headerp->vital_header.headersize);
174   headerp->vital_header.freePtr     = ntohl(headerp->vital_header.freePtr);
175   headerp->vital_header.eofPtr      = ntohl(headerp->vital_header.eofPtr);
176   headerp->vital_header.allocs      = ntohl(headerp->vital_header.allocs);
177   headerp->vital_header.frees       = ntohl(headerp->vital_header.frees);
178   headerp->vital_header.MaxVolumeId = ntohl(headerp->vital_header.MaxVolumeId);
179   headerp->vital_header.totalEntries[0] = ntohl(headerp->vital_header.totalEntries[0]);
180   for (i=0; i<MAXTYPES; i++)
181      headerp->vital_header.totalEntries[i] = ntohl(headerp->vital_header.totalEntries[1]);
182
183   headerp->SIT = ntohl(headerp->SIT);
184   for (i=0; i<MAXSERVERID; i++)
185      headerp->IpMappedAddr[i] = ntohl(headerp->IpMappedAddr[i]);
186   for (i=0; i<HASHSIZE; i++)
187      headerp->VolnameHash[i] = ntohl(headerp->VolnameHash[i]);
188   for (i=0; i<MAXTYPES; i++) 
189      for (j=0; j<HASHSIZE; j++) 
190         headerp->VolidHash[i][j] = ntohl(headerp->VolidHash[i][j]);
191
192   if (listheader) {
193      printf("vldb header\n");
194      printf("   vldbversion      = %u\n", headerp->vital_header.vldbversion);
195      printf("   headersize       = %u [actual=%u]\n",
196             headerp->vital_header.headersize, sizeof(*headerp));
197      printf("   freePtr          = 0x%x\n", headerp->vital_header.freePtr);
198      printf("   eofPtr           = %u\n", headerp->vital_header.eofPtr);
199      printf("   allocblock calls = %10u\n", headerp->vital_header.allocs);
200      printf("   freeblock  calls = %10u\n", headerp->vital_header.frees);
201      printf("   MaxVolumeId      = %u\n", headerp->vital_header.MaxVolumeId);
202      printf("   rw vol entries   = %u\n", headerp->vital_header.totalEntries[0]);
203      printf("   ro vol entries   = %u\n", headerp->vital_header.totalEntries[1]);
204      printf("   bk vol entries   = %u\n", headerp->vital_header.totalEntries[2]);
205      printf("   multihome info   = 0x%x (%u)\n", headerp->SIT, headerp->SIT);
206      printf("   server ip addr   table: size = %d entries\n", MAXSERVERID+1);
207      printf("   volume name hash table: size = %d buckets\n", HASHSIZE);
208      printf("   volume id   hash table: %d tables with %d buckets each\n",
209             MAXTYPES, HASHSIZE);
210   }
211
212   /* Check the header size */
213   if (headerp->vital_header.headersize != sizeof(*headerp))
214      printf("Header reports its size as %d (should be %d)\n",
215             headerp->vital_header.headersize, sizeof(*headerp));
216 }
217
218 readMH(addr, mhblockP)
219   afs_int32 addr;
220   struct extentaddr *mhblockP;
221 {
222   int i, j;
223   struct extentaddr *e;
224
225   vldbread(addr, mhblockP, VL_ADDREXTBLK_SIZE);
226
227   mhblockP->ex_count = ntohl(mhblockP->ex_count);
228   mhblockP->ex_flags = ntohl(mhblockP->ex_flags);
229   for (i=0; i<VL_MAX_ADDREXTBLKS; i++)
230      mhblockP->ex_contaddrs[i] = ntohl(mhblockP->ex_contaddrs[i]);
231
232   for (i=1; i<VL_MHSRV_PERBLK; i++) {
233      e = &(mhblockP[i]);
234
235      /* won't convert hostuuid */
236      e->ex_uniquifier = ntohl(e->ex_uniquifier);
237      for (j=0; j<VL_MAXIPADDRS_PERMH; j++)
238         e->ex_addrs[j] = ntohl(e->ex_addrs[j]);
239   }
240 }     
241
242 readentry(addr, vlentryp, type)
243   afs_int32 addr;
244   struct nvlentry *vlentryp;
245   afs_int32 *type;
246 {
247   int i;
248
249   vldbread(addr, vlentryp, sizeof(*vlentryp));
250
251   for (i=0; i<MAXTYPES; i++)
252      vlentryp->volumeId[i]   = ntohl(vlentryp->volumeId[i]);
253   vlentryp->flags            = ntohl(vlentryp->flags);
254   vlentryp->LockAfsId        = ntohl(vlentryp->LockAfsId);
255   vlentryp->LockTimestamp    = ntohl(vlentryp->LockTimestamp);
256   vlentryp->cloneId          = ntohl(vlentryp->cloneId);
257   for (i=0; i<MAXTYPES; i++)    
258      vlentryp->nextIdHash[i] = ntohl(vlentryp->nextIdHash[i]);
259   vlentryp->nextNameHash     = ntohl(vlentryp->nextNameHash);
260   for (i=0; i<NMAXNSERVERS; i++) {
261      vlentryp->serverNumber[i]    = ntohl(vlentryp->serverNumber[i]);
262      vlentryp->serverPartition[i] = ntohl(vlentryp->serverPartition[i]);
263      vlentryp->serverFlags[i]     = ntohl(vlentryp->serverFlags[i]);
264   }
265
266   if (vlentryp->flags == VLCONTBLOCK) {
267      *type = MH;
268   } else if (vlentryp->flags == VLFREE) {
269      *type = FR;
270   } else {
271      *type = VL;
272   }
273
274   if (listentries) {
275      printf("address %u: ", addr);
276      if (vlentryp->flags == VLCONTBLOCK) {
277         printf("mh extension block\n");
278      } else if (vlentryp->flags == VLFREE) {
279         printf("free vlentry\n");
280      } else {
281         printf("vlentry %s\n", vlentryp->name);
282         printf("   rw id = %u ; ro id = %u ; bk id = %u\n",
283                vlentryp->volumeId[0], vlentryp->volumeId[1], vlentryp->volumeId[2]);
284         printf("   flags         =");
285            if (vlentryp->flags & VLF_RWEXISTS) printf(" rw");
286            if (vlentryp->flags & VLF_ROEXISTS) printf(" ro");
287            if (vlentryp->flags & VLF_BACKEXISTS) printf(" bk");
288            if (vlentryp->flags & 0xffff8fff) 
289               printf(" errorflag(0x%x)", vlentryp->flags);
290            printf("\n");
291         printf("   LockAfsId     = %d\n", vlentryp->LockAfsId);
292         printf("   LockTimestamp = %d\n", vlentryp->LockTimestamp);
293         printf("   cloneId       = %u\n", vlentryp->cloneId);
294         printf("   next hash for rw = %u ; ro = %u ; bk = %u ; name = %u\n",
295                vlentryp->nextIdHash[0], vlentryp->nextIdHash[1], 
296                vlentryp->nextIdHash[2], vlentryp->nextNameHash);
297         for (i=0; i<NMAXNSERVERS; i++) {
298            if (vlentryp->serverNumber[i] != 255) {
299               printf("   server %d ; partition %d ; flags =",
300                      vlentryp->serverNumber[i], vlentryp->serverPartition[i]);
301               if (vlentryp->serverFlags[i] & VLSF_RWVOL) printf(" rw");
302               if (vlentryp->serverFlags[i] & VLSF_ROVOL) printf(" ro");
303               if (vlentryp->serverFlags[i] & VLSF_BACKVOL) printf(" bk");
304               if (vlentryp->serverFlags[i] & VLSF_NEWREPSITE) printf(" newro");
305               printf("\n");
306            }
307         }
308      }
309   }
310 }
311
312 void
313 readSIT(base, addr)
314   int base;
315   int addr;
316 {
317   int i,j,a;
318   char sitbuf[VL_ADDREXTBLK_SIZE];
319   struct extentaddr *extent;
320
321   if (!addr)
322      return;
323   vldbread(addr, sitbuf, VL_ADDREXTBLK_SIZE);
324   extent = (struct extentaddr *)sitbuf;
325
326   printf("multihome info block: base %d\n", base);
327   if (base == 0) {
328      printf("   count = %u\n", ntohl(extent->ex_count));
329      printf("   flags = %u\n", ntohl(extent->ex_flags));
330      for (i=0; i<VL_MAX_ADDREXTBLKS; i++) {
331         printf("   contaddrs[%d] = %u\n", i, ntohl(extent->ex_contaddrs[i]));
332      }
333   }
334   for (i=1; i<VL_MHSRV_PERBLK; i++) {
335      /* should we skip this entry */
336      for (j=0; j<VL_MAX_ADDREXTBLKS; j++) {
337         if (extent[i].ex_addrs[j]) break;
338      }
339      if (j >= VL_MAX_ADDREXTBLKS) continue;
340
341      printf("   base %d index %d:\n", base, i);
342      
343      printf("       afsuuid    = (%x %x %x /%d/%d/ /%x/%x/%x/%x/%x/%x/)\n",
344             ntohl(extent[i].ex_hostuuid.time_low),
345             ntohl(extent[i].ex_hostuuid.time_mid),
346             ntohl(extent[i].ex_hostuuid.time_hi_and_version),
347             ntohl(extent[i].ex_hostuuid.clock_seq_hi_and_reserved),
348             ntohl(extent[i].ex_hostuuid.clock_seq_low),
349             ntohl(extent[i].ex_hostuuid.node[0]), ntohl(extent[i].ex_hostuuid.node[1]),
350             ntohl(extent[i].ex_hostuuid.node[2]), ntohl(extent[i].ex_hostuuid.node[3]),
351             ntohl(extent[i].ex_hostuuid.node[4]), ntohl(extent[i].ex_hostuuid.node[5]));
352      printf("       uniquifier = %u\n", ntohl(extent[i].ex_uniquifier));
353      for (j=0; j<VL_MAXIPADDRS_PERMH; j++) {
354         a = ntohl(extent[i].ex_addrs[j]);
355         if (a) {
356            printf("       %d.%d.%d.%d\n",
357                   (a>>24)&0xff, (a>>16)&0xff,
358                   (a>>8) &0xff, (a    )&0xff);
359         }
360      }
361   }
362 }
363
364 /*
365  * Read each entry in the database:
366  * Record what type of entry it is and its address in the record array.
367  * Remember what the maximum volume id we found is and check against the header.
368  */
369 void
370 ReadAllEntries(header)
371   struct vlheader *header;
372 {
373   afs_int32 type, rindex, i, j, e;
374   int freecount=0, mhcount=0, vlcount=0;
375   int rwcount=0, rocount=0, bkcount=0;
376   struct nvlentry vlentry;
377   afs_uint32 addr, entrysize, maxvolid=0;
378
379   if (verbose)
380      printf("Read each entry in the database\n");
381   for (addr = header->vital_header.headersize;
382        addr < header->vital_header.eofPtr; addr += entrysize) {
383
384      /* Remember the highest volume id */
385      readentry(addr, &vlentry, &type);
386      if (type == VL) {
387         if (!(vlentry.flags & VLF_RWEXISTS))
388            printf("WARNING: VLDB entry '%s' has no RW volume\n", vlentry.name);
389
390         for (i=0; i<MAXTYPES; i++)
391            if (maxvolid < vlentry.volumeId[i]) maxvolid = vlentry.volumeId[i];
392
393         e = 1;
394         for (j=0; j<NMAXNSERVERS; j++) {
395            if (vlentry.serverNumber[j] == 255) continue;
396            if (vlentry.serverFlags[j] & (VLSF_ROVOL|VLSF_NEWREPSITE)) {
397               rocount++;
398               continue;
399            }
400            if (vlentry.serverFlags[j] & VLSF_RWVOL) {
401               rwcount++;
402               if (vlentry.flags & VLF_BACKEXISTS) bkcount++;
403               continue;
404            }
405            if (e) {
406               printf("VLDB entry '%s' contains an unknown RW/RO index serverFlag\n", 
407                      vlentry.name);
408               e = 0;
409            }
410            printf("   index %d : serverNumber %d : serverPartition %d : serverFlag %d\n", 
411                   j, vlentry.serverNumber[j], vlentry.serverPartition[j], vlentry.serverFlags[j]);
412         }
413      }
414
415      rindex = addr/sizeof(vlentry);
416      if (record[rindex].type) {
417         printf("INTERNAL ERROR: record holder %d already in use\n", rindex);
418         return;
419      }
420      record[rindex].addr = addr;
421      record[rindex].type = type;
422
423      /* Determine entrysize and keep count */
424      if (type == VL) {
425         entrysize = sizeof(vlentry);
426         vlcount++;
427      } else if (type == FR) {
428         entrysize = sizeof(vlentry);
429         freecount++;
430      } else if (type == MH) {
431         entrysize = VL_ADDREXTBLK_SIZE;
432         mhcount++;
433      } else {
434         printf("Unknown entry at %u\n", addr);
435      }
436   }
437   if (verbose) {
438      printf("Found %d entries, %d free entries, %d multihomed blocks\n",
439             vlcount, freecount, mhcount);
440      printf("Found %d RW volumes, %d BK volumes, %d RO volumes\n",
441             rwcount, bkcount, rocount);
442   }
443
444   /* Check the maxmimum volume id in the header */
445   if (maxvolid != header->vital_header.MaxVolumeId-1)
446      printf("Header's maximum volume id is %u and largest id found in VLDB is %u\n",
447             header->vital_header.MaxVolumeId, maxvolid);
448 }
449
450
451 /*
452  * Follow each Name hash bucket marking it as read in the record array.
453  * Record we found it in the name hash within the record array.
454  * Check that the name is hashed correctly.
455  */
456 FollowNameHash(header)
457   struct vlheader *header;
458 {
459   int count=0, longest=0, shortest=-1, chainlength;
460   struct nvlentry vlentry;
461   afs_uint32 addr;
462   afs_int32 i, type, rindex;
463
464   /* Now follow the Name Hash Table */
465   if (verbose)
466      printf("Check Volume Name Hash\n");
467   for (i=0; i<HASHSIZE; i++) {
468      chainlength = 0;
469      for (addr = header->VolnameHash[i]; addr; addr=vlentry.nextNameHash) {
470         readentry(addr, &vlentry, &type);
471         if (type != VL) {
472            printf("Name Hash %d: Bad entry at %u: Not a valid vlentry\n", i, addr);
473            continue;
474         }
475
476         rindex = addr/sizeof(vlentry);
477
478         if (record[rindex].addr != addr && record[rindex].addr) {
479            printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
480                   record[rindex].addr, addr, rindex);
481         }
482         if (record[rindex].type & NH) {
483            printf("Name Hash %d: Bad entry '%s': Already in the name hash\n",
484                   i, vlentry.name);
485            break;
486         }
487         record[rindex].type |= NH;
488
489         chainlength++;
490         count++;
491
492         /* Hash the name and check if in correct hash table */
493         if (NameHash(vlentry.name) != i) {
494            printf("Name Hash %d: Bad entry '%s': Incorrect name hash chain (should be in %d)\n",
495                   i, vlentry.name, NameHash(vlentry.name));
496         }
497      }
498      if (chainlength > longest) longest = chainlength;
499      if ((shortest == -1) || (chainlength < shortest)) shortest = chainlength;
500   }
501   if (verbose) {
502      printf("%d entries in name hash, longest is %d, shortest is %d, average length is %f\n",
503             count, longest, shortest, ((float)count/(float)HASHSIZE));
504   }
505 }
506
507 /*
508  * Follow the ID hash chains for the RW, RO, and BK hash tables.
509  * Record we found it in the id hash within the record array.
510  * Check that the ID is hashed correctly.
511  */
512 FollowIdHash(header)
513   struct vlheader *header;
514 {
515   int count=0, longest=0, shortest=-1, chainlength;
516   struct nvlentry vlentry;
517   afs_uint32 addr;
518   afs_int32 i, j, hash, type, rindex;
519
520   /* Now follow the RW, RO, and BK Hash Tables */
521   if (verbose)
522      printf("Check RW, RO, and BK id Hashes\n");
523   for (i=0; i<MAXTYPES; i++) {
524      hash = ((i==0)?RWH : ((i==1)?ROH : BKH));
525      count = longest = 0; shortest = -1;
526
527      for (j=0; j<HASHSIZE; j++) {
528         chainlength = 0;
529         for (addr=header->VolidHash[i][j]; addr; addr=vlentry.nextIdHash[i]) {
530            readentry(addr, &vlentry, &type);
531            if (type != VL) {
532               printf("%s Id Hash %d: Bad entry at %u: Not a valid vlentry\n",
533                      vtype(i), j, addr);
534               continue;
535            }
536
537            rindex = addr/sizeof(vlentry);
538            if (record[rindex].addr != addr && record[rindex].addr) {
539               printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
540                      record[rindex].addr, addr, rindex);
541            }
542            if (record[rindex].type & hash) {
543               printf("%s Id Hash %d: Bad entry '%s': Already in the the hash table\n",
544                      vtype(i), j, vlentry.name);
545               break;
546            } 
547            record[rindex].type |= hash;
548
549            chainlength++;
550            count++;
551
552            /* Hash the id and check if in correct hash table */
553            if (IdHash(vlentry.volumeId[i]) != j) {
554               printf("%s Id Hash %d: Bad entry '%s': Incorrect Id hash chain (should be in %d)\n",
555                      vtype(i), j, vlentry.name, IdHash(vlentry.volumeId[i]));
556            }
557         }
558
559         if (chainlength > longest) longest = chainlength;
560         if ((shortest == -1) || (chainlength < shortest)) shortest = chainlength;
561      }
562      if (verbose) {
563         printf("%d entries in %s hash, longest is %d, shortest is %d, average length is %f\n",
564                count, vtype(i), longest, shortest, ((float)count/(float)HASHSIZE));
565      }
566   }
567 }
568
569 /*
570  * Follow the free chain.
571  * Record we found it in the free chain within the record array.
572  */
573 FollowFreeChain(header)
574   struct vlheader *header;
575 {
576   afs_int32 count=0;
577   struct nvlentry vlentry;
578   afs_uint32 addr;
579   afs_int32 type, rindex;
580
581   /* Now follow the Free Chain */
582   if (verbose)
583      printf("Check Volume Free Chain\n");
584   for (addr=header->vital_header.freePtr; addr; addr=vlentry.nextIdHash[0]) {
585      readentry(addr, &vlentry, &type);
586      if (type != FR) {
587         printf("Free Chain %d: Bad entry at %u: Not a valid free vlentry (0x%x)\n",
588                count, addr, type);
589         continue;
590      }
591
592      rindex = addr/sizeof(vlentry);
593      if (record[rindex].addr != addr && record[rindex].addr) {
594         printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
595                record[rindex].addr, addr, rindex);
596      }
597      if (record[rindex].type & FRC) {
598         printf("Free Chain: Bad entry at %u: Already in the free chain\n", addr);
599         break;
600      }
601      record[rindex].type |= FRC;
602
603      count++;
604   }
605   if (verbose)
606      printf("%d entries on free chain\n", count);
607 }
608
609 /*
610  * Read each multihomed block and mark it as found in the record.
611  * Read each entry in each multihomed block and mark the serveraddrs
612  * array with the number of ip addresses found for this entry.
613  * 
614  * Then read the IpMappedAddr array in the header.
615  * Verify that multihomed entries base and index are valid and points to
616  * a good multhomed entry.
617  * Mark the serveraddrs array with 1 ip address for regular entries.
618  * 
619  * By the end, the severaddrs array will have a 0 if the entry has no 
620  * IP addresses in it or the count of the number of IP addresses.
621  *
622  * The code does not verify if there are duplicate IP addresses in the 
623  * list. The vlserver does this when a fileserver registeres itself.
624  */
625 CheckIpAddrs(header)
626   struct vlheader *header;
627 {
628   int mhblocks=0;
629   afs_int32 i, j, m, rindex;
630   afs_int32 mhentries, regentries;
631   afs_int32 caddrs[VL_MAX_ADDREXTBLKS];
632   char mhblock[VL_ADDREXTBLK_SIZE];
633   struct extentaddr *MHblock = (struct extentaddr *)mhblock;
634   struct extentaddr *e;
635   int ipindex, ipaddrs;
636   afsUUID nulluuid;
637
638   memset(&nulluuid, 0, sizeof(nulluuid));
639
640   if (verbose)
641      printf("Check Multihomed blocks\n");
642
643   if (header->SIT) {
644      /* Read the first MH block and from it, gather the 
645       * addresses of all the mh blocks.
646       */
647      readMH(header->SIT, MHblock);
648      if (MHblock->ex_flags != VLCONTBLOCK) {
649         printf("Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
650                header->SIT);
651      }
652
653      for (i=0; i<VL_MAX_ADDREXTBLKS; i++) {
654         caddrs[i] = MHblock->ex_contaddrs[i];
655      }
656
657      if (header->SIT != caddrs[0]) {
658         printf("MH block does not point to self %u in header, %u in block\n",
659                header->SIT, caddrs[0]);
660      }
661      
662      /* Now read each MH block and record it in the record array */
663      for (i=0; i<VL_MAX_ADDREXTBLKS; i++) {
664         if (!caddrs[i]) continue;
665
666         readMH(caddrs[i], MHblock);
667         if (MHblock->ex_flags != VLCONTBLOCK) {
668            printf("Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
669                   header->SIT);
670         }
671
672         rindex = caddrs[i]/sizeof(vlentry);
673         if (record[rindex].addr != caddrs[i] && record[rindex].addr) {
674            printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
675                   record[rindex].addr, caddrs[i], rindex);
676         }
677         if (record[rindex].type & FRC) {
678            printf("MH Blocks Chain %d: Bad entry at %u: Already a MH block\n", i, record[rindex].addr);
679            break;
680         }
681         record[rindex].type |= MHC;
682         
683         mhblocks++;
684
685         /* Read each entry in a multihomed block. 
686          * Find the pointer to the entry in the IpMappedAddr array and
687          * verify that the entry is good (has IP addresses in it).
688          */
689         mhentries = 0;
690         for (j=1; j<VL_MHSRV_PERBLK; j++) {
691            e = (struct extentaddr *)&(MHblock[j]);
692
693            /* Search the IpMappedAddr array for the reference to this entry */
694            for (ipindex=0; ipindex<MAXSERVERID; ipindex++) {
695               if (  ((header->IpMappedAddr[ipindex] & 0xff000000) == 0xff000000) &&
696                    (((header->IpMappedAddr[ipindex] & 0x00ff0000)>>16) == i)     &&
697                     ((header->IpMappedAddr[ipindex] & 0x0000ffff)      == j) ) {
698                  break;
699               }
700            }
701            if (ipindex >= MAXSERVERID) ipindex = -1;
702            else serveraddrs[ipindex] = -1;
703
704            if (memcmp(&e->ex_hostuuid, &nulluuid, sizeof(afsUUID)) == 0) {
705               if (ipindex != -1) {
706                  printf("Server Addrs index %d references null MH block %d, index %d\n", i, j);
707                  serveraddrs[ipindex] = 0;     /* avoids printing 2nd error below */
708               }
709               continue;
710            }
711
712            /* Step through each ip address and count the good addresses */
713            ipaddrs = 0;
714            for (m=0; m<VL_MAXIPADDRS_PERMH; m++) {
715              if (e->ex_addrs[m]) ipaddrs++;
716            }
717
718            /* If we found any good ip addresses, mark it in the serveraddrs record */
719            if (ipaddrs) {
720               mhentries++;
721               if (ipindex == -1) {
722                  printf("MH block %d, index %d: Not referenced by server addrs\n", i, j);
723               } else {
724                  serveraddrs[ipindex] = ipaddrs;       /* It is good */
725               }
726            }
727
728            if (listservers && ipaddrs) {
729               printf("MH block %d, index %d:", i, j);
730               for (m=0; m<VL_MAXIPADDRS_PERMH; m++) {
731                  if (!e->ex_addrs[m]) continue;
732                  printf(" %d.%d.%d.%d",
733                         (e->ex_addrs[m]&0xff000000)>>24,
734                         (e->ex_addrs[m]&0x00ff0000)>>16,
735                         (e->ex_addrs[m]&0x0000ff00)>>8,
736                         (e->ex_addrs[m]&0x000000ff));
737               }
738               printf("\n");
739            }
740         }
741 /*
742  *      if (mhentries != MHblock->ex_count) {
743  *         printf("MH blocks says it has %d entries (found %d)\n",
744  *                MHblock->ex_count, mhentries);
745  *      }
746  */
747      }
748   }
749   if (verbose)
750      printf("%d multihomed blocks\n", mhblocks);
751
752   /* Check the server addresses */
753   if (verbose)
754      printf("Check server addresses\n");
755   mhentries = regentries = 0;
756   for (i=0; i<=MAXSERVERID; i++) {
757      if (header->IpMappedAddr[i]) {
758         if ((header->IpMappedAddr[i] & 0xff000000) == 0xff000000) {
759            mhentries++;
760            if (((header->IpMappedAddr[i] & 0x00ff0000)>>16) > VL_MAX_ADDREXTBLKS)
761               printf("IP Addr for entry %d: Multihome block is bad (%d)\n",
762                      i, ((header->IpMappedAddr[i] & 0x00ff0000)>>16));
763            if ( ((header->IpMappedAddr[i] & 0x0000ffff) > VL_MHSRV_PERBLK) ||
764                 ((header->IpMappedAddr[i] & 0x0000ffff) < 1) )
765               printf("IP Addr for entry %d: Multihome index is bad (%d)\n",
766                      i, (header->IpMappedAddr[i] & 0x0000ffff));
767            if (serveraddrs[i] == -1) {
768               printf("warning: IP Addr for entry %d: Multihome entry has no ip addresses\n", i);
769               serveraddrs[i] = 0;
770            }
771            if (listservers) {
772               printf("   Server ip addr %d = MH block %d, index %d\n", i,
773                      (header->IpMappedAddr[i] & 0x00ff0000)>>16,
774                      (header->IpMappedAddr[i] & 0x0000ffff));
775            }
776         } else {
777            regentries++;
778            serveraddrs[i] = 1;       /* It is good */
779            if (listservers) {
780               printf("   Server ip addr %d = %d.%d.%d.%d\n", i, 
781                      (header->IpMappedAddr[i]&0xff000000)>>24,
782                      (header->IpMappedAddr[i]&0x00ff0000)>>16,
783                      (header->IpMappedAddr[i]&0x0000ff00)>>8,
784                      (header->IpMappedAddr[i]&0x000000ff));
785            }
786         }
787      }
788   }
789   if (verbose) {
790      printf("%d simple entries, %d multihomed entries, Total = %d\n",
791             regentries, mhentries, mhentries+regentries);
792   }
793
794 }
795
796 int
797 WorkerBee(as, arock)
798   struct cmd_syndesc *as;
799   char *arock;
800 {
801   char *dbfile;
802   afs_int32  maxentries, type;
803   struct vlheader header;
804   struct nvlentry vlentry;
805   int i, j, help=0;
806
807   dbfile = as->parms[0].items->data;          /* -database */
808   listuheader = (as->parms[1].items ? 1 : 0); /* -uheader  */
809   listheader  = (as->parms[2].items ? 1 : 0); /* -vheader  */
810   listservers = (as->parms[3].items ? 1 : 0); /* -servers  */
811   listentries = (as->parms[4].items ? 1 : 0); /* -entries  */
812   verbose     = (as->parms[5].items ? 1 : 0); /* -verbose  */
813
814   /* open the vldb database file */
815   fd = open(dbfile, O_RDONLY, 0);
816   if (fd < 0) {
817      printf("can't open file '%s'. error = %d\n", dbfile, errno);
818      return;
819   }
820
821   /* read the ubik header and the vldb database header*/
822   readUbikHeader();
823   readheader(&header);
824   if (header.vital_header.vldbversion < 3) {
825      printf("does not support vldb with version less than 3\n");
826      return;
827   }
828
829   maxentries = (header.vital_header.eofPtr / sizeof(vlentry)) + 1;
830   record = (struct er *)malloc(maxentries * sizeof(struct er));
831   memset((char *)record, 0, (maxentries * sizeof(struct er)));
832   memset((char *)serveraddrs, 0, sizeof(serveraddrs));
833
834   /* Will fill in the record array of entries it found */
835   ReadAllEntries(&header);
836   listentries = 0;                /* Listed all the entries */
837
838   /* Check the multihomed blocks for valid entries as well as
839    * the IpMappedAddrs array in the header for valid entries.
840    */
841   CheckIpAddrs(&header);
842
843   /* Follow the hash tables */
844   FollowNameHash(&header);
845   FollowIdHash(&header);
846
847   /* Follow the chain of free entries */
848   FollowFreeChain(&header);
849
850   /* Now check the record we have been keeping for inconsistancies
851    * For valid vlentries, also check that the server we point to is 
852    * valid (the serveraddrs array).
853    */
854   if (verbose) 
855      printf("Verify each volume entry\n");
856   for (i=0; i<maxentries; i++) {
857      if (record[i].type == 0) continue;
858
859      /* If a vlentry, verify that its name is valid, its name and ids are
860       * on the hash chains, and its server numbers are good.
861       */
862      if (record[i].type & VL) {
863         readentry(record[i].addr, &vlentry, &type);
864
865         if (InvalidVolname(vlentry.name))
866            printf("Volume '%s' at addr has an invalid name\n", vlentry.name, record[i].addr);
867
868         if (!(record[i].type & NH)) 
869            printf("Volume '%s' not found in name hash\n", vlentry.name);
870
871         if (vlentry.volumeId[0] && !(record[i].type & RWH))
872            printf("Volume '%s' id %u not found in RW hash chain\n",
873                   vlentry.name, vlentry.volumeId[0]);
874
875         if (vlentry.volumeId[1] && !(record[i].type & ROH))
876            printf("Volume '%s' id %u not found in RO hash chain\n",
877                   vlentry.name, vlentry.volumeId[1]);
878
879         if (vlentry.volumeId[2] && !(record[i].type & BKH))
880            printf("Volume '%s' id %u not found in BK hash chain\n",
881                   vlentry.name, vlentry.volumeId[2]);
882
883         for (j=0; j<NMAXNSERVERS; j++) {
884            if ( (vlentry.serverNumber[j] != 255) && 
885                 (serveraddrs[vlentry.serverNumber[j]] == 0) ) {
886               printf("Volume '%s', index %d points to empty server entry %d\n",
887                      vlentry.name, j, vlentry.serverNumber[j]);
888            }
889         }
890
891         if (record[i].type & 0xffffff00)
892            printf("Volume '%s' id %u also found on other chains (0x%x)\n",
893                   vlentry.name, vlentry.volumeId[0], record[i].type);
894
895      /* A free entry */
896      } else if (record[i].type & FR) {
897         if (!(record[i].type & FRC))
898            printf("Free vlentry at %u not on free chain\n", record[i].addr);
899         
900         if (record[i].type & 0xfffffdf0)
901            printf("Free vlentry at %u also found on other chains (0x%x)\n",
902                   record[i].addr, record[i].type);
903
904      /* A multihomed entry */
905      } else if (record[i].type & MH) {
906         if (!(record[i].type & MHC))
907            printf("Multihomed block at %u is orphaned\n", record[i].addr);
908         
909         if (record[i].type & 0xfffffef0)
910            printf("Multihomed block at %u also found on other chains (0x%x)\n",
911                   record[i].addr, record[i].type);
912
913      } else {
914         printf("Unknown entry type at %u (0x%x)\n", record[i].addr, record[i].type);
915      }
916   }
917 }
918
919 main(argc, argv)
920   int  argc;
921   char **argv;
922 {
923   struct cmd_syndesc *ts;
924
925   setlinebuf(stdout);
926
927   ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "vldb check");
928   cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "vldb_file");
929   cmd_AddParm(ts, "-uheader",  CMD_FLAG,   CMD_OPTIONAL, "Display UBIK header");
930   cmd_AddParm(ts, "-vheader",  CMD_FLAG,   CMD_OPTIONAL, "Display VLDB header");
931   cmd_AddParm(ts, "-servers",  CMD_FLAG,   CMD_OPTIONAL, "Display server list");
932   cmd_AddParm(ts, "-entries",  CMD_FLAG,   CMD_OPTIONAL, "Display entries");
933   cmd_AddParm(ts, "-verbose",  CMD_FLAG,   CMD_OPTIONAL, "verbose");
934
935   return cmd_Dispatch(argc, argv);
936 }