include-afsconfig-before-param-h-20010712
[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    int i;
139    char *vchar;
140
141    hash = 0;
142    for (vchar=volname+strlen(volname)-1; vchar >= volname; vchar--)
143       hash = (hash*63) + (*((unsigned char *)vchar) - 63);
144    return(hash % HASHSIZE);
145 }
146
147 afs_int32 IdHash(volid)
148    afs_int32 volid;
149 {
150    return((abs(volid)) % HASHSIZE);
151 }
152
153 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
154 int InvalidVolname(volname)
155   char *volname;
156 {
157   char *map;
158   int slen;
159
160   map = LEGALCHARS;
161   slen = strlen(volname);
162   if (slen >= VL_MAXNAMELEN) return 1;
163   return (slen != strspn(volname, map));
164 }
165
166 readheader(headerp)
167   struct vlheader *headerp;
168 {
169   int i,j;
170
171   vldbread(0, headerp, sizeof(*headerp));
172
173   headerp->vital_header.vldbversion = ntohl(headerp->vital_header.vldbversion);
174   headerp->vital_header.headersize  = ntohl(headerp->vital_header.headersize);
175   headerp->vital_header.freePtr     = ntohl(headerp->vital_header.freePtr);
176   headerp->vital_header.eofPtr      = ntohl(headerp->vital_header.eofPtr);
177   headerp->vital_header.allocs      = ntohl(headerp->vital_header.allocs);
178   headerp->vital_header.frees       = ntohl(headerp->vital_header.frees);
179   headerp->vital_header.MaxVolumeId = ntohl(headerp->vital_header.MaxVolumeId);
180   headerp->vital_header.totalEntries[0] = ntohl(headerp->vital_header.totalEntries[0]);
181   for (i=0; i<MAXTYPES; i++)
182      headerp->vital_header.totalEntries[i] = ntohl(headerp->vital_header.totalEntries[1]);
183
184   headerp->SIT = ntohl(headerp->SIT);
185   for (i=0; i<MAXSERVERID; i++)
186      headerp->IpMappedAddr[i] = ntohl(headerp->IpMappedAddr[i]);
187   for (i=0; i<HASHSIZE; i++)
188      headerp->VolnameHash[i] = ntohl(headerp->VolnameHash[i]);
189   for (i=0; i<MAXTYPES; i++) 
190      for (j=0; j<HASHSIZE; j++) 
191         headerp->VolidHash[i][j] = ntohl(headerp->VolidHash[i][j]);
192
193   if (listheader) {
194      printf("vldb header\n");
195      printf("   vldbversion      = %u\n", headerp->vital_header.vldbversion);
196      printf("   headersize       = %u [actual=%u]\n",
197             headerp->vital_header.headersize, sizeof(*headerp));
198      printf("   freePtr          = 0x%x\n", headerp->vital_header.freePtr);
199      printf("   eofPtr           = %u\n", headerp->vital_header.eofPtr);
200      printf("   allocblock calls = %10u\n", headerp->vital_header.allocs);
201      printf("   freeblock  calls = %10u\n", headerp->vital_header.frees);
202      printf("   MaxVolumeId      = %u\n", headerp->vital_header.MaxVolumeId);
203      printf("   rw vol entries   = %u\n", headerp->vital_header.totalEntries[0]);
204      printf("   ro vol entries   = %u\n", headerp->vital_header.totalEntries[1]);
205      printf("   bk vol entries   = %u\n", headerp->vital_header.totalEntries[2]);
206      printf("   multihome info   = 0x%x (%u)\n", headerp->SIT, headerp->SIT);
207      printf("   server ip addr   table: size = %d entries\n", MAXSERVERID+1);
208      printf("   volume name hash table: size = %d buckets\n", HASHSIZE);
209      printf("   volume id   hash table: %d tables with %d buckets each\n",
210             MAXTYPES, HASHSIZE);
211   }
212
213   /* Check the header size */
214   if (headerp->vital_header.headersize != sizeof(*headerp))
215      printf("Header reports its size as %d (should be %d)\n",
216             headerp->vital_header.headersize, sizeof(*headerp));
217 }
218
219 readMH(addr, mhblockP)
220   afs_int32 addr;
221   struct extentaddr *mhblockP;
222 {
223   int i, j;
224   struct extentaddr *e;
225
226   vldbread(addr, mhblockP, VL_ADDREXTBLK_SIZE);
227
228   mhblockP->ex_count = ntohl(mhblockP->ex_count);
229   mhblockP->ex_flags = ntohl(mhblockP->ex_flags);
230   for (i=0; i<VL_MAX_ADDREXTBLKS; i++)
231      mhblockP->ex_contaddrs[i] = ntohl(mhblockP->ex_contaddrs[i]);
232
233   for (i=1; i<VL_MHSRV_PERBLK; i++) {
234      e = &(mhblockP[i]);
235
236      /* won't convert hostuuid */
237      e->ex_uniquifier = ntohl(e->ex_uniquifier);
238      for (j=0; j<VL_MAXIPADDRS_PERMH; j++)
239         e->ex_addrs[j] = ntohl(e->ex_addrs[j]);
240   }
241 }     
242
243 readentry(addr, vlentryp, type)
244   afs_int32 addr;
245   struct nvlentry *vlentryp;
246   afs_int32 *type;
247 {
248   int i;
249
250   vldbread(addr, vlentryp, sizeof(*vlentryp));
251
252   for (i=0; i<MAXTYPES; i++)
253      vlentryp->volumeId[i]   = ntohl(vlentryp->volumeId[i]);
254   vlentryp->flags            = ntohl(vlentryp->flags);
255   vlentryp->LockAfsId        = ntohl(vlentryp->LockAfsId);
256   vlentryp->LockTimestamp    = ntohl(vlentryp->LockTimestamp);
257   vlentryp->cloneId          = ntohl(vlentryp->cloneId);
258   for (i=0; i<MAXTYPES; i++)    
259      vlentryp->nextIdHash[i] = ntohl(vlentryp->nextIdHash[i]);
260   vlentryp->nextNameHash     = ntohl(vlentryp->nextNameHash);
261   for (i=0; i<NMAXNSERVERS; i++) {
262      vlentryp->serverNumber[i]    = ntohl(vlentryp->serverNumber[i]);
263      vlentryp->serverPartition[i] = ntohl(vlentryp->serverPartition[i]);
264      vlentryp->serverFlags[i]     = ntohl(vlentryp->serverFlags[i]);
265   }
266
267   if (vlentryp->flags == VLCONTBLOCK) {
268      *type = MH;
269   } else if (vlentryp->flags == VLFREE) {
270      *type = FR;
271   } else {
272      *type = VL;
273   }
274
275   if (listentries) {
276      printf("address %u: ", addr);
277      if (vlentryp->flags == VLCONTBLOCK) {
278         printf("mh extension block\n");
279      } else if (vlentryp->flags == VLFREE) {
280         printf("free vlentry\n");
281      } else {
282         printf("vlentry %s\n", vlentryp->name);
283         printf("   rw id = %u ; ro id = %u ; bk id = %u\n",
284                vlentryp->volumeId[0], vlentryp->volumeId[1], vlentryp->volumeId[2]);
285         printf("   flags         =");
286            if (vlentryp->flags & VLF_RWEXISTS) printf(" rw");
287            if (vlentryp->flags & VLF_ROEXISTS) printf(" ro");
288            if (vlentryp->flags & VLF_BACKEXISTS) printf(" bk");
289            if (vlentryp->flags & 0xffff8fff) 
290               printf(" errorflag(0x%x)", vlentryp->flags);
291            printf("\n");
292         printf("   LockAfsId     = %d\n", vlentryp->LockAfsId);
293         printf("   LockTimestamp = %d\n", vlentryp->LockTimestamp);
294         printf("   cloneId       = %u\n", vlentryp->cloneId);
295         printf("   next hash for rw = %u ; ro = %u ; bk = %u ; name = %u\n",
296                vlentryp->nextIdHash[0], vlentryp->nextIdHash[1], 
297                vlentryp->nextIdHash[2], vlentryp->nextNameHash);
298         for (i=0; i<NMAXNSERVERS; i++) {
299            if (vlentryp->serverNumber[i] != 255) {
300               printf("   server %d ; partition %d ; flags =",
301                      vlentryp->serverNumber[i], vlentryp->serverPartition[i]);
302               if (vlentryp->serverFlags[i] & VLSF_RWVOL) printf(" rw");
303               if (vlentryp->serverFlags[i] & VLSF_ROVOL) printf(" ro");
304               if (vlentryp->serverFlags[i] & VLSF_BACKVOL) printf(" bk");
305               if (vlentryp->serverFlags[i] & VLSF_NEWREPSITE) printf(" newro");
306               printf("\n");
307            }
308         }
309      }
310   }
311 }
312
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 ReadAllEntries(header)
370   struct vlheader *header;
371 {
372   afs_int32 type, rindex, i, j, e;
373   int freecount=0, mhcount=0, vlcount=0;
374   int rwcount=0, rocount=0, bkcount=0;
375   struct nvlentry vlentry;
376   afs_uint32 addr, entrysize, maxvolid=0;
377
378   if (verbose)
379      printf("Read each entry in the database\n");
380   for (addr = header->vital_header.headersize;
381        addr < header->vital_header.eofPtr; addr += entrysize) {
382
383      /* Remember the highest volume id */
384      readentry(addr, &vlentry, &type);
385      if (type == VL) {
386         if (!(vlentry.flags & VLF_RWEXISTS))
387            printf("WARNING: VLDB entry '%s' has no RW volume\n", vlentry.name);
388
389         for (i=0; i<MAXTYPES; i++)
390            if (maxvolid < vlentry.volumeId[i]) maxvolid = vlentry.volumeId[i];
391
392         e = 1;
393         for (j=0; j<NMAXNSERVERS; j++) {
394            if (vlentry.serverNumber[j] == 255) continue;
395            if (vlentry.serverFlags[j] & (VLSF_ROVOL|VLSF_NEWREPSITE)) {
396               rocount++;
397               continue;
398            }
399            if (vlentry.serverFlags[j] & VLSF_RWVOL) {
400               rwcount++;
401               if (vlentry.flags & VLF_BACKEXISTS) bkcount++;
402               continue;
403            }
404            if (e) {
405               printf("VLDB entry '%s' contains an unknown RW/RO index serverFlag\n", 
406                      vlentry.name);
407               e = 0;
408            }
409            printf("   index %d : serverNumber %d : serverPartition %d : serverFlag %d\n", 
410                   j, vlentry.serverNumber[j], vlentry.serverPartition[j], vlentry.serverFlags[j]);
411         }
412      }
413
414      rindex = addr/sizeof(vlentry);
415      if (record[rindex].type) {
416         printf("INTERNAL ERROR: record holder %d already in use\n", rindex);
417         return;
418      }
419      record[rindex].addr = addr;
420      record[rindex].type = type;
421
422      /* Determine entrysize and keep count */
423      if (type == VL) {
424         entrysize = sizeof(vlentry);
425         vlcount++;
426      } else if (type == FR) {
427         entrysize = sizeof(vlentry);
428         freecount++;
429      } else if (type == MH) {
430         entrysize = VL_ADDREXTBLK_SIZE;
431         mhcount++;
432      } else {
433         printf("Unknown entry at %u\n", addr);
434      }
435   }
436   if (verbose) {
437      printf("Found %d entries, %d free entries, %d multihomed blocks\n",
438             vlcount, freecount, mhcount);
439      printf("Found %d RW volumes, %d BK volumes, %d RO volumes\n",
440             rwcount, bkcount, rocount);
441   }
442
443   /* Check the maxmimum volume id in the header */
444   if (maxvolid != header->vital_header.MaxVolumeId-1)
445      printf("Header's maximum volume id is %u and largest id found in VLDB is %u\n",
446             header->vital_header.MaxVolumeId, maxvolid);
447 }
448
449
450 /*
451  * Follow each Name hash bucket marking it as read in the record array.
452  * Record we found it in the name hash within the record array.
453  * Check that the name is hashed correctly.
454  */
455 FollowNameHash(header)
456   struct vlheader *header;
457 {
458   int count=0, longest=0, shortest=-1, chainlength;
459   struct nvlentry vlentry;
460   afs_uint32 addr;
461   afs_int32 i, type, rindex;
462
463   /* Now follow the Name Hash Table */
464   if (verbose)
465      printf("Check Volume Name Hash\n");
466   for (i=0; i<HASHSIZE; i++) {
467      chainlength = 0;
468      for (addr = header->VolnameHash[i]; addr; addr=vlentry.nextNameHash) {
469         readentry(addr, &vlentry, &type);
470         if (type != VL) {
471            printf("Name Hash %d: Bad entry at %u: Not a valid vlentry\n", i, addr);
472            continue;
473         }
474
475         rindex = addr/sizeof(vlentry);
476
477         if (record[rindex].addr != addr && record[rindex].addr) {
478            printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
479                   record[rindex].addr, addr, rindex);
480         }
481         if (record[rindex].type & NH) {
482            printf("Name Hash %d: Bad entry '%s': Already in the name hash\n",
483                   i, vlentry.name);
484            break;
485         }
486         record[rindex].type |= NH;
487
488         chainlength++;
489         count++;
490
491         /* Hash the name and check if in correct hash table */
492         if (NameHash(vlentry.name) != i) {
493            printf("Name Hash %d: Bad entry '%s': Incorrect name hash chain (should be in %d)\n",
494                   i, vlentry.name, NameHash(vlentry.name));
495         }
496      }
497      if (chainlength > longest) longest = chainlength;
498      if ((shortest == -1) || (chainlength < shortest)) shortest = chainlength;
499   }
500   if (verbose) {
501      printf("%d entries in name hash, longest is %d, shortest is %d, average length is %f\n",
502             count, longest, shortest, ((float)count/(float)HASHSIZE));
503   }
504 }
505
506 /*
507  * Follow the ID hash chains for the RW, RO, and BK hash tables.
508  * Record we found it in the id hash within the record array.
509  * Check that the ID is hashed correctly.
510  */
511 FollowIdHash(header)
512   struct vlheader *header;
513 {
514   int count=0, longest=0, shortest=-1, chainlength;
515   struct nvlentry vlentry;
516   afs_uint32 addr;
517   afs_int32 i, j, hash, type, rindex;
518
519   /* Now follow the RW, RO, and BK Hash Tables */
520   if (verbose)
521      printf("Check RW, RO, and BK id Hashes\n");
522   for (i=0; i<MAXTYPES; i++) {
523      hash = ((i==0)?RWH : ((i==1)?ROH : BKH));
524      count = longest = 0; shortest = -1;
525
526      for (j=0; j<HASHSIZE; j++) {
527         chainlength = 0;
528         for (addr=header->VolidHash[i][j]; addr; addr=vlentry.nextIdHash[i]) {
529            readentry(addr, &vlentry, &type);
530            if (type != VL) {
531               printf("%s Id Hash %d: Bad entry at %u: Not a valid vlentry\n",
532                      vtype(i), j, addr);
533               continue;
534            }
535
536            rindex = addr/sizeof(vlentry);
537            if (record[rindex].addr != addr && record[rindex].addr) {
538               printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
539                      record[rindex].addr, addr, rindex);
540            }
541            if (record[rindex].type & hash) {
542               printf("%s Id Hash %d: Bad entry '%s': Already in the the hash table\n",
543                      vtype(i), j, vlentry.name);
544               break;
545            } 
546            record[rindex].type |= hash;
547
548            chainlength++;
549            count++;
550
551            /* Hash the id and check if in correct hash table */
552            if (IdHash(vlentry.volumeId[i]) != j) {
553               printf("%s Id Hash %d: Bad entry '%s': Incorrect Id hash chain (should be in %d)\n",
554                      vtype(i), j, vlentry.name, IdHash(vlentry.volumeId[i]));
555            }
556         }
557
558         if (chainlength > longest) longest = chainlength;
559         if ((shortest == -1) || (chainlength < shortest)) shortest = chainlength;
560      }
561      if (verbose) {
562         printf("%d entries in %s hash, longest is %d, shortest is %d, average length is %f\n",
563                count, vtype(i), longest, shortest, ((float)count/(float)HASHSIZE));
564      }
565   }
566 }
567
568 /*
569  * Follow the free chain.
570  * Record we found it in the free chain within the record array.
571  */
572 FollowFreeChain(header)
573   struct vlheader *header;
574 {
575   int count=0;
576   struct nvlentry vlentry;
577   afs_uint32 addr;
578   afs_int32 i, type, rindex;
579
580   /* Now follow the Free Chain */
581   if (verbose)
582      printf("Check Volume Free Chain\n");
583   for (addr=header->vital_header.freePtr; addr; addr=vlentry.nextIdHash[0]) {
584      readentry(addr, &vlentry, &type);
585      if (type != FR) {
586         printf("Free Chain %d: Bad entry at %u: Not a valid free vlentry (0x%x)\n",
587                i, addr, type);
588         continue;
589      }
590
591      rindex = addr/sizeof(vlentry);
592      if (record[rindex].addr != addr && record[rindex].addr) {
593         printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
594                record[rindex].addr, addr, rindex);
595      }
596      if (record[rindex].type & FRC) {
597         printf("Free Chain: Bad entry at %u: Already in the free chain\n", addr);
598         break;
599      }
600      record[rindex].type |= FRC;
601
602      count++;
603   }
604   if (verbose)
605      printf("%d entries on free chain\n", count);
606 }
607
608 /*
609  * Read each multihomed block and mark it as found in the record.
610  * Read each entry in each multihomed block and mark the serveraddrs
611  * array with the number of ip addresses found for this entry.
612  * 
613  * Then read the IpMappedAddr array in the header.
614  * Verify that multihomed entries base and index are valid and points to
615  * a good multhomed entry.
616  * Mark the serveraddrs array with 1 ip address for regular entries.
617  * 
618  * By the end, the severaddrs array will have a 0 if the entry has no 
619  * IP addresses in it or the count of the number of IP addresses.
620  *
621  * The code does not verify if there are duplicate IP addresses in the 
622  * list. The vlserver does this when a fileserver registeres itself.
623  */
624 CheckIpAddrs(header)
625   struct vlheader *header;
626 {
627   int mhblocks=0;
628   struct nvlentry vlentry;
629   afs_uint32 addr;
630   afs_int32 i, j, m, rindex;
631   afs_int32 mhentries, regentries;
632   afs_int32 caddrs[VL_MAX_ADDREXTBLKS];
633   char mhblock[VL_ADDREXTBLK_SIZE];
634   struct extentaddr *MHblock = (struct extentaddr *)mhblock;
635   struct extentaddr *e;
636   int ipindex, ipaddrs;
637   afsUUID nulluuid;
638
639   bzero(&nulluuid, sizeof(nulluuid));
640
641   if (verbose)
642      printf("Check Multihomed blocks\n");
643
644   if (header->SIT) {
645      /* Read the first MH block and from it, gather the 
646       * addresses of all the mh blocks.
647       */
648      readMH(header->SIT, MHblock);
649      if (MHblock->ex_flags != VLCONTBLOCK) {
650         printf("Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
651                header->SIT);
652      }
653
654      for (i=0; i<VL_MAX_ADDREXTBLKS; i++) {
655         caddrs[i] = MHblock->ex_contaddrs[i];
656      }
657
658      if (header->SIT != caddrs[0]) {
659         printf("MH block does not point to self %u in header, %u in block\n",
660                header->SIT, caddrs[0]);
661      }
662      
663      /* Now read each MH block and record it in the record array */
664      for (i=0; i<VL_MAX_ADDREXTBLKS; i++) {
665         if (!caddrs[i]) continue;
666
667         readMH(caddrs[i], MHblock);
668         if (MHblock->ex_flags != VLCONTBLOCK) {
669            printf("Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
670                   header->SIT);
671         }
672
673         rindex = caddrs[i]/sizeof(vlentry);
674         if (record[rindex].addr != caddrs[i] && record[rindex].addr) {
675            printf("INTERNAL ERROR: addresses %u and %u use same record slot %d\n",
676                   record[rindex].addr, caddrs[i], rindex);
677         }
678         if (record[rindex].type & FRC) {
679            printf("MH Blocks Chain %d: Bad entry at %u: Already a MH block\n", i, addr);
680            break;
681         }
682         record[rindex].type |= MHC;
683         
684         mhblocks++;
685
686         /* Read each entry in a multihomed block. 
687          * Find the pointer to the entry in the IpMappedAddr array and
688          * verify that the entry is good (has IP addresses in it).
689          */
690         mhentries = 0;
691         for (j=1; j<VL_MHSRV_PERBLK; j++) {
692            e = (struct extentaddr *)&(MHblock[j]);
693
694            /* Search the IpMappedAddr array for the reference to this entry */
695            for (ipindex=0; ipindex<MAXSERVERID; ipindex++) {
696               if (  ((header->IpMappedAddr[ipindex] & 0xff000000) == 0xff000000) &&
697                    (((header->IpMappedAddr[ipindex] & 0x00ff0000)>>16) == i)     &&
698                     ((header->IpMappedAddr[ipindex] & 0x0000ffff)      == j) ) {
699                  break;
700               }
701            }
702            if (ipindex >= MAXSERVERID) ipindex = -1;
703            else serveraddrs[ipindex] = -1;
704
705            if (memcmp(&e->ex_hostuuid, &nulluuid, sizeof(afsUUID)) == 0) {
706               if (ipindex != -1) {
707                  printf("Server Addrs index %d references null MH block %d, index %d\n", i, j);
708                  serveraddrs[ipindex] = 0;     /* avoids printing 2nd error below */
709               }
710               continue;
711            }
712
713            /* Step through each ip address and count the good addresses */
714            ipaddrs = 0;
715            for (m=0; m<VL_MAXIPADDRS_PERMH; m++) {
716              if (e->ex_addrs[m]) ipaddrs++;
717            }
718
719            /* If we found any good ip addresses, mark it in the serveraddrs record */
720            if (ipaddrs) {
721               mhentries++;
722               if (ipindex == -1) {
723                  printf("MH block %d, index %d: Not referenced by server addrs\n", i, j);
724               } else {
725                  serveraddrs[ipindex] = ipaddrs;       /* It is good */
726               }
727            }
728
729            if (listservers && ipaddrs) {
730               printf("MH block %d, index %d:", i, j);
731               for (m=0; m<VL_MAXIPADDRS_PERMH; m++) {
732                  if (!e->ex_addrs[m]) continue;
733                  printf(" %d.%d.%d.%d",
734                         (e->ex_addrs[m]&0xff000000)>>24,
735                         (e->ex_addrs[m]&0x00ff0000)>>16,
736                         (e->ex_addrs[m]&0x0000ff00)>>8,
737                         (e->ex_addrs[m]&0x000000ff));
738               }
739               printf("\n");
740            }
741         }
742 /*
743  *      if (mhentries != MHblock->ex_count) {
744  *         printf("MH blocks says it has %d entries (found %d)\n",
745  *                MHblock->ex_count, mhentries);
746  *      }
747  */
748      }
749   }
750   if (verbose)
751      printf("%d multihomed blocks\n", mhblocks);
752
753   /* Check the server addresses */
754   if (verbose)
755      printf("Check server addresses\n");
756   mhentries = regentries = 0;
757   for (i=0; i<=MAXSERVERID; i++) {
758      if (header->IpMappedAddr[i]) {
759         if ((header->IpMappedAddr[i] & 0xff000000) == 0xff000000) {
760            mhentries++;
761            if (((header->IpMappedAddr[i] & 0x00ff0000)>>16) > VL_MAX_ADDREXTBLKS)
762               printf("IP Addr for entry %d: Multihome block is bad (%d)\n",
763                      i, ((header->IpMappedAddr[i] & 0x00ff0000)>>16));
764            if ( ((header->IpMappedAddr[i] & 0x0000ffff) > VL_MHSRV_PERBLK) ||
765                 ((header->IpMappedAddr[i] & 0x0000ffff) < 1) )
766               printf("IP Addr for entry %d: Multihome index is bad (%d)\n",
767                      i, (header->IpMappedAddr[i] & 0x0000ffff));
768            if (serveraddrs[i] == -1) {
769               printf("warning: IP Addr for entry %d: Multihome entry has no ip addresses\n", i);
770               serveraddrs[i] = 0;
771            }
772            if (listservers) {
773               printf("   Server ip addr %d = MH block %d, index %d\n", i,
774                      (header->IpMappedAddr[i] & 0x00ff0000)>>16,
775                      (header->IpMappedAddr[i] & 0x0000ffff));
776            }
777         } else {
778            regentries++;
779            serveraddrs[i] = 1;       /* It is good */
780            if (listservers) {
781               printf("   Server ip addr %d = %d.%d.%d.%d\n", i, 
782                      (header->IpMappedAddr[i]&0xff000000)>>24,
783                      (header->IpMappedAddr[i]&0x00ff0000)>>16,
784                      (header->IpMappedAddr[i]&0x0000ff00)>>8,
785                      (header->IpMappedAddr[i]&0x000000ff));
786            }
787         }
788      }
789   }
790   if (verbose) {
791      printf("%d simple entries, %d multihomed entries, Total = %d\n",
792             regentries, mhentries, mhentries+regentries);
793   }
794
795 }
796
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   bzero((char *)record, (maxentries * sizeof(struct er)));
832   bzero((char *)serveraddrs, 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   struct cmd_item    *ti;
925
926   setlinebuf(stdout);
927
928   ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "vldb check");
929   cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "vldb_file");
930   cmd_AddParm(ts, "-uheader",  CMD_FLAG,   CMD_OPTIONAL, "Display UBIK header");
931   cmd_AddParm(ts, "-vheader",  CMD_FLAG,   CMD_OPTIONAL, "Display VLDB header");
932   cmd_AddParm(ts, "-servers",  CMD_FLAG,   CMD_OPTIONAL, "Display server list");
933   cmd_AddParm(ts, "-entries",  CMD_FLAG,   CMD_OPTIONAL, "Display entries");
934   cmd_AddParm(ts, "-verbose",  CMD_FLAG,   CMD_OPTIONAL, "verbose");
935
936   return cmd_Dispatch(argc, argv);
937 }