Rewrite vldb_check -fix
[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 #define REFRW 0x1000            /* linked from something (RW) */
25 #define REFRO 0x2000            /* linked from something (RO) */
26 #define REFBK 0x4000            /* linked from something (BK) */
27 #define REFN  0x8000            /* linked from something (name) */
28
29 #define MULTRW 0x10000         /* multiply-chained (RW) */
30 #define MULTRO 0x20000         /* multiply-chained (RO) */
31 #define MULTBK 0x40000         /* multiply-chained (BK) */
32 #define MULTN  0x80000         /* multiply-chained (name) */
33
34 #define MISRWH 0x100000          /* mischained (RW) */
35 #define MISROH 0x200000          /* mischained (RO) */
36 #define MISBKH 0x400000          /* mischained (BK) */
37 #define MISNH  0x800000          /* mischained (name) */
38
39 #define VLDB_CHECK_NO_VLDB_CHECK_ERROR 0
40 #define VLDB_CHECK_WARNING  1
41 #define VLDB_CHECK_ERROR    2
42 #define VLDB_CHECK_FATAL    4
43 #define vldbread(x,y,z) vldbio(x,y,z,0)
44 #define vldbwrite(x,y,z) vldbio(x,y,z,1)
45
46 #include <afsconfig.h>
47 #include <afs/param.h>
48
49
50 #include <stdlib.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <fcntl.h>
54 #include <errno.h>
55 #include <string.h>
56 #ifdef AFS_NT40_ENV
57 #include <winsock2.h>
58 #include <WINNT/afsevent.h>
59 #include <io.h>
60 #else
61 #include <sys/socket.h>
62 #include <netdb.h>
63 #include <netinet/in.h>
64 #endif
65
66 #include "vlserver.h"
67 #include "vldbint.h"
68 #include <ubik.h>
69 #include <afs/afsutil.h>
70 #include <afs/cmd.h>
71
72 #define ADDR(x) (x/sizeof(struct nvlentry))
73
74 int fd;
75 int listentries, listservers, listheader, listuheader, verbose, quiet;
76
77 int fix = 0;
78 int passes = 0;
79 /* if quiet, don't send anything to stdout */
80 int quiet = 0; 
81 /*  error level. 0 = no error, 1 = warning, 2 = error, 4 = fatal */
82 int error_level  = 0; 
83
84 struct er {
85     long addr;
86     int type;
87 } *record;
88 afs_int32 maxentries;
89 int serveraddrs[MAXSERVERID + 2];
90
91 /*  Used to control what goes to stdout based on quiet flag */
92 void 
93 quiet_println(const char *fmt,...) {
94     va_list args;                                             
95     if (!quiet) {
96         va_start(args, fmt);                                      
97         vfprintf(stdout, fmt, args);                              
98         va_end(args);                                             
99     }
100 }
101
102 /*  Used to set the error level and ship messages to stderr */
103 void                                                   
104 log_error(int eval, const char *fmt, ...)                          
105 {                                                             
106     va_list args;                                             
107     if (error_level < eval) error_level  = eval ;  /*  bump up the severity */
108     va_start(args, fmt);                                      
109     vfprintf(stderr, fmt, args);                              
110     va_end(args);                                             
111
112     if (error_level  == VLDB_CHECK_FATAL) exit(VLDB_CHECK_FATAL);
113 }  
114
115
116 #if 0
117 int
118 writeUbikHeader()
119 {
120     /* Bump the version number?? We could cheat and push a new db... */
121 }
122 #endif
123
124 #define HDRSIZE 64
125 int
126 readUbikHeader(void)
127 {
128     int offset, r;
129     struct ubik_hdr uheader;
130
131     offset = lseek(fd, 0, 0);
132     if (offset != 0) {
133         log_error(VLDB_CHECK_FATAL,"error: lseek to 0 failed: %d %d\n", offset, errno);
134         return (VLDB_CHECK_FATAL);
135     }
136
137     /* now read the info */
138     r = read(fd, &uheader, sizeof(uheader));
139     if (r != sizeof(uheader)) {
140         log_error(VLDB_CHECK_FATAL,"error: read of %lu bytes failed: %d %d\n", sizeof(uheader), r,
141                errno);
142         return (VLDB_CHECK_FATAL);
143     }
144
145     uheader.magic = ntohl(uheader.magic);
146     uheader.size = ntohl(uheader.size);
147     uheader.version.epoch = ntohl(uheader.version.epoch);
148     uheader.version.counter = ntohl(uheader.version.counter);
149
150     if (listuheader) {
151         quiet_println("Ubik Header\n");
152         quiet_println("   Magic           = 0x%x\n", uheader.magic);
153         quiet_println("   Size            = %u\n", uheader.size);
154         quiet_println("   Version.epoch   = %u\n", uheader.version.epoch);
155         quiet_println("   Version.counter = %u\n", uheader.version.counter);
156     }
157
158     if (uheader.size != HDRSIZE)
159         log_error(VLDB_CHECK_WARNING,"VLDB_CHECK_WARNING: Ubik header size is %u (should be %u)\n", uheader.size,
160                HDRSIZE);
161     if (uheader.magic != UBIK_MAGIC)
162         log_error(VLDB_CHECK_ERROR,"Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic,
163                UBIK_MAGIC);
164
165     return (0);
166 }
167
168 int
169 vldbio(int position, void *buffer, int size, int rdwr)
170 {
171     int offset, r, p;
172
173     /* seek to the correct spot. skip ubik stuff */
174     p = position + HDRSIZE;
175     offset = lseek(fd, p, 0);
176     if (offset != p) {
177         log_error(VLDB_CHECK_FATAL,"error: lseek to %d failed: %d %d\n", p, offset, errno);
178         return (-1);
179     }
180
181     if (rdwr == 1) 
182         r = write(fd, buffer, size);
183     else 
184         r = read(fd, buffer, size);
185
186     if (r != size) {
187         log_error(VLDB_CHECK_FATAL,"error: %s of %d bytes failed: %d %d\n", rdwr==1?"write":"read",
188                size, r, errno);
189         return (-1);
190     }
191     return (0);
192 }
193
194 char *
195 vtype(int type)
196 {
197     static char Type[3];
198
199     if (type == 0)
200         strcpy(Type, "rw");
201     else if (type == 1)
202         strcpy(Type, "ro");
203     else if (type == 2)
204         strcpy(Type, "bk");
205     else
206         strcpy(Type, "??");
207     return (Type);
208 }
209
210 afs_int32
211 NameHash(char *volname)
212 {
213     unsigned int hash;
214     char *vchar;
215
216     hash = 0;
217     for (vchar = volname + strlen(volname) - 1; vchar >= volname; vchar--)
218         hash = (hash * 63) + (*((unsigned char *)vchar) - 63);
219     return (hash % HASHSIZE);
220 }
221
222 afs_int32
223 IdHash(afs_uint32 volid)
224 {
225     return ((abs(volid)) % HASHSIZE);
226 }
227
228 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
229 int
230 InvalidVolname(char *volname)
231 {
232     char *map;
233     size_t slen;
234
235     map = LEGALCHARS;
236     slen = strlen(volname);
237     if (slen >= VL_MAXNAMELEN)
238         return 1;
239     return (slen != strspn(volname, map));
240 }
241
242 int
243 validVolumeAddr(afs_uint32 fileOffset)
244 {
245     if (ADDR(fileOffset) >= maxentries) {
246         /* Are we in range */
247         return 0;
248     }
249     /*
250      * We cannot test whether the offset is aligned
251      * since the vl entries are not in a regular array
252      */
253     return 1;
254 }
255
256 void
257 readheader(struct vlheader *headerp)
258 {
259     int i, j;
260
261     vldbread(0, (char *)headerp, sizeof(*headerp));
262
263     headerp->vital_header.vldbversion =
264         ntohl(headerp->vital_header.vldbversion);
265     headerp->vital_header.headersize =
266         ntohl(headerp->vital_header.headersize);
267     headerp->vital_header.freePtr = ntohl(headerp->vital_header.freePtr);
268     headerp->vital_header.eofPtr = ntohl(headerp->vital_header.eofPtr);
269     headerp->vital_header.allocs = ntohl(headerp->vital_header.allocs);
270     headerp->vital_header.frees = ntohl(headerp->vital_header.frees);
271     headerp->vital_header.MaxVolumeId =
272         ntohl(headerp->vital_header.MaxVolumeId);
273     headerp->vital_header.totalEntries[0] =
274         ntohl(headerp->vital_header.totalEntries[0]);
275     for (i = 0; i < MAXTYPES; i++)
276         headerp->vital_header.totalEntries[i] =
277             ntohl(headerp->vital_header.totalEntries[1]);
278
279     headerp->SIT = ntohl(headerp->SIT);
280     for (i = 0; i < MAXSERVERID; i++)
281         headerp->IpMappedAddr[i] = ntohl(headerp->IpMappedAddr[i]);
282     for (i = 0; i < HASHSIZE; i++)
283         headerp->VolnameHash[i] = ntohl(headerp->VolnameHash[i]);
284     for (i = 0; i < MAXTYPES; i++)
285         for (j = 0; j < HASHSIZE; j++)
286             headerp->VolidHash[i][j] = ntohl(headerp->VolidHash[i][j]);
287
288     if (listheader) {
289         quiet_println("vldb header\n");
290         quiet_println("   vldbversion      = %u\n",
291                headerp->vital_header.vldbversion);
292         quiet_println("   headersize       = %u [actual=%lu]\n",
293                headerp->vital_header.headersize, sizeof(*headerp));
294         quiet_println("   freePtr          = 0x%x\n", headerp->vital_header.freePtr);
295         quiet_println("   eofPtr           = %u\n", headerp->vital_header.eofPtr);
296         quiet_println("   allocblock calls = %10u\n", headerp->vital_header.allocs);
297         quiet_println("   freeblock  calls = %10u\n", headerp->vital_header.frees);
298         quiet_println("   MaxVolumeId      = %u\n",
299                headerp->vital_header.MaxVolumeId);
300         quiet_println("   rw vol entries   = %u\n",
301                headerp->vital_header.totalEntries[0]);
302         quiet_println("   ro vol entries   = %u\n",
303                headerp->vital_header.totalEntries[1]);
304         quiet_println("   bk vol entries   = %u\n",
305                headerp->vital_header.totalEntries[2]);
306         quiet_println("   multihome info   = 0x%x (%u)\n", headerp->SIT,
307                headerp->SIT);
308         quiet_println("   server ip addr   table: size = %d entries\n",
309                MAXSERVERID + 1);
310         quiet_println("   volume name hash table: size = %d buckets\n", HASHSIZE);
311         quiet_println("   volume id   hash table: %d tables with %d buckets each\n",
312                MAXTYPES, HASHSIZE);
313     }
314
315     /* Check the header size */
316     if (headerp->vital_header.headersize != sizeof(*headerp))
317         log_error(VLDB_CHECK_WARNING,"Header reports its size as %d (should be %lu)\n",
318                headerp->vital_header.headersize, sizeof(*headerp));
319     return;
320 }
321
322 void
323 writeheader(struct vlheader *headerp)
324 {
325     int i, j;
326
327     headerp->vital_header.vldbversion =
328         htonl(headerp->vital_header.vldbversion);
329     headerp->vital_header.headersize =
330         htonl(headerp->vital_header.headersize);
331     headerp->vital_header.freePtr = htonl(headerp->vital_header.freePtr);
332     headerp->vital_header.eofPtr = htonl(headerp->vital_header.eofPtr);
333     headerp->vital_header.allocs = htonl(headerp->vital_header.allocs);
334     headerp->vital_header.frees = htonl(headerp->vital_header.frees);
335     headerp->vital_header.MaxVolumeId =
336         htonl(headerp->vital_header.MaxVolumeId);
337     headerp->vital_header.totalEntries[0] =
338         htonl(headerp->vital_header.totalEntries[0]);
339     for (i = 0; i < MAXTYPES; i++)
340         headerp->vital_header.totalEntries[i] =
341             htonl(headerp->vital_header.totalEntries[1]);
342
343     headerp->SIT = htonl(headerp->SIT);
344     for (i = 0; i < MAXSERVERID; i++)
345         headerp->IpMappedAddr[i] = htonl(headerp->IpMappedAddr[i]);
346     for (i = 0; i < HASHSIZE; i++)
347         headerp->VolnameHash[i] = htonl(headerp->VolnameHash[i]);
348     for (i = 0; i < MAXTYPES; i++)
349         for (j = 0; j < HASHSIZE; j++)
350             headerp->VolidHash[i][j] = htonl(headerp->VolidHash[i][j]);
351
352     vldbwrite(0, (char *)headerp, sizeof(*headerp));
353 }
354
355 void
356 readMH(afs_int32 addr, struct extentaddr *mhblockP)
357 {
358     int i, j;
359     struct extentaddr *e;
360
361     vldbread(addr, (char *)mhblockP, VL_ADDREXTBLK_SIZE);
362
363     mhblockP->ex_count = ntohl(mhblockP->ex_count);
364     mhblockP->ex_flags = ntohl(mhblockP->ex_flags);
365     for (i = 0; i < VL_MAX_ADDREXTBLKS; i++)
366         mhblockP->ex_contaddrs[i] = ntohl(mhblockP->ex_contaddrs[i]);
367
368     for (i = 1; i < VL_MHSRV_PERBLK; i++) {
369         e = &(mhblockP[i]);
370
371         /* won't convert hostuuid */
372         e->ex_uniquifier = ntohl(e->ex_uniquifier);
373         for (j = 0; j < VL_MAXIPADDRS_PERMH; j++)
374             e->ex_addrs[j] = ntohl(e->ex_addrs[j]);
375     }
376     return;
377 }
378
379 void
380 readentry(afs_int32 addr, struct nvlentry *vlentryp, afs_int32 *type)
381 {
382     int i;
383
384     vldbread(addr, (char *)vlentryp, sizeof(*vlentryp));
385
386     for (i = 0; i < MAXTYPES; i++)
387         vlentryp->volumeId[i] = ntohl(vlentryp->volumeId[i]);
388     vlentryp->flags = ntohl(vlentryp->flags);
389     vlentryp->LockAfsId = ntohl(vlentryp->LockAfsId);
390     vlentryp->LockTimestamp = ntohl(vlentryp->LockTimestamp);
391     vlentryp->cloneId = ntohl(vlentryp->cloneId);
392     for (i = 0; i < MAXTYPES; i++)
393         vlentryp->nextIdHash[i] = ntohl(vlentryp->nextIdHash[i]);
394     vlentryp->nextNameHash = ntohl(vlentryp->nextNameHash);
395     for (i = 0; i < NMAXNSERVERS; i++) {
396         /* make sure not to ntohl these, as they're chars, not ints */
397         vlentryp->serverNumber[i] = vlentryp->serverNumber[i];
398         vlentryp->serverPartition[i] = vlentryp->serverPartition[i];
399         vlentryp->serverFlags[i] = vlentryp->serverFlags[i];
400     }
401
402     if (vlentryp->flags == VLCONTBLOCK) {
403         *type = MH;
404     } else if (vlentryp->flags == VLFREE) {
405         *type = FR;
406     } else {
407         *type = VL;
408     }
409
410     if (listentries) {
411         quiet_println("address %u: ", addr);
412         if (vlentryp->flags == VLCONTBLOCK) {
413             quiet_println("mh extension block\n");
414         } else if (vlentryp->flags == VLFREE) {
415             quiet_println("free vlentry\n");
416         } else {
417             quiet_println("vlentry %s\n", vlentryp->name);
418             quiet_println("   rw id = %u ; ro id = %u ; bk id = %u\n",
419                    vlentryp->volumeId[0], vlentryp->volumeId[1],
420                    vlentryp->volumeId[2]);
421             quiet_println("   flags         =");
422             if (vlentryp->flags & VLF_RWEXISTS)
423                 quiet_println(" rw");
424             if (vlentryp->flags & VLF_ROEXISTS)
425                 quiet_println(" ro");
426             if (vlentryp->flags & VLF_BACKEXISTS)
427                 quiet_println(" bk");
428             if (vlentryp->flags & 0xffff8fff)
429                 quiet_println(" errorflag(0x%x)", vlentryp->flags);
430             quiet_println("\n");
431             quiet_println("   LockAfsId     = %d\n", vlentryp->LockAfsId);
432             quiet_println("   LockTimestamp = %d\n", vlentryp->LockTimestamp);
433             quiet_println("   cloneId       = %u\n", vlentryp->cloneId);
434             quiet_println
435                 ("   next hash for rw = %u ; ro = %u ; bk = %u ; name = %u\n",
436                  vlentryp->nextIdHash[0], vlentryp->nextIdHash[1],
437                  vlentryp->nextIdHash[2], vlentryp->nextNameHash);
438             for (i = 0; i < NMAXNSERVERS; i++) {
439                 if (vlentryp->serverNumber[i] != 255) {
440                     quiet_println("   server %d ; partition %d ; flags =",
441                            vlentryp->serverNumber[i],
442                            vlentryp->serverPartition[i]);
443                     if (vlentryp->serverFlags[i] & VLSF_RWVOL)
444                         quiet_println(" rw");
445                     if (vlentryp->serverFlags[i] & VLSF_ROVOL)
446                         quiet_println(" ro");
447                     if (vlentryp->serverFlags[i] & VLSF_BACKVOL)
448                         quiet_println(" bk");
449                     if (vlentryp->serverFlags[i] & VLSF_NEWREPSITE)
450                         quiet_println(" newro");
451                     quiet_println("\n");
452                 }
453             }
454         }
455     }
456     return;
457 }
458
459 void
460 writeentry(afs_int32 addr, struct nvlentry *vlentryp)
461 {
462     int i;
463
464     if (verbose) quiet_println("Writing back entry at addr %u\n", addr);
465     for (i = 0; i < MAXTYPES; i++)
466         vlentryp->volumeId[i] = htonl(vlentryp->volumeId[i]);
467     vlentryp->flags = htonl(vlentryp->flags);
468     vlentryp->LockAfsId = htonl(vlentryp->LockAfsId);
469     vlentryp->LockTimestamp = htonl(vlentryp->LockTimestamp);
470     vlentryp->cloneId = htonl(vlentryp->cloneId);
471     for (i = 0; i < MAXTYPES; i++)
472         vlentryp->nextIdHash[i] = htonl(vlentryp->nextIdHash[i]);
473     vlentryp->nextNameHash = htonl(vlentryp->nextNameHash);
474     for (i = 0; i < NMAXNSERVERS; i++) {
475         /* make sure not to htonl these, as they're chars, not ints */
476         vlentryp->serverNumber[i] =  vlentryp->serverNumber[i] ;
477         vlentryp->serverPartition[i] = vlentryp->serverPartition[i] ;
478         vlentryp->serverFlags[i] = vlentryp->serverFlags[i] ;
479     }
480     vldbwrite(addr, (char *)vlentryp, sizeof(*vlentryp));
481 }
482
483 void
484 readSIT(int base, int addr)
485 {
486     int i, j, a;
487     char sitbuf[VL_ADDREXTBLK_SIZE];
488     struct extentaddr *extent;
489
490     if (!addr)
491         return;
492     vldbread(addr, sitbuf, VL_ADDREXTBLK_SIZE);
493     extent = (struct extentaddr *)sitbuf;
494
495     quiet_println("multihome info block: base %d\n", base);
496     if (base == 0) {
497         quiet_println("   count = %u\n", ntohl(extent->ex_count));
498         quiet_println("   flags = %u\n", ntohl(extent->ex_flags));
499         for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
500             quiet_println("   contaddrs[%d] = %u\n", i,
501                    ntohl(extent->ex_contaddrs[i]));
502         }
503     }
504     for (i = 1; i < VL_MHSRV_PERBLK; i++) {
505         /* should we skip this entry */
506         for (j = 0; j < VL_MAX_ADDREXTBLKS; j++) {
507             if (extent[i].ex_addrs[j])
508                 break;
509         }
510         if (j >= VL_MAX_ADDREXTBLKS)
511             continue;
512
513         quiet_println("   base %d index %d:\n", base, i);
514
515         quiet_println("       afsuuid    = (%x %x %x /%d/%d/ /%x/%x/%x/%x/%x/%x/)\n",
516                ntohl(extent[i].ex_hostuuid.time_low),
517                ntohl(extent[i].ex_hostuuid.time_mid),
518                ntohl(extent[i].ex_hostuuid.time_hi_and_version),
519                ntohl(extent[i].ex_hostuuid.clock_seq_hi_and_reserved),
520                ntohl(extent[i].ex_hostuuid.clock_seq_low),
521                ntohl(extent[i].ex_hostuuid.node[0]),
522                ntohl(extent[i].ex_hostuuid.node[1]),
523                ntohl(extent[i].ex_hostuuid.node[2]),
524                ntohl(extent[i].ex_hostuuid.node[3]),
525                ntohl(extent[i].ex_hostuuid.node[4]),
526                ntohl(extent[i].ex_hostuuid.node[5]));
527         quiet_println("       uniquifier = %u\n", ntohl(extent[i].ex_uniquifier));
528         for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
529             a = ntohl(extent[i].ex_addrs[j]);
530             if (a) {
531                 quiet_println("       %d.%d.%d.%d\n", (a >> 24) & 0xff,
532                        (a >> 16) & 0xff, (a >> 8) & 0xff, (a) & 0xff);
533             }
534         }
535     }
536 }
537
538 /*
539  * Read each entry in the database:
540  * Record what type of entry it is and its address in the record array.
541  * Remember what the maximum volume id we found is and check against the header.
542  */
543 void
544 ReadAllEntries(struct vlheader *header)
545 {
546     afs_int32 type, rindex, i, j, e;
547     int freecount = 0, mhcount = 0, vlcount = 0;
548     int rwcount = 0, rocount = 0, bkcount = 0;
549     struct nvlentry vlentry;
550     afs_uint32 addr;
551     afs_uint32 entrysize = 0;
552     afs_uint32 maxvolid = 0;
553
554     if (verbose) quiet_println("Read each entry in the database\n");
555     for (addr = header->vital_header.headersize;
556          addr < header->vital_header.eofPtr; addr += entrysize) {
557
558         /* Remember the highest volume id */
559         readentry(addr, &vlentry, &type);
560         if (type == VL) {
561             if (!(vlentry.flags & VLF_RWEXISTS))
562                 log_error(VLDB_CHECK_WARNING,"VLDB_CHECK_WARNING: VLDB entry '%s' has no RW volume\n",
563                        vlentry.name);
564
565             for (i = 0; i < MAXTYPES; i++)
566                 if (maxvolid < vlentry.volumeId[i])
567                     maxvolid = vlentry.volumeId[i];
568
569             e = 1;
570             for (j = 0; j < NMAXNSERVERS; j++) {
571                 if (vlentry.serverNumber[j] == 255)
572                     continue;
573                 if (vlentry.serverFlags[j] & (VLSF_ROVOL | VLSF_NEWREPSITE)) {
574                     rocount++;
575                     continue;
576                 }
577                 if (vlentry.serverFlags[j] & VLSF_RWVOL) {
578                     rwcount++;
579                     if (vlentry.flags & VLF_BACKEXISTS)
580                         bkcount++;
581                     continue;
582                 }
583                 if (!vlentry.serverFlags[j]) {
584                     /*e = 0;*/
585                     continue;
586                 }
587                 if (e) {
588                    log_error 
589                         (VLDB_CHECK_ERROR,"VLDB entry '%s' contains an unknown RW/RO index serverFlag\n",
590                          vlentry.name);
591                     e = 0;
592                 }
593                 quiet_println
594                     ("   index %d : serverNumber %d : serverPartition %d : serverFlag %d\n",
595                      j, vlentry.serverNumber[j], vlentry.serverPartition[j],
596                      vlentry.serverFlags[j]);
597             }
598         }
599
600         rindex = addr / sizeof(vlentry);
601         if (record[rindex].type) {
602             log_error(VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: record holder %d already in use\n",
603                    rindex);
604             return;
605         }
606         record[rindex].addr = addr;
607         record[rindex].type = type;
608
609         /* Determine entrysize and keep count */
610         if (type == VL) {
611             entrysize = sizeof(vlentry);
612             vlcount++;
613         } else if (type == FR) {
614             entrysize = sizeof(vlentry);
615             freecount++;
616         } else if (type == MH) {
617             entrysize = VL_ADDREXTBLK_SIZE;
618             mhcount++;
619         } else {
620             log_error(VLDB_CHECK_ERROR, "Unknown entry at %u. Aborting\n", addr);
621             break;
622         }
623     }
624     if (verbose) {
625         quiet_println("Found %d entries, %d free entries, %d multihomed blocks\n",
626                vlcount, freecount, mhcount);
627         quiet_println("Found %d RW volumes, %d BK volumes, %d RO volumes\n", rwcount,
628                bkcount, rocount);
629     }
630
631     /* Check the maxmimum volume id in the header */
632     if (maxvolid != header->vital_header.MaxVolumeId - 1)
633         quiet_println
634             ("Header's maximum volume id is %u and largest id found in VLDB is %u\n",
635              header->vital_header.MaxVolumeId, maxvolid);
636 }
637
638 /*
639  * Follow each Name hash bucket marking it as read in the record array.
640  * Record we found it in the name hash within the record array.
641  * Check that the name is hashed correctly.
642  */
643 void
644 FollowNameHash(struct vlheader *header)
645 {
646     int count = 0, longest = 0, shortest = -1, chainlength;
647     struct nvlentry vlentry;
648     afs_uint32 addr;
649     afs_int32 i, type, rindex;
650
651     /* Now follow the Name Hash Table */
652     if (verbose) quiet_println("Check Volume Name Hash\n");
653     for (i = 0; i < HASHSIZE; i++) {
654         chainlength = 0;
655
656         if (!validVolumeAddr(header->VolnameHash[i])) {
657             log_error(VLDB_CHECK_ERROR,"Name Hash %d: Bad entry %u is out of range\n",
658                       i, header->VolnameHash[i]);
659             continue;
660         }
661
662         for (addr = header->VolnameHash[i]; addr; addr = vlentry.nextNameHash) {
663             readentry(addr, &vlentry, &type);
664             if (type != VL) {
665                 log_error(VLDB_CHECK_ERROR,"Name Hash %d: Bad entry at %u: Not a valid vlentry\n",
666                        i, addr);
667                 continue;
668             }
669
670             rindex = ADDR(addr);
671
672             /*
673              * we know that the address is valid because we
674              * checked it either above or below
675              */
676             if (record[rindex].addr != addr && record[rindex].addr) {
677                 log_error       
678                     (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
679                      record[rindex].addr, addr, rindex);
680             }
681             if (record[rindex].type & NH) {
682                 log_error       
683                     (VLDB_CHECK_ERROR,"Name Hash %d: Bad entry '%s': Already in the name hash\n",
684                      i, vlentry.name);
685                 record[rindex].type |= MULTN;
686                 break;
687             }
688
689             if (!validVolumeAddr(vlentry.nextNameHash)) {
690                 log_error(VLDB_CHECK_ERROR,"Name Hash forward link of '%s' is out of range\n",
691                           vlentry.name);
692                 record[rindex].type |= MULTN;
693                 break;
694             }
695
696             record[rindex].type |= NH;
697             record[rindex].type |= REFN;
698
699             chainlength++;
700             count++;
701
702             /* Hash the name and check if in correct hash table */
703             if (NameHash(vlentry.name) != i) {
704                 log_error       
705                     (VLDB_CHECK_ERROR,"Name Hash %d: Bad entry '%s': Incorrect name hash chain (should be in %d)\n",
706                      i, vlentry.name, NameHash(vlentry.name));
707                 record[rindex].type |= MULTN;
708             }
709         }
710         if (chainlength > longest)
711             longest = chainlength;
712         if ((shortest == -1) || (chainlength < shortest))
713             shortest = chainlength;
714     }
715     if (verbose) {
716         quiet_println
717             ("%d entries in name hash, longest is %d, shortest is %d, average length is %f\n",
718              count, longest, shortest, ((float)count / (float)HASHSIZE));
719     }
720     return;
721 }
722
723 /*
724  * Follow the ID hash chains for the RW, RO, and BK hash tables.
725  * Record we found it in the id hash within the record array.
726  * Check that the ID is hashed correctly.
727  */
728 void
729 FollowIdHash(struct vlheader *header)
730 {
731     int count = 0, longest = 0, shortest = -1, chainlength;
732     struct nvlentry vlentry;
733     afs_uint32 addr;
734     afs_int32 i, j, hash, type, rindex, ref, badref, badhash;
735
736     /* Now follow the RW, RO, and BK Hash Tables */
737     if (verbose) quiet_println("Check RW, RO, and BK id Hashes\n");
738     for (i = 0; i < MAXTYPES; i++) {
739         hash = ((i == 0) ? RWH : ((i == 1) ? ROH : BKH));
740         ref = ((i == 0) ? REFRW : ((i == 1) ? REFRO : REFBK));
741         badref = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
742         badhash = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
743         count = longest = 0;
744         shortest = -1;
745
746         for (j = 0; j < HASHSIZE; j++) {
747             chainlength = 0;
748             if (!validVolumeAddr(header->VolidHash[i][j])) {
749                 log_error(VLDB_CHECK_ERROR,"%s Hash %d: Bad entry %u is out of range\n",
750                           vtype(i), j, header->VolidHash[i][j]);
751                 continue;
752             }
753
754             for (addr = header->VolidHash[i][j]; addr;
755                  addr = vlentry.nextIdHash[i]) {
756                 readentry(addr, &vlentry, &type);
757                 if (type != VL) {
758                     log_error
759                         (VLDB_CHECK_ERROR,"%s Id Hash %d: Bad entry at %u: Not a valid vlentry\n",
760                          vtype(i), j, addr);
761                     continue;
762                 }
763
764                 rindex = ADDR(addr);
765                 if (record[rindex].addr != addr && record[rindex].addr) {
766                     log_error
767                         (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
768                          record[rindex].addr, addr, rindex);
769                 }
770                 if (record[rindex].type & hash) {
771                     log_error
772                         (VLDB_CHECK_ERROR,"%s Id Hash %d: Bad entry '%s': Already in the hash table\n",
773                          vtype(i), j, vlentry.name);
774                     record[rindex].type |= badref;
775                     break;
776                 }
777
778                 if (!validVolumeAddr(vlentry.nextIdHash[i])) {
779                     log_error(VLDB_CHECK_ERROR,"%s Id Hash forward link of '%s' is out of range\n",
780                               vtype(i), vlentry.name);
781                     record[rindex].type |= badref;
782                     break;
783                 }
784
785                 record[rindex].type |= hash;
786                 record[rindex].type |= ref;
787
788                 chainlength++;
789                 count++;
790
791                 /* Hash the id and check if in correct hash table */
792                 if (IdHash(vlentry.volumeId[i]) != j) {
793                    log_error 
794                         (VLDB_CHECK_ERROR,"%s Id Hash %d: Bad entry '%s': Incorrect Id hash chain (should be in %d)\n",
795                          vtype(i), j, vlentry.name,
796                          IdHash(vlentry.volumeId[i]));
797                     record[rindex].type |= badhash;
798                 }
799             }
800
801             if (chainlength > longest)
802                 longest = chainlength;
803             if ((shortest == -1) || (chainlength < shortest))
804                 shortest = chainlength;
805         }
806         if (verbose) {
807             quiet_println
808                 ("%d entries in %s hash, longest is %d, shortest is %d, average length is %f\n",
809                  count, vtype(i), longest, shortest,((float)count / (float)HASHSIZE));
810         }
811     }
812     return;
813 }
814
815 /*
816  * Follow the free chain.
817  * Record we found it in the free chain within the record array.
818  */
819 void
820 FollowFreeChain(struct vlheader *header)
821 {
822     afs_int32 count = 0;
823     struct nvlentry vlentry;
824     afs_uint32 addr;
825     afs_int32 type, rindex;
826
827     /* Now follow the Free Chain */
828     if (verbose) quiet_println("Check Volume Free Chain\n");
829     for (addr = header->vital_header.freePtr; addr;
830          addr = vlentry.nextIdHash[0]) {
831         readentry(addr, &vlentry, &type);
832         if (type != FR) {
833            log_error 
834                 (VLDB_CHECK_ERROR,"Free Chain %d: Bad entry at %u: Not a valid free vlentry (0x%x)\n",
835                  count, addr, type);
836             continue;
837         }
838
839         rindex = addr / sizeof(vlentry);
840         if (record[rindex].addr != addr && record[rindex].addr) {
841            log_error 
842                 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u and %ld use same record slot %d\n",
843                  record[rindex].addr, addr, rindex);
844         }
845         if (record[rindex].type & FRC) {
846             log_error(VLDB_CHECK_ERROR,"Free Chain: Bad entry at %u: Already in the free chain\n",
847                    addr);
848             break;
849         }
850         record[rindex].type |= FRC;
851
852         count++;
853     }
854     if (verbose)
855      quiet_println("%d entries on free chain\n", count);
856     return;
857 }
858
859 /*
860  * Read each multihomed block and mark it as found in the record.
861  * Read each entry in each multihomed block and mark the serveraddrs
862  * array with the number of ip addresses found for this entry.
863  * 
864  * Then read the IpMappedAddr array in the header.
865  * Verify that multihomed entries base and index are valid and points to
866  * a good multhomed entry.
867  * Mark the serveraddrs array with 1 ip address for regular entries.
868  * 
869  * By the end, the severaddrs array will have a 0 if the entry has no 
870  * IP addresses in it or the count of the number of IP addresses.
871  *
872  * The code does not verify if there are duplicate IP addresses in the 
873  * list. The vlserver does this when a fileserver registeres itself.
874  */
875 void
876 CheckIpAddrs(struct vlheader *header)
877 {
878     int mhblocks = 0;
879     afs_int32 i, j, m, rindex;
880     afs_int32 mhentries, regentries;
881     afs_int32 caddrs[VL_MAX_ADDREXTBLKS];
882     char mhblock[VL_ADDREXTBLK_SIZE];
883     struct extentaddr *MHblock = (struct extentaddr *)mhblock;
884     struct extentaddr *e;
885     int ipindex, ipaddrs;
886     afsUUID nulluuid;
887
888     memset(&nulluuid, 0, sizeof(nulluuid));
889
890     if (verbose)
891         quiet_println("Check Multihomed blocks\n");
892
893     if (header->SIT) {
894         /* Read the first MH block and from it, gather the 
895          * addresses of all the mh blocks.
896          */
897         readMH(header->SIT, MHblock);
898         if (MHblock->ex_flags != VLCONTBLOCK) {
899            log_error 
900                 (VLDB_CHECK_ERROR,"Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
901                  header->SIT);
902         }
903
904         for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
905             caddrs[i] = MHblock->ex_contaddrs[i];
906         }
907
908         if (header->SIT != caddrs[0]) {
909            log_error 
910                 (VLDB_CHECK_ERROR,"MH block does not point to self %u in header, %u in block\n",
911                  header->SIT, caddrs[0]);
912         }
913
914         /* Now read each MH block and record it in the record array */
915         for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
916             if (!caddrs[i])
917                 continue;
918
919             readMH(caddrs[i], MHblock);
920             if (MHblock->ex_flags != VLCONTBLOCK) {
921                 log_error       
922                     (VLDB_CHECK_ERROR,"Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
923                      header->SIT);
924             }
925
926             rindex = caddrs[i] / sizeof(vlentry);
927             if (record[rindex].addr != caddrs[i] && record[rindex].addr) {
928                 log_error       
929                     (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u and %u use same record slot %d\n",
930                      record[rindex].addr, caddrs[i], rindex);
931             }
932             if (record[rindex].type & FRC) {
933                 log_error       
934                     (VLDB_CHECK_ERROR,"MH Blocks Chain %d: Bad entry at %ld: Already a MH block\n",
935                      i, record[rindex].addr);
936                 break;
937             }
938             record[rindex].type |= MHC;
939
940             mhblocks++;
941
942             /* Read each entry in a multihomed block. 
943              * Find the pointer to the entry in the IpMappedAddr array and
944              * verify that the entry is good (has IP addresses in it).
945              */
946             mhentries = 0;
947             for (j = 1; j < VL_MHSRV_PERBLK; j++) {
948                 e = (struct extentaddr *)&(MHblock[j]);
949
950                 /* Search the IpMappedAddr array for the reference to this entry */
951                 for (ipindex = 0; ipindex < MAXSERVERID; ipindex++) {
952                     if (((header->IpMappedAddr[ipindex] & 0xff000000) ==
953                          0xff000000)
954                         &&
955                         (((header->
956                            IpMappedAddr[ipindex] & 0x00ff0000) >> 16) == i)
957                         && ((header->IpMappedAddr[ipindex] & 0x0000ffff) ==
958                             j)) {
959                         break;
960                     }
961                 }
962                 if (ipindex >= MAXSERVERID)
963                     ipindex = -1;
964                 else
965                     serveraddrs[ipindex] = -1;
966
967                 if (memcmp(&e->ex_hostuuid, &nulluuid, sizeof(afsUUID)) == 0) {
968                     if (ipindex != -1) {
969                         log_error       
970                             (VLDB_CHECK_ERROR,"Server Addrs index %d references null MH block %d, index %d\n",
971                              ipindex, i, j);
972                         serveraddrs[ipindex] = 0;       /* avoids printing 2nd error below */
973                     }
974                     continue;
975                 }
976
977                 /* Step through each ip address and count the good addresses */
978                 ipaddrs = 0;
979                 for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
980                     if (e->ex_addrs[m])
981                         ipaddrs++;
982                 }
983
984                 /* If we found any good ip addresses, mark it in the serveraddrs record */
985                 if (ipaddrs) {
986                     mhentries++;
987                     if (ipindex == -1) {
988                         log_error       
989                             (VLDB_CHECK_ERROR,"MH block %d, index %d: Not referenced by server addrs\n",
990                              i, j);
991                     } else {
992                         serveraddrs[ipindex] = ipaddrs; /* It is good */
993                     }
994                 }
995
996                 if (listservers && ipaddrs) {
997                     quiet_println("MH block %d, index %d:", i, j);
998                     for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
999                         if (!e->ex_addrs[m])
1000                             continue;
1001                         quiet_println(" %d.%d.%d.%d",
1002                                (e->ex_addrs[m] & 0xff000000) >> 24,
1003                                (e->ex_addrs[m] & 0x00ff0000) >> 16,
1004                                (e->ex_addrs[m] & 0x0000ff00) >> 8,
1005                                (e->ex_addrs[m] & 0x000000ff));
1006                     }
1007                     quiet_println("\n");
1008                 }
1009             }
1010 /*
1011  *      if (mhentries != MHblock->ex_count) {
1012  *         quiet_println("MH blocks says it has %d entries (found %d)\n",
1013  *                MHblock->ex_count, mhentries);
1014  *      }
1015  */
1016         }
1017     }
1018     if (verbose)
1019         quiet_println("%d multihomed blocks\n", mhblocks);
1020
1021     /* Check the server addresses */
1022     if (verbose)
1023         quiet_println("Check server addresses\n");
1024     mhentries = regentries = 0;
1025     for (i = 0; i <= MAXSERVERID; i++) {
1026         if (header->IpMappedAddr[i]) {
1027             if ((header->IpMappedAddr[i] & 0xff000000) == 0xff000000) {
1028                 mhentries++;
1029                 if (((header->IpMappedAddr[i] & 0x00ff0000) >> 16) >
1030                     VL_MAX_ADDREXTBLKS)
1031                    log_error 
1032                         (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome block is bad (%d)\n",
1033                          i, ((header->IpMappedAddr[i] & 0x00ff0000) >> 16));
1034                 if (((header->IpMappedAddr[i] & 0x0000ffff) > VL_MHSRV_PERBLK)
1035                     || ((header->IpMappedAddr[i] & 0x0000ffff) < 1))
1036                     log_error 
1037                         (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome index is bad (%d)\n",
1038                          i, (header->IpMappedAddr[i] & 0x0000ffff));
1039                 if (serveraddrs[i] == -1) {
1040                     log_error 
1041                         (VLDB_CHECK_WARNING,"warning: IP Addr for entry %d: Multihome entry has no ip addresses\n",
1042                          i);
1043                     serveraddrs[i] = 0;
1044                 }
1045                 if (listservers) {
1046                     quiet_println("   Server ip addr %d = MH block %d, index %d\n",
1047                            i, (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1048                            (header->IpMappedAddr[i] & 0x0000ffff));
1049                 }
1050             } else {
1051                 regentries++;
1052                 serveraddrs[i] = 1;     /* It is good */
1053                 if (listservers) {
1054                     quiet_println("   Server ip addr %d = %d.%d.%d.%d\n", i,
1055                            (header->IpMappedAddr[i] & 0xff000000) >> 24,
1056                            (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1057                            (header->IpMappedAddr[i] & 0x0000ff00) >> 8,
1058                            (header->IpMappedAddr[i] & 0x000000ff));
1059                 }
1060             }
1061         }
1062     }
1063     if (verbose) {
1064         quiet_println("%d simple entries, %d multihomed entries, Total = %d\n",
1065                regentries, mhentries, mhentries + regentries);
1066     }
1067     return;
1068 }
1069
1070 char *
1071 nameForAddr(afs_uint32 addr, int hashtype, afs_uint32 *hash, char *buffer)
1072 {
1073     /*
1074      * We need to simplify the reporting, while retaining
1075      * legible messages.  This is a helper function.  The return address
1076      * is either a fixed char or the provided buffer - so don't use the
1077      * name after the valid lifetime of the buffer.
1078      */
1079     afs_int32 type;
1080     struct nvlentry entry;
1081     if (!addr) {
1082         /* Distinguished, invalid, hash */
1083         *hash = 0xFFFFFFFF;
1084         return "empty";
1085     } else if (!validVolumeAddr(addr)) {
1086         /* Different, invalid, hash */
1087         *hash = 0XFFFFFFFE;
1088         return "invalid";
1089     }
1090     readentry(addr, &entry, &type);
1091     if (VL != type) {
1092         *hash = 0XFFFFFFFE;
1093         return "invalid";
1094     }
1095     if (hashtype >= MAXTYPES) {
1096         *hash = NameHash(entry.name);
1097     } else {
1098         *hash = IdHash(entry.volumeId[hashtype]);
1099     }
1100     sprintf(buffer, "for '%s'", entry.name);
1101     return buffer;
1102 }
1103
1104 void
1105 reportHashChanges(struct vlheader *header, afs_uint32 oldnamehash[HASHSIZE], afs_uint32 oldidhash[MAXTYPES][HASHSIZE])
1106 {
1107     int i, j;
1108     afs_uint32 oldhash, newhash;
1109     char oldNameBuffer[10 + VL_MAXNAMELEN];
1110     char newNameBuffer[10 + VL_MAXNAMELEN];
1111     char *oldname, *newname;
1112     /*
1113      * report hash changes
1114      */
1115
1116     for (i = 0; i < HASHSIZE; i++) {
1117         if (oldnamehash[i] != header->VolnameHash[i]) {
1118
1119             oldname = nameForAddr(oldnamehash[i], MAXTYPES, &oldhash, oldNameBuffer);
1120             newname = nameForAddr(header->VolnameHash[i], MAXTYPES, &newhash, newNameBuffer);
1121             if (verbose || (oldhash != newhash)) {
1122                 quiet_println("FIX: Name hash header at %d was %s, is now %s\n", i, oldname, newname);
1123             }
1124         }
1125         for (j = 0; j < MAXTYPES; j++) {
1126             if (oldidhash[j][i] != header->VolidHash[j][i]) {
1127
1128                 oldname = nameForAddr(oldidhash[j][i], j, &oldhash, oldNameBuffer);
1129                 newname = nameForAddr(header->VolidHash[j][i], j, &newhash, newNameBuffer);
1130                 if (verbose || (oldhash != newhash)) {
1131                     quiet_println("FIX: %s hash header at %d was %s, is now %s\n", vtype(j), i, oldname, newname);
1132                 }
1133             }
1134         }
1135     }
1136 }
1137
1138 int
1139 WorkerBee(struct cmd_syndesc *as, void *arock)
1140 {
1141     char *dbfile;
1142     afs_int32 type;
1143     struct vlheader header;
1144     struct nvlentry vlentry, vlentry2;
1145     int i, j;
1146     afs_uint32 oldnamehash[HASHSIZE];
1147     afs_uint32 oldidhash[MAXTYPES][HASHSIZE];
1148
1149     error_level = 0;  /*  start clean with no error status */
1150     dbfile = as->parms[0].items->data;  /* -database */
1151     listuheader = (as->parms[1].items ? 1 : 0); /* -uheader  */
1152     listheader = (as->parms[2].items ? 1 : 0);  /* -vheader  */
1153     listservers = (as->parms[3].items ? 1 : 0); /* -servers  */
1154     listentries = (as->parms[4].items ? 1 : 0); /* -entries  */
1155     verbose = (as->parms[5].items ? 1 : 0);     /* -verbose  */
1156     quiet = (as->parms[6].items ? 1 : 0);  /* -quiet */
1157     fix = (as->parms[7].items ? 1 : 0);    /* -fix  */
1158
1159     /* sanity check */
1160     if (quiet && (verbose || listuheader || listheader ||listservers \
1161                 || listentries)) {
1162         log_error(VLDB_CHECK_FATAL," -quiet cannot be used other display flags\n");
1163         return VLDB_CHECK_FATAL;
1164     }
1165
1166
1167     /* open the vldb database file */
1168     fd = open(dbfile, (fix > 0)?O_RDWR:O_RDONLY, 0);
1169     if (fd < 0) {
1170         log_error(VLDB_CHECK_FATAL,"can't open file '%s'. error = %d\n", dbfile, errno);
1171         return 0;
1172     }
1173
1174     /* read the ubik header and the vldb database header */
1175     readUbikHeader();
1176     readheader(&header);
1177     if (header.vital_header.vldbversion < 3) {
1178         log_error(VLDB_CHECK_FATAL,"does not support vldb with version less than 3\n");
1179         return VLDB_CHECK_FATAL;
1180     }
1181
1182     maxentries = (header.vital_header.eofPtr / sizeof(vlentry)) + 1;
1183     record = (struct er *)malloc(maxentries * sizeof(struct er));
1184     memset(record, 0, (maxentries * sizeof(struct er)));
1185     memset(serveraddrs, 0, sizeof(serveraddrs));
1186
1187     /* Will fill in the record array of entries it found */
1188     ReadAllEntries(&header);
1189     listentries = 0;            /* Listed all the entries */
1190
1191     /* Check the multihomed blocks for valid entries as well as
1192      * the IpMappedAddrs array in the header for valid entries.
1193      */
1194     CheckIpAddrs(&header);
1195
1196     /* Follow the hash tables */
1197     FollowNameHash(&header);
1198     FollowIdHash(&header);
1199
1200     /* Follow the chain of free entries */
1201     FollowFreeChain(&header);
1202
1203     /* Now check the record we have been keeping for inconsistencies
1204      * For valid vlentries, also check that the server we point to is 
1205      * valid (the serveraddrs array).
1206      */
1207     if (verbose)
1208         quiet_println("Verify each volume entry\n");
1209     for (i = 0; i < maxentries; i++) {
1210         int nextp = 0;
1211         int reft = 0;
1212         int hash = 0;
1213         int nexthash = 0;
1214         int *nextpp = NULL;
1215         char *which = NULL;
1216
1217         if (record[i].type == 0)
1218             continue;
1219
1220         /* If a vlentry, verify that its name is valid, its name and ids are
1221          * on the hash chains, and its server numbers are good.
1222          */
1223         if (record[i].type & VL) {
1224             int foundbad = 0;
1225             int foundbroken = 0;
1226             char volidbuf[256];
1227
1228             readentry(record[i].addr, &vlentry, &type);
1229
1230             if (InvalidVolname(vlentry.name))
1231                 log_error(VLDB_CHECK_ERROR,"Volume '%s' at addr %ld has an invalid name\n",
1232                        vlentry.name, record[i].addr);
1233
1234             if (!(record[i].type & NH)) {
1235                 nextp = ADDR(vlentry.nextNameHash);
1236                 reft = REFN;
1237                 hash = NameHash(vlentry.name);
1238                 nextpp = &vlentry.nextNameHash;
1239                 which = "name";
1240                 volidbuf[0]='\0';
1241                 foundbad = 1;
1242             }
1243
1244             if (vlentry.volumeId[0] && !(record[i].type & RWH)) {
1245                 nextp = ADDR(vlentry.nextIdHash[0]);
1246                 reft = REFRW;
1247                 hash = IdHash(vlentry.volumeId[0]);
1248                 nextpp = &(vlentry.nextIdHash[0]);
1249                 which = "RW";
1250                 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1251                 foundbad = 1;
1252             }
1253
1254             if (vlentry.volumeId[1] && !(record[i].type & ROH)) {
1255                 nextp = ADDR(vlentry.nextIdHash[1]);
1256                 reft = REFRO;
1257                 hash = IdHash(vlentry.volumeId[1]);
1258                 nextpp = &(vlentry.nextIdHash[1]);
1259                 which = "RO";
1260                 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1261                 foundbad = 1;
1262             }
1263
1264             if (vlentry.volumeId[2] && !(record[i].type & BKH)) {
1265                 nextp = ADDR(vlentry.nextIdHash[2]);
1266                 reft = REFBK;
1267                 hash = IdHash(vlentry.volumeId[2]);
1268                 nextpp = &(vlentry.nextIdHash[2]);
1269                 which = "BK";
1270                 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1271                 foundbad = 1;
1272             }
1273
1274             if (!validVolumeAddr(vlentry.nextNameHash) ||
1275                 record[ADDR(vlentry.nextNameHash)].type & MULTN) {
1276                 nextp = ADDR(vlentry.nextNameHash);
1277                 reft = REFN;
1278                 hash = NameHash(vlentry.name);
1279                 nextpp = &vlentry.nextNameHash;
1280                 which = "name";
1281                 volidbuf[0]='\0';
1282                 if (validVolumeAddr(vlentry.nextNameHash)) {
1283                     readentry(vlentry.nextNameHash, &vlentry2, &type);
1284                     nexthash = NameHash(vlentry2.name);
1285                 } else {
1286                     nexthash = 0xFFFFFFFF;
1287                 }
1288                 if (hash != nexthash)
1289                     foundbroken = 1;
1290             }
1291
1292             if (!validVolumeAddr(vlentry.nextIdHash[0]) ||
1293                 record[ADDR(vlentry.nextIdHash[0])].type & MULTRW) {
1294                 nextp = ADDR(vlentry.nextIdHash[0]);
1295                 reft = REFRW;
1296                 hash = IdHash(vlentry.volumeId[0]);
1297                 nextpp = &(vlentry.nextIdHash[0]);
1298                 which = "RW";
1299                 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1300                 if (validVolumeAddr(vlentry.nextIdHash[0])) {
1301                     readentry(vlentry.nextIdHash[0], &vlentry2, &type);
1302                     nexthash = IdHash(vlentry2.volumeId[0]);
1303                 } else {
1304                     nexthash = 0xFFFFFFFF;
1305                 }
1306                 if (hash != nexthash)
1307                     foundbroken = 1;
1308             }
1309
1310             if (!validVolumeAddr(vlentry.nextIdHash[1]) ||
1311                 record[ADDR(vlentry.nextIdHash[1])].type & MULTRO) {
1312                 nextp = ADDR(vlentry.nextIdHash[1]);
1313                 reft = REFRO;
1314                 hash = IdHash(vlentry.volumeId[1]);
1315                 nextpp = &(vlentry.nextIdHash[1]);
1316                 which = "RO";
1317                 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1318                 if (validVolumeAddr(vlentry.nextIdHash[1])) {
1319                     readentry(vlentry.nextIdHash[1], &vlentry2, &type);
1320                     nexthash = IdHash(vlentry2.volumeId[1]);
1321                 } else {
1322                     nexthash = 0xFFFFFFFF;
1323                 }
1324                 if (hash != nexthash)
1325                     foundbroken = 1;
1326             }
1327
1328             if (!validVolumeAddr(vlentry.nextIdHash[2]) ||
1329                 record[ADDR(vlentry.nextIdHash[2])].type & MULTBK) {
1330                 nextp = ADDR(vlentry.nextIdHash[2]);
1331                 reft = REFBK;
1332                 hash = IdHash(vlentry.volumeId[2]);
1333                 nextpp = &(vlentry.nextIdHash[2]);
1334                 which = "BK";
1335                 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1336                 if (validVolumeAddr(vlentry.nextIdHash[2])) {
1337                     readentry(vlentry.nextIdHash[2], &vlentry2, &type);
1338                     nexthash = IdHash(vlentry2.volumeId[2]);
1339                 } else {
1340                     nexthash = 0xFFFFFFFF;
1341                 }
1342                 if (hash != nexthash)
1343                     foundbroken = 1;
1344             }
1345
1346             if (foundbroken) {
1347                 log_error(VLDB_CHECK_ERROR, "%d: Volume '%s' %s forward link in %s hash chain is broken (hash %d != %d)\n", i,
1348                           vlentry.name, volidbuf, which, hash, nexthash);
1349             } else if (foundbad) {
1350                 log_error(VLDB_CHECK_ERROR, "%d: Volume '%s' %snot found in %s hash %d\n", i,
1351                        vlentry.name, volidbuf, which, hash);
1352             }
1353
1354             for (j = 0; j < NMAXNSERVERS; j++) {
1355                 if ((vlentry.serverNumber[j] != 255)
1356                     && (serveraddrs[vlentry.serverNumber[j]] == 0)) {
1357                    log_error 
1358                         (VLDB_CHECK_ERROR,"Volume '%s', index %d points to empty server entry %d\n",
1359                          vlentry.name, j, vlentry.serverNumber[j]);
1360                 }
1361             }
1362         
1363             if (record[i].type & 0xffff0f00)
1364                 log_error       
1365                     (VLDB_CHECK_ERROR,"Volume '%s' id %u also found on other chains (0x%x)\n",
1366                      vlentry.name, vlentry.volumeId[0], record[i].type);
1367             
1368             /* A free entry */
1369         } else if (record[i].type & FR) {
1370             if (!(record[i].type & FRC))
1371                 log_error(VLDB_CHECK_ERROR,"Free vlentry at %ld not on free chain\n",
1372                        record[i].addr);
1373             
1374             if (record[i].type & 0xfffffdf0)
1375                 log_error       
1376                     (VLDB_CHECK_ERROR,"Free vlentry at %ld also found on other chains (0x%x)\n",
1377                      record[i].addr, record[i].type);
1378             
1379             /* A multihomed entry */
1380         } else if (record[i].type & MH) {
1381             if (!(record[i].type & MHC))
1382                 log_error(VLDB_CHECK_ERROR,"Multihomed block at %ld is orphaned\n",
1383                        record[i].addr);
1384             
1385             if (record[i].type & 0xfffffef0)
1386                 log_error       
1387                     (VLDB_CHECK_ERROR,"Multihomed block at %ld also found on other chains (0x%x)\n",
1388                      record[i].addr, record[i].type);
1389             
1390         } else {
1391             log_error(VLDB_CHECK_ERROR,"Unknown entry type at %u (0x%x)\n", record[i].addr,
1392                    record[i].type);
1393         }
1394     }
1395
1396     if (fix) {
1397         /*
1398          * If we are fixing we will rebuild all the hash lists from the ground up
1399          */
1400         memcpy(oldnamehash, header.VolnameHash, sizeof(oldnamehash));
1401         memset(header.VolnameHash, 0, sizeof(header.VolnameHash));
1402
1403         memcpy(oldidhash, header.VolidHash, sizeof(oldidhash));
1404         memset(header.VolidHash, 0, sizeof(header.VolidHash));
1405         quiet_println("Rebuilding %u entries\n", maxentries);
1406     } else {
1407         quiet_println("Scanning %u entries for possible repairs\n", maxentries);
1408     }
1409     for (i = 0; i < maxentries; i++) {
1410         afs_uint32 hash;
1411         if (record[i].type & VL) {
1412             readentry(record[i].addr, &vlentry, &type);
1413             if (!(record[i].type & REFN)) {
1414                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a name chain\n", i, 
1415                        record[i].addr, record[i].type);
1416             }
1417             if (vlentry.volumeId[0] && !(record[i].type & REFRW)) {
1418                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a RW chain\n", i,
1419                        record[i].addr, record[i].type);
1420             }
1421             if (vlentry.volumeId[1] && !(record[i].type & REFRO)) {
1422                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a RO chain\n", i, 
1423                        record[i].addr, record[i].type);
1424             }
1425             if (vlentry.volumeId[2] && !(record[i].type & REFBK)) {
1426                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a BK chain\n", i, 
1427                        record[i].addr, record[i].type);
1428             }
1429             if (fix) {
1430                 afs_uint32 oldhash, newhash;
1431                 char oldNameBuffer[10 + VL_MAXNAMELEN];
1432                 char newNameBuffer[10 + VL_MAXNAMELEN];
1433                 char *oldname, *newname;
1434
1435                 /*
1436                  * Put the current hash table contexts into our 'next'
1437                  * and our address into the hash table.
1438                  */
1439                 hash = NameHash(vlentry.name);
1440
1441                 if (vlentry.nextNameHash != header.VolnameHash[hash]) {
1442                     oldname = nameForAddr(vlentry.nextNameHash, MAXTYPES, &oldhash, oldNameBuffer);
1443                     newname = nameForAddr(header.VolnameHash[hash], MAXTYPES, &newhash, newNameBuffer);
1444                     if (verbose || ((oldhash != newhash) &&
1445                                     (0 != vlentry.nextNameHash) &&
1446                                     (0 != header.VolnameHash[hash]))) {
1447                         /*
1448                          * That is, only report if we are verbose
1449                          * or the hash is changing (and one side wasn't NULL
1450                          */
1451                         quiet_println("FIX: Name hash link for '%s' was %s, is now %s\n",
1452                               vlentry.name, oldname, newname);
1453                     }
1454                 }
1455
1456                 vlentry.nextNameHash = header.VolnameHash[hash];
1457                 header.VolnameHash[hash] = record[i].addr;
1458
1459                 for (j = 0; j < MAXTYPES; j++) {
1460
1461                     if (0 == vlentry.volumeId[j]) {
1462                         /*
1463                          * No volume of that type.  Continue
1464                          */
1465                         continue;
1466                     }
1467                     hash = IdHash(vlentry.volumeId[j]);
1468
1469                     if (vlentry.nextIdHash[j] != header.VolidHash[j][hash]) {
1470                         oldname = nameForAddr(vlentry.nextIdHash[j], j, &oldhash, oldNameBuffer);
1471                         newname = nameForAddr(header.VolidHash[j][hash], j, &newhash, newNameBuffer);
1472                         if (verbose || ((oldhash != newhash) &&
1473                                         (0 != vlentry.nextIdHash[j]) &&
1474                                         (0 != header.VolidHash[j][hash]))) {
1475                             quiet_println("FIX: %s hash link for '%s' was %s, is now %s\n",
1476                                           vtype(j), vlentry.name, oldname, newname);
1477                         }
1478                     }
1479
1480                     vlentry.nextIdHash[j] = header.VolidHash[j][hash];
1481                     header.VolidHash[j][hash] = record[i].addr;
1482                 }
1483                 writeentry(record[i].addr, &vlentry);
1484             }
1485         }
1486     }
1487     if (fix) {
1488         reportHashChanges(&header, oldnamehash, oldidhash);
1489         writeheader(&header);
1490     }
1491
1492     close(fd);
1493
1494     return error_level;
1495 }
1496
1497 int
1498 main(int argc, char **argv)
1499 {
1500     struct cmd_syndesc *ts;
1501
1502     setlinebuf(stdout);
1503
1504     ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "vldb check");
1505     cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "vldb_file");
1506     cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1507                 "Display UBIK header");
1508     cmd_AddParm(ts, "-vheader", CMD_FLAG, CMD_OPTIONAL,
1509                 "Display VLDB header");
1510     cmd_AddParm(ts, "-servers", CMD_FLAG, CMD_OPTIONAL,
1511                 "Display server list");
1512     cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1513     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1514     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL, "quiet");
1515     cmd_AddParm(ts, "-fix", CMD_FLAG, CMD_OPTIONAL, "attempt to patch the database (potentially dangerous)");
1516
1517     return cmd_Dispatch(argc, argv);
1518 }