vlserver: Use unsigned addresses
[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 = ntohs(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 & VLOP_MOVE)
429                 quiet_println(" lock_move");
430             if (vlentryp->flags & VLOP_RELEASE)
431                 quiet_println(" lock_release");
432             if (vlentryp->flags & VLOP_BACKUP)
433                 quiet_println(" lock_backup");
434             if (vlentryp->flags & VLOP_DELETE)
435                 quiet_println(" lock_delete");
436             if (vlentryp->flags & VLOP_DUMP)
437                 quiet_println(" lock_dump");
438
439             /* all bits not covered by VLF_* and VLOP_* constants */
440             if (vlentryp->flags & 0xffff8e0f)
441                 quiet_println(" errorflag(0x%x)", vlentryp->flags);
442             quiet_println("\n");
443             quiet_println("   LockAfsId     = %d\n", vlentryp->LockAfsId);
444             quiet_println("   LockTimestamp = %d\n", vlentryp->LockTimestamp);
445             quiet_println("   cloneId       = %u\n", vlentryp->cloneId);
446             quiet_println
447                 ("   next hash for rw = %u ; ro = %u ; bk = %u ; name = %u\n",
448                  vlentryp->nextIdHash[0], vlentryp->nextIdHash[1],
449                  vlentryp->nextIdHash[2], vlentryp->nextNameHash);
450             for (i = 0; i < NMAXNSERVERS; i++) {
451                 if (vlentryp->serverNumber[i] != 255) {
452                     quiet_println("   server %d ; partition %d ; flags =",
453                            vlentryp->serverNumber[i],
454                            vlentryp->serverPartition[i]);
455                     if (vlentryp->serverFlags[i] & VLSF_RWVOL)
456                         quiet_println(" rw");
457                     if (vlentryp->serverFlags[i] & VLSF_ROVOL)
458                         quiet_println(" ro");
459                     if (vlentryp->serverFlags[i] & VLSF_BACKVOL)
460                         quiet_println(" bk");
461                     if (vlentryp->serverFlags[i] & VLSF_NEWREPSITE)
462                         quiet_println(" newro");
463                     quiet_println("\n");
464                 }
465             }
466         }
467     }
468     return;
469 }
470
471 void
472 writeentry(afs_int32 addr, struct nvlentry *vlentryp)
473 {
474     int i;
475
476     if (verbose) quiet_println("Writing back entry at addr %u\n", addr);
477     for (i = 0; i < MAXTYPES; i++)
478         vlentryp->volumeId[i] = htonl(vlentryp->volumeId[i]);
479     vlentryp->flags = htonl(vlentryp->flags);
480     vlentryp->LockAfsId = htonl(vlentryp->LockAfsId);
481     vlentryp->LockTimestamp = htonl(vlentryp->LockTimestamp);
482     vlentryp->cloneId = htonl(vlentryp->cloneId);
483     for (i = 0; i < MAXTYPES; i++)
484         vlentryp->nextIdHash[i] = htonl(vlentryp->nextIdHash[i]);
485     vlentryp->nextNameHash = htonl(vlentryp->nextNameHash);
486     for (i = 0; i < NMAXNSERVERS; i++) {
487         /* make sure not to htonl these, as they're chars, not ints */
488         vlentryp->serverNumber[i] =  vlentryp->serverNumber[i] ;
489         vlentryp->serverPartition[i] = vlentryp->serverPartition[i] ;
490         vlentryp->serverFlags[i] = vlentryp->serverFlags[i] ;
491     }
492     vldbwrite(addr, (char *)vlentryp, sizeof(*vlentryp));
493 }
494
495 void
496 readSIT(int base, int addr)
497 {
498     int i, j, a;
499     char sitbuf[VL_ADDREXTBLK_SIZE];
500     struct extentaddr *extent;
501
502     if (!addr)
503         return;
504     vldbread(addr, sitbuf, VL_ADDREXTBLK_SIZE);
505     extent = (struct extentaddr *)sitbuf;
506
507     quiet_println("multihome info block: base %d\n", base);
508     if (base == 0) {
509         quiet_println("   count = %u\n", ntohl(extent->ex_count));
510         quiet_println("   flags = %u\n", ntohl(extent->ex_flags));
511         for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
512             quiet_println("   contaddrs[%d] = %u\n", i,
513                    ntohl(extent->ex_contaddrs[i]));
514         }
515     }
516     for (i = 1; i < VL_MHSRV_PERBLK; i++) {
517         /* should we skip this entry */
518         for (j = 0; j < VL_MAX_ADDREXTBLKS; j++) {
519             if (extent[i].ex_addrs[j])
520                 break;
521         }
522         if (j >= VL_MAX_ADDREXTBLKS)
523             continue;
524
525         quiet_println("   base %d index %d:\n", base, i);
526
527         quiet_println("       afsuuid    = (%x %x %x /%d/%d/ /%x/%x/%x/%x/%x/%x/)\n",
528                ntohl(extent[i].ex_hostuuid.time_low),
529                ntohl(extent[i].ex_hostuuid.time_mid),
530                ntohl(extent[i].ex_hostuuid.time_hi_and_version),
531                ntohl(extent[i].ex_hostuuid.clock_seq_hi_and_reserved),
532                ntohl(extent[i].ex_hostuuid.clock_seq_low),
533                ntohl(extent[i].ex_hostuuid.node[0]),
534                ntohl(extent[i].ex_hostuuid.node[1]),
535                ntohl(extent[i].ex_hostuuid.node[2]),
536                ntohl(extent[i].ex_hostuuid.node[3]),
537                ntohl(extent[i].ex_hostuuid.node[4]),
538                ntohl(extent[i].ex_hostuuid.node[5]));
539         quiet_println("       uniquifier = %u\n", ntohl(extent[i].ex_uniquifier));
540         for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
541             a = ntohl(extent[i].ex_addrs[j]);
542             if (a) {
543                 quiet_println("       %d.%d.%d.%d\n", (a >> 24) & 0xff,
544                        (a >> 16) & 0xff, (a >> 8) & 0xff, (a) & 0xff);
545             }
546         }
547     }
548 }
549
550 /*
551  * Read each entry in the database:
552  * Record what type of entry it is and its address in the record array.
553  * Remember what the maximum volume id we found is and check against the header.
554  */
555 void
556 ReadAllEntries(struct vlheader *header)
557 {
558     afs_int32 type, rindex, i, j, e;
559     int freecount = 0, mhcount = 0, vlcount = 0;
560     int rwcount = 0, rocount = 0, bkcount = 0;
561     struct nvlentry vlentry;
562     afs_uint32 addr;
563     afs_uint32 entrysize = 0;
564     afs_uint32 maxvolid = 0;
565
566     if (verbose) quiet_println("Read each entry in the database\n");
567     for (addr = header->vital_header.headersize;
568          addr < header->vital_header.eofPtr; addr += entrysize) {
569
570         /* Remember the highest volume id */
571         readentry(addr, &vlentry, &type);
572         if (type == VL) {
573             if (!(vlentry.flags & VLF_RWEXISTS))
574                 log_error(VLDB_CHECK_WARNING,"VLDB_CHECK_WARNING: VLDB entry '%s' has no RW volume\n",
575                        vlentry.name);
576
577             for (i = 0; i < MAXTYPES; i++)
578                 if (maxvolid < vlentry.volumeId[i])
579                     maxvolid = vlentry.volumeId[i];
580
581             e = 1;
582             for (j = 0; j < NMAXNSERVERS; j++) {
583                 if (vlentry.serverNumber[j] == 255)
584                     continue;
585                 if (vlentry.serverFlags[j] & (VLSF_ROVOL | VLSF_NEWREPSITE)) {
586                     rocount++;
587                     continue;
588                 }
589                 if (vlentry.serverFlags[j] & VLSF_RWVOL) {
590                     rwcount++;
591                     if (vlentry.flags & VLF_BACKEXISTS)
592                         bkcount++;
593                     continue;
594                 }
595                 if (!vlentry.serverFlags[j]) {
596                     /*e = 0;*/
597                     continue;
598                 }
599                 if (e) {
600                    log_error 
601                         (VLDB_CHECK_ERROR,"VLDB entry '%s' contains an unknown RW/RO index serverFlag\n",
602                          vlentry.name);
603                     e = 0;
604                 }
605                 quiet_println
606                     ("   index %d : serverNumber %d : serverPartition %d : serverFlag %d\n",
607                      j, vlentry.serverNumber[j], vlentry.serverPartition[j],
608                      vlentry.serverFlags[j]);
609             }
610         }
611
612         rindex = addr / sizeof(vlentry);
613         if (record[rindex].type) {
614             log_error(VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: record holder %d already in use\n",
615                    rindex);
616             return;
617         }
618         record[rindex].addr = addr;
619         record[rindex].type = type;
620
621         /* Determine entrysize and keep count */
622         if (type == VL) {
623             entrysize = sizeof(vlentry);
624             vlcount++;
625         } else if (type == FR) {
626             entrysize = sizeof(vlentry);
627             freecount++;
628         } else if (type == MH) {
629             entrysize = VL_ADDREXTBLK_SIZE;
630             mhcount++;
631         } else {
632             log_error(VLDB_CHECK_ERROR, "Unknown entry at %u. Aborting\n", addr);
633             break;
634         }
635     }
636     if (verbose) {
637         quiet_println("Found %d entries, %d free entries, %d multihomed blocks\n",
638                vlcount, freecount, mhcount);
639         quiet_println("Found %d RW volumes, %d BK volumes, %d RO volumes\n", rwcount,
640                bkcount, rocount);
641     }
642
643     /* Check the maxmimum volume id in the header */
644     if (maxvolid != header->vital_header.MaxVolumeId - 1)
645         quiet_println
646             ("Header's maximum volume id is %u and largest id found in VLDB is %u\n",
647              header->vital_header.MaxVolumeId, maxvolid);
648 }
649
650 /*
651  * Follow each Name hash bucket marking it as read in the record array.
652  * Record we found it in the name hash within the record array.
653  * Check that the name is hashed correctly.
654  */
655 void
656 FollowNameHash(struct vlheader *header)
657 {
658     int count = 0, longest = 0, shortest = -1, chainlength;
659     struct nvlentry vlentry;
660     afs_uint32 addr;
661     afs_int32 i, type, rindex;
662
663     /* Now follow the Name Hash Table */
664     if (verbose) quiet_println("Check Volume Name Hash\n");
665     for (i = 0; i < HASHSIZE; i++) {
666         chainlength = 0;
667
668         if (!validVolumeAddr(header->VolnameHash[i])) {
669             log_error(VLDB_CHECK_ERROR,"Name Hash %d: Bad entry %u is out of range\n",
670                       i, header->VolnameHash[i]);
671             continue;
672         }
673
674         for (addr = header->VolnameHash[i]; addr; addr = vlentry.nextNameHash) {
675             readentry(addr, &vlentry, &type);
676             if (type != VL) {
677                 log_error(VLDB_CHECK_ERROR,"Name Hash %d: Bad entry at %u: Not a valid vlentry\n",
678                        i, addr);
679                 continue;
680             }
681
682             rindex = ADDR(addr);
683
684             /*
685              * we know that the address is valid because we
686              * checked it either above or below
687              */
688             if (record[rindex].addr != addr && record[rindex].addr) {
689                 log_error       
690                     (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
691                      record[rindex].addr, addr, rindex);
692             }
693             if (record[rindex].type & NH) {
694                 log_error       
695                     (VLDB_CHECK_ERROR,"Name Hash %d: Bad entry '%s': Already in the name hash\n",
696                      i, vlentry.name);
697                 record[rindex].type |= MULTN;
698                 break;
699             }
700
701             if (!validVolumeAddr(vlentry.nextNameHash)) {
702                 log_error(VLDB_CHECK_ERROR,"Name Hash forward link of '%s' is out of range\n",
703                           vlentry.name);
704                 record[rindex].type |= MULTN;
705                 break;
706             }
707
708             record[rindex].type |= NH;
709             record[rindex].type |= REFN;
710
711             chainlength++;
712             count++;
713
714             /* Hash the name and check if in correct hash table */
715             if (NameHash(vlentry.name) != i) {
716                 log_error       
717                     (VLDB_CHECK_ERROR,"Name Hash %d: Bad entry '%s': Incorrect name hash chain (should be in %d)\n",
718                      i, vlentry.name, NameHash(vlentry.name));
719                 record[rindex].type |= MULTN;
720             }
721         }
722         if (chainlength > longest)
723             longest = chainlength;
724         if ((shortest == -1) || (chainlength < shortest))
725             shortest = chainlength;
726     }
727     if (verbose) {
728         quiet_println
729             ("%d entries in name hash, longest is %d, shortest is %d, average length is %f\n",
730              count, longest, shortest, ((float)count / (float)HASHSIZE));
731     }
732     return;
733 }
734
735 /*
736  * Follow the ID hash chains for the RW, RO, and BK hash tables.
737  * Record we found it in the id hash within the record array.
738  * Check that the ID is hashed correctly.
739  */
740 void
741 FollowIdHash(struct vlheader *header)
742 {
743     int count = 0, longest = 0, shortest = -1, chainlength;
744     struct nvlentry vlentry;
745     afs_uint32 addr;
746     afs_int32 i, j, hash, type, rindex, ref, badref, badhash;
747
748     /* Now follow the RW, RO, and BK Hash Tables */
749     if (verbose) quiet_println("Check RW, RO, and BK id Hashes\n");
750     for (i = 0; i < MAXTYPES; i++) {
751         hash = ((i == 0) ? RWH : ((i == 1) ? ROH : BKH));
752         ref = ((i == 0) ? REFRW : ((i == 1) ? REFRO : REFBK));
753         badref = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
754         badhash = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
755         count = longest = 0;
756         shortest = -1;
757
758         for (j = 0; j < HASHSIZE; j++) {
759             chainlength = 0;
760             if (!validVolumeAddr(header->VolidHash[i][j])) {
761                 log_error(VLDB_CHECK_ERROR,"%s Hash %d: Bad entry %u is out of range\n",
762                           vtype(i), j, header->VolidHash[i][j]);
763                 continue;
764             }
765
766             for (addr = header->VolidHash[i][j]; addr;
767                  addr = vlentry.nextIdHash[i]) {
768                 readentry(addr, &vlentry, &type);
769                 if (type != VL) {
770                     log_error
771                         (VLDB_CHECK_ERROR,"%s Id Hash %d: Bad entry at %u: Not a valid vlentry\n",
772                          vtype(i), j, addr);
773                     continue;
774                 }
775
776                 rindex = ADDR(addr);
777                 if (record[rindex].addr != addr && record[rindex].addr) {
778                     log_error
779                         (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
780                          record[rindex].addr, addr, rindex);
781                 }
782                 if (record[rindex].type & hash) {
783                     log_error
784                         (VLDB_CHECK_ERROR,"%s Id Hash %d: Bad entry '%s': Already in the hash table\n",
785                          vtype(i), j, vlentry.name);
786                     record[rindex].type |= badref;
787                     break;
788                 }
789
790                 if (!validVolumeAddr(vlentry.nextIdHash[i])) {
791                     log_error(VLDB_CHECK_ERROR,"%s Id Hash forward link of '%s' is out of range\n",
792                               vtype(i), vlentry.name);
793                     record[rindex].type |= badref;
794                     break;
795                 }
796
797                 record[rindex].type |= hash;
798                 record[rindex].type |= ref;
799
800                 chainlength++;
801                 count++;
802
803                 /* Hash the id and check if in correct hash table */
804                 if (IdHash(vlentry.volumeId[i]) != j) {
805                    log_error 
806                         (VLDB_CHECK_ERROR,"%s Id Hash %d: Bad entry '%s': Incorrect Id hash chain (should be in %d)\n",
807                          vtype(i), j, vlentry.name,
808                          IdHash(vlentry.volumeId[i]));
809                     record[rindex].type |= badhash;
810                 }
811             }
812
813             if (chainlength > longest)
814                 longest = chainlength;
815             if ((shortest == -1) || (chainlength < shortest))
816                 shortest = chainlength;
817         }
818         if (verbose) {
819             quiet_println
820                 ("%d entries in %s hash, longest is %d, shortest is %d, average length is %f\n",
821                  count, vtype(i), longest, shortest,((float)count / (float)HASHSIZE));
822         }
823     }
824     return;
825 }
826
827 /*
828  * Follow the free chain.
829  * Record we found it in the free chain within the record array.
830  */
831 void
832 FollowFreeChain(struct vlheader *header)
833 {
834     afs_int32 count = 0;
835     struct nvlentry vlentry;
836     afs_uint32 addr;
837     afs_int32 type, rindex;
838
839     /* Now follow the Free Chain */
840     if (verbose) quiet_println("Check Volume Free Chain\n");
841     for (addr = header->vital_header.freePtr; addr;
842          addr = vlentry.nextIdHash[0]) {
843         readentry(addr, &vlentry, &type);
844         if (type != FR) {
845            log_error 
846                 (VLDB_CHECK_ERROR,"Free Chain %d: Bad entry at %u: Not a valid free vlentry (0x%x)\n",
847                  count, addr, type);
848             continue;
849         }
850
851         rindex = addr / sizeof(vlentry);
852         if (record[rindex].addr != addr && record[rindex].addr) {
853            log_error 
854                 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u and %ld use same record slot %d\n",
855                  record[rindex].addr, addr, rindex);
856         }
857         if (record[rindex].type & FRC) {
858             log_error(VLDB_CHECK_ERROR,"Free Chain: Bad entry at %u: Already in the free chain\n",
859                    addr);
860             break;
861         }
862         record[rindex].type |= FRC;
863
864         count++;
865     }
866     if (verbose)
867      quiet_println("%d entries on free chain\n", count);
868     return;
869 }
870
871 /*
872  * Read each multihomed block and mark it as found in the record.
873  * Read each entry in each multihomed block and mark the serveraddrs
874  * array with the number of ip addresses found for this entry.
875  * 
876  * Then read the IpMappedAddr array in the header.
877  * Verify that multihomed entries base and index are valid and points to
878  * a good multhomed entry.
879  * Mark the serveraddrs array with 1 ip address for regular entries.
880  * 
881  * By the end, the severaddrs array will have a 0 if the entry has no 
882  * IP addresses in it or the count of the number of IP addresses.
883  *
884  * The code does not verify if there are duplicate IP addresses in the 
885  * list. The vlserver does this when a fileserver registeres itself.
886  */
887 void
888 CheckIpAddrs(struct vlheader *header)
889 {
890     int mhblocks = 0;
891     afs_int32 i, j, m, rindex;
892     afs_int32 mhentries, regentries;
893     afs_uint32 caddrs[VL_MAX_ADDREXTBLKS];
894     char mhblock[VL_ADDREXTBLK_SIZE];
895     struct extentaddr *MHblock = (struct extentaddr *)mhblock;
896     struct extentaddr *e;
897     int ipindex, ipaddrs;
898     afsUUID nulluuid;
899
900     memset(&nulluuid, 0, sizeof(nulluuid));
901
902     if (verbose)
903         quiet_println("Check Multihomed blocks\n");
904
905     if (header->SIT) {
906         /* Read the first MH block and from it, gather the 
907          * addresses of all the mh blocks.
908          */
909         readMH(header->SIT, MHblock);
910         if (MHblock->ex_flags != VLCONTBLOCK) {
911            log_error 
912                 (VLDB_CHECK_ERROR,"Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
913                  header->SIT);
914         }
915
916         for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
917             caddrs[i] = MHblock->ex_contaddrs[i];
918         }
919
920         if (header->SIT != caddrs[0]) {
921            log_error 
922                 (VLDB_CHECK_ERROR,"MH block does not point to self %u in header, %u in block\n",
923                  header->SIT, caddrs[0]);
924         }
925
926         /* Now read each MH block and record it in the record array */
927         for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
928             if (!caddrs[i])
929                 continue;
930
931             readMH(caddrs[i], MHblock);
932             if (MHblock->ex_flags != VLCONTBLOCK) {
933                 log_error       
934                     (VLDB_CHECK_ERROR,"Multihomed Block 0: Bad entry at %u: Not a valid multihomed block\n",
935                      header->SIT);
936             }
937
938             rindex = caddrs[i] / sizeof(vlentry);
939             if (record[rindex].addr != caddrs[i] && record[rindex].addr) {
940                 log_error       
941                     (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u and %u use same record slot %d\n",
942                      record[rindex].addr, caddrs[i], rindex);
943             }
944             if (record[rindex].type & FRC) {
945                 log_error       
946                     (VLDB_CHECK_ERROR,"MH Blocks Chain %d: Bad entry at %ld: Already a MH block\n",
947                      i, record[rindex].addr);
948                 break;
949             }
950             record[rindex].type |= MHC;
951
952             mhblocks++;
953
954             /* Read each entry in a multihomed block. 
955              * Find the pointer to the entry in the IpMappedAddr array and
956              * verify that the entry is good (has IP addresses in it).
957              */
958             mhentries = 0;
959             for (j = 1; j < VL_MHSRV_PERBLK; j++) {
960                 e = (struct extentaddr *)&(MHblock[j]);
961
962                 /* Search the IpMappedAddr array for the reference to this entry */
963                 for (ipindex = 0; ipindex < MAXSERVERID; ipindex++) {
964                     if (((header->IpMappedAddr[ipindex] & 0xff000000) ==
965                          0xff000000)
966                         &&
967                         (((header->
968                            IpMappedAddr[ipindex] & 0x00ff0000) >> 16) == i)
969                         && ((header->IpMappedAddr[ipindex] & 0x0000ffff) ==
970                             j)) {
971                         break;
972                     }
973                 }
974                 if (ipindex >= MAXSERVERID)
975                     ipindex = -1;
976                 else
977                     serveraddrs[ipindex] = -1;
978
979                 if (memcmp(&e->ex_hostuuid, &nulluuid, sizeof(afsUUID)) == 0) {
980                     if (ipindex != -1) {
981                         log_error       
982                             (VLDB_CHECK_ERROR,"Server Addrs index %d references null MH block %d, index %d\n",
983                              ipindex, i, j);
984                         serveraddrs[ipindex] = 0;       /* avoids printing 2nd error below */
985                     }
986                     continue;
987                 }
988
989                 /* Step through each ip address and count the good addresses */
990                 ipaddrs = 0;
991                 for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
992                     if (e->ex_addrs[m])
993                         ipaddrs++;
994                 }
995
996                 /* If we found any good ip addresses, mark it in the serveraddrs record */
997                 if (ipaddrs) {
998                     mhentries++;
999                     if (ipindex == -1) {
1000                         log_error       
1001                             (VLDB_CHECK_ERROR,"MH block %d, index %d: Not referenced by server addrs\n",
1002                              i, j);
1003                     } else {
1004                         serveraddrs[ipindex] = ipaddrs; /* It is good */
1005                     }
1006                 }
1007
1008                 if (listservers && ipaddrs) {
1009                     quiet_println("MH block %d, index %d:", i, j);
1010                     for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
1011                         if (!e->ex_addrs[m])
1012                             continue;
1013                         quiet_println(" %d.%d.%d.%d",
1014                                (e->ex_addrs[m] & 0xff000000) >> 24,
1015                                (e->ex_addrs[m] & 0x00ff0000) >> 16,
1016                                (e->ex_addrs[m] & 0x0000ff00) >> 8,
1017                                (e->ex_addrs[m] & 0x000000ff));
1018                     }
1019                     quiet_println("\n");
1020                 }
1021             }
1022 /*
1023  *      if (mhentries != MHblock->ex_count) {
1024  *         quiet_println("MH blocks says it has %d entries (found %d)\n",
1025  *                MHblock->ex_count, mhentries);
1026  *      }
1027  */
1028         }
1029     }
1030     if (verbose)
1031         quiet_println("%d multihomed blocks\n", mhblocks);
1032
1033     /* Check the server addresses */
1034     if (verbose)
1035         quiet_println("Check server addresses\n");
1036     mhentries = regentries = 0;
1037     for (i = 0; i <= MAXSERVERID; i++) {
1038         if (header->IpMappedAddr[i]) {
1039             if ((header->IpMappedAddr[i] & 0xff000000) == 0xff000000) {
1040                 mhentries++;
1041                 if (((header->IpMappedAddr[i] & 0x00ff0000) >> 16) >
1042                     VL_MAX_ADDREXTBLKS)
1043                    log_error 
1044                         (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome block is bad (%d)\n",
1045                          i, ((header->IpMappedAddr[i] & 0x00ff0000) >> 16));
1046                 if (((header->IpMappedAddr[i] & 0x0000ffff) > VL_MHSRV_PERBLK)
1047                     || ((header->IpMappedAddr[i] & 0x0000ffff) < 1))
1048                     log_error 
1049                         (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome index is bad (%d)\n",
1050                          i, (header->IpMappedAddr[i] & 0x0000ffff));
1051                 if (serveraddrs[i] == -1) {
1052                     log_error 
1053                         (VLDB_CHECK_WARNING,"warning: IP Addr for entry %d: Multihome entry has no ip addresses\n",
1054                          i);
1055                     serveraddrs[i] = 0;
1056                 }
1057                 if (listservers) {
1058                     quiet_println("   Server ip addr %d = MH block %d, index %d\n",
1059                            i, (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1060                            (header->IpMappedAddr[i] & 0x0000ffff));
1061                 }
1062             } else {
1063                 regentries++;
1064                 serveraddrs[i] = 1;     /* It is good */
1065                 if (listservers) {
1066                     quiet_println("   Server ip addr %d = %d.%d.%d.%d\n", i,
1067                            (header->IpMappedAddr[i] & 0xff000000) >> 24,
1068                            (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1069                            (header->IpMappedAddr[i] & 0x0000ff00) >> 8,
1070                            (header->IpMappedAddr[i] & 0x000000ff));
1071                 }
1072             }
1073         }
1074     }
1075     if (verbose) {
1076         quiet_println("%d simple entries, %d multihomed entries, Total = %d\n",
1077                regentries, mhentries, mhentries + regentries);
1078     }
1079     return;
1080 }
1081
1082 char *
1083 nameForAddr(afs_uint32 addr, int hashtype, afs_uint32 *hash, char *buffer)
1084 {
1085     /*
1086      * We need to simplify the reporting, while retaining
1087      * legible messages.  This is a helper function.  The return address
1088      * is either a fixed char or the provided buffer - so don't use the
1089      * name after the valid lifetime of the buffer.
1090      */
1091     afs_int32 type;
1092     struct nvlentry entry;
1093     if (!addr) {
1094         /* Distinguished, invalid, hash */
1095         *hash = 0xFFFFFFFF;
1096         return "empty";
1097     } else if (!validVolumeAddr(addr)) {
1098         /* Different, invalid, hash */
1099         *hash = 0XFFFFFFFE;
1100         return "invalid";
1101     }
1102     readentry(addr, &entry, &type);
1103     if (VL != type) {
1104         *hash = 0XFFFFFFFE;
1105         return "invalid";
1106     }
1107     if (hashtype >= MAXTYPES) {
1108         *hash = NameHash(entry.name);
1109     } else {
1110         *hash = IdHash(entry.volumeId[hashtype]);
1111     }
1112     sprintf(buffer, "for '%s'", entry.name);
1113     return buffer;
1114 }
1115
1116 void
1117 reportHashChanges(struct vlheader *header, afs_uint32 oldnamehash[HASHSIZE], afs_uint32 oldidhash[MAXTYPES][HASHSIZE])
1118 {
1119     int i, j;
1120     afs_uint32 oldhash, newhash;
1121     char oldNameBuffer[10 + VL_MAXNAMELEN];
1122     char newNameBuffer[10 + VL_MAXNAMELEN];
1123     char *oldname, *newname;
1124     /*
1125      * report hash changes
1126      */
1127
1128     for (i = 0; i < HASHSIZE; i++) {
1129         if (oldnamehash[i] != header->VolnameHash[i]) {
1130
1131             oldname = nameForAddr(oldnamehash[i], MAXTYPES, &oldhash, oldNameBuffer);
1132             newname = nameForAddr(header->VolnameHash[i], MAXTYPES, &newhash, newNameBuffer);
1133             if (verbose || (oldhash != newhash)) {
1134                 quiet_println("FIX: Name hash header at %d was %s, is now %s\n", i, oldname, newname);
1135             }
1136         }
1137         for (j = 0; j < MAXTYPES; j++) {
1138             if (oldidhash[j][i] != header->VolidHash[j][i]) {
1139
1140                 oldname = nameForAddr(oldidhash[j][i], j, &oldhash, oldNameBuffer);
1141                 newname = nameForAddr(header->VolidHash[j][i], j, &newhash, newNameBuffer);
1142                 if (verbose || (oldhash != newhash)) {
1143                     quiet_println("FIX: %s hash header at %d was %s, is now %s\n", vtype(j), i, oldname, newname);
1144                 }
1145             }
1146         }
1147     }
1148 }
1149
1150 int
1151 WorkerBee(struct cmd_syndesc *as, void *arock)
1152 {
1153     char *dbfile;
1154     afs_int32 type;
1155     struct vlheader header;
1156     struct nvlentry vlentry, vlentry2;
1157     int i, j;
1158     afs_uint32 oldnamehash[HASHSIZE];
1159     afs_uint32 oldidhash[MAXTYPES][HASHSIZE];
1160
1161     error_level = 0;  /*  start clean with no error status */
1162     dbfile = as->parms[0].items->data;  /* -database */
1163     listuheader = (as->parms[1].items ? 1 : 0); /* -uheader  */
1164     listheader = (as->parms[2].items ? 1 : 0);  /* -vheader  */
1165     listservers = (as->parms[3].items ? 1 : 0); /* -servers  */
1166     listentries = (as->parms[4].items ? 1 : 0); /* -entries  */
1167     verbose = (as->parms[5].items ? 1 : 0);     /* -verbose  */
1168     quiet = (as->parms[6].items ? 1 : 0);  /* -quiet */
1169     fix = (as->parms[7].items ? 1 : 0);    /* -fix  */
1170
1171     /* sanity check */
1172     if (quiet && (verbose || listuheader || listheader ||listservers \
1173                 || listentries)) {
1174         log_error(VLDB_CHECK_FATAL," -quiet cannot be used other display flags\n");
1175         return VLDB_CHECK_FATAL;
1176     }
1177
1178
1179     /* open the vldb database file */
1180     fd = open(dbfile, (fix > 0)?O_RDWR:O_RDONLY, 0);
1181     if (fd < 0) {
1182         log_error(VLDB_CHECK_FATAL,"can't open file '%s'. error = %d\n", dbfile, errno);
1183         return 0;
1184     }
1185
1186     /* read the ubik header and the vldb database header */
1187     readUbikHeader();
1188     readheader(&header);
1189     if (header.vital_header.vldbversion < 3) {
1190         log_error(VLDB_CHECK_FATAL,"does not support vldb with version less than 3\n");
1191         return VLDB_CHECK_FATAL;
1192     }
1193
1194     maxentries = (header.vital_header.eofPtr / sizeof(vlentry)) + 1;
1195     record = (struct er *)malloc(maxentries * sizeof(struct er));
1196     memset(record, 0, (maxentries * sizeof(struct er)));
1197     memset(serveraddrs, 0, sizeof(serveraddrs));
1198
1199     /* Will fill in the record array of entries it found */
1200     ReadAllEntries(&header);
1201     listentries = 0;            /* Listed all the entries */
1202
1203     /* Check the multihomed blocks for valid entries as well as
1204      * the IpMappedAddrs array in the header for valid entries.
1205      */
1206     CheckIpAddrs(&header);
1207
1208     /* Follow the hash tables */
1209     FollowNameHash(&header);
1210     FollowIdHash(&header);
1211
1212     /* Follow the chain of free entries */
1213     FollowFreeChain(&header);
1214
1215     /* Now check the record we have been keeping for inconsistencies
1216      * For valid vlentries, also check that the server we point to is 
1217      * valid (the serveraddrs array).
1218      */
1219     if (verbose)
1220         quiet_println("Verify each volume entry\n");
1221     for (i = 0; i < maxentries; i++) {
1222         int nextp = 0;
1223         int reft = 0;
1224         int hash = 0;
1225         int nexthash = 0;
1226         int *nextpp = NULL;
1227         char *which = NULL;
1228
1229         if (record[i].type == 0)
1230             continue;
1231
1232         /* If a vlentry, verify that its name is valid, its name and ids are
1233          * on the hash chains, and its server numbers are good.
1234          */
1235         if (record[i].type & VL) {
1236             int foundbad = 0;
1237             int foundbroken = 0;
1238             char volidbuf[256];
1239
1240             readentry(record[i].addr, &vlentry, &type);
1241
1242             if (InvalidVolname(vlentry.name))
1243                 log_error(VLDB_CHECK_ERROR,"Volume '%s' at addr %ld has an invalid name\n",
1244                        vlentry.name, record[i].addr);
1245
1246             if (!(record[i].type & NH)) {
1247                 nextp = ADDR(vlentry.nextNameHash);
1248                 reft = REFN;
1249                 hash = NameHash(vlentry.name);
1250                 nextpp = &vlentry.nextNameHash;
1251                 which = "name";
1252                 volidbuf[0]='\0';
1253                 foundbad = 1;
1254             }
1255
1256             if (vlentry.volumeId[0] && !(record[i].type & RWH)) {
1257                 nextp = ADDR(vlentry.nextIdHash[0]);
1258                 reft = REFRW;
1259                 hash = IdHash(vlentry.volumeId[0]);
1260                 nextpp = &(vlentry.nextIdHash[0]);
1261                 which = "RW";
1262                 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1263                 foundbad = 1;
1264             }
1265
1266             if (vlentry.volumeId[1] && !(record[i].type & ROH)) {
1267                 nextp = ADDR(vlentry.nextIdHash[1]);
1268                 reft = REFRO;
1269                 hash = IdHash(vlentry.volumeId[1]);
1270                 nextpp = &(vlentry.nextIdHash[1]);
1271                 which = "RO";
1272                 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1273                 foundbad = 1;
1274             }
1275
1276             if (vlentry.volumeId[2] && !(record[i].type & BKH)) {
1277                 nextp = ADDR(vlentry.nextIdHash[2]);
1278                 reft = REFBK;
1279                 hash = IdHash(vlentry.volumeId[2]);
1280                 nextpp = &(vlentry.nextIdHash[2]);
1281                 which = "BK";
1282                 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1283                 foundbad = 1;
1284             }
1285
1286             if (!validVolumeAddr(vlentry.nextNameHash) ||
1287                 record[ADDR(vlentry.nextNameHash)].type & MULTN) {
1288                 nextp = ADDR(vlentry.nextNameHash);
1289                 reft = REFN;
1290                 hash = NameHash(vlentry.name);
1291                 nextpp = &vlentry.nextNameHash;
1292                 which = "name";
1293                 volidbuf[0]='\0';
1294                 if (validVolumeAddr(vlentry.nextNameHash)) {
1295                     readentry(vlentry.nextNameHash, &vlentry2, &type);
1296                     nexthash = NameHash(vlentry2.name);
1297                 } else {
1298                     nexthash = 0xFFFFFFFF;
1299                 }
1300                 if (hash != nexthash)
1301                     foundbroken = 1;
1302             }
1303
1304             if (!validVolumeAddr(vlentry.nextIdHash[0]) ||
1305                 record[ADDR(vlentry.nextIdHash[0])].type & MULTRW) {
1306                 nextp = ADDR(vlentry.nextIdHash[0]);
1307                 reft = REFRW;
1308                 hash = IdHash(vlentry.volumeId[0]);
1309                 nextpp = &(vlentry.nextIdHash[0]);
1310                 which = "RW";
1311                 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1312                 if (validVolumeAddr(vlentry.nextIdHash[0])) {
1313                     readentry(vlentry.nextIdHash[0], &vlentry2, &type);
1314                     nexthash = IdHash(vlentry2.volumeId[0]);
1315                 } else {
1316                     nexthash = 0xFFFFFFFF;
1317                 }
1318                 if (hash != nexthash)
1319                     foundbroken = 1;
1320             }
1321
1322             if (!validVolumeAddr(vlentry.nextIdHash[1]) ||
1323                 record[ADDR(vlentry.nextIdHash[1])].type & MULTRO) {
1324                 nextp = ADDR(vlentry.nextIdHash[1]);
1325                 reft = REFRO;
1326                 hash = IdHash(vlentry.volumeId[1]);
1327                 nextpp = &(vlentry.nextIdHash[1]);
1328                 which = "RO";
1329                 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1330                 if (validVolumeAddr(vlentry.nextIdHash[1])) {
1331                     readentry(vlentry.nextIdHash[1], &vlentry2, &type);
1332                     nexthash = IdHash(vlentry2.volumeId[1]);
1333                 } else {
1334                     nexthash = 0xFFFFFFFF;
1335                 }
1336                 if (hash != nexthash)
1337                     foundbroken = 1;
1338             }
1339
1340             if (!validVolumeAddr(vlentry.nextIdHash[2]) ||
1341                 record[ADDR(vlentry.nextIdHash[2])].type & MULTBK) {
1342                 nextp = ADDR(vlentry.nextIdHash[2]);
1343                 reft = REFBK;
1344                 hash = IdHash(vlentry.volumeId[2]);
1345                 nextpp = &(vlentry.nextIdHash[2]);
1346                 which = "BK";
1347                 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1348                 if (validVolumeAddr(vlentry.nextIdHash[2])) {
1349                     readentry(vlentry.nextIdHash[2], &vlentry2, &type);
1350                     nexthash = IdHash(vlentry2.volumeId[2]);
1351                 } else {
1352                     nexthash = 0xFFFFFFFF;
1353                 }
1354                 if (hash != nexthash)
1355                     foundbroken = 1;
1356             }
1357
1358             if (foundbroken) {
1359                 log_error(VLDB_CHECK_ERROR, "%d: Volume '%s' %s forward link in %s hash chain is broken (hash %d != %d)\n", i,
1360                           vlentry.name, volidbuf, which, hash, nexthash);
1361             } else if (foundbad) {
1362                 log_error(VLDB_CHECK_ERROR, "%d: Volume '%s' %snot found in %s hash %d\n", i,
1363                        vlentry.name, volidbuf, which, hash);
1364             }
1365
1366             for (j = 0; j < NMAXNSERVERS; j++) {
1367                 if ((vlentry.serverNumber[j] != 255)
1368                     && (serveraddrs[vlentry.serverNumber[j]] == 0)) {
1369                    log_error 
1370                         (VLDB_CHECK_ERROR,"Volume '%s', index %d points to empty server entry %d\n",
1371                          vlentry.name, j, vlentry.serverNumber[j]);
1372                 }
1373             }
1374         
1375             if (record[i].type & 0xffff0f00)
1376                 log_error       
1377                     (VLDB_CHECK_ERROR,"Volume '%s' id %u also found on other chains (0x%x)\n",
1378                      vlentry.name, vlentry.volumeId[0], record[i].type);
1379             
1380             /* A free entry */
1381         } else if (record[i].type & FR) {
1382             if (!(record[i].type & FRC))
1383                 log_error(VLDB_CHECK_ERROR,"Free vlentry at %ld not on free chain\n",
1384                        record[i].addr);
1385             
1386             if (record[i].type & 0xfffffdf0)
1387                 log_error       
1388                     (VLDB_CHECK_ERROR,"Free vlentry at %ld also found on other chains (0x%x)\n",
1389                      record[i].addr, record[i].type);
1390             
1391             /* A multihomed entry */
1392         } else if (record[i].type & MH) {
1393             if (!(record[i].type & MHC))
1394                 log_error(VLDB_CHECK_ERROR,"Multihomed block at %ld is orphaned\n",
1395                        record[i].addr);
1396             
1397             if (record[i].type & 0xfffffef0)
1398                 log_error       
1399                     (VLDB_CHECK_ERROR,"Multihomed block at %ld also found on other chains (0x%x)\n",
1400                      record[i].addr, record[i].type);
1401             
1402         } else {
1403             log_error(VLDB_CHECK_ERROR,"Unknown entry type at %u (0x%x)\n", record[i].addr,
1404                    record[i].type);
1405         }
1406     }
1407
1408     if (fix) {
1409         /*
1410          * If we are fixing we will rebuild all the hash lists from the ground up
1411          */
1412         memcpy(oldnamehash, header.VolnameHash, sizeof(oldnamehash));
1413         memset(header.VolnameHash, 0, sizeof(header.VolnameHash));
1414
1415         memcpy(oldidhash, header.VolidHash, sizeof(oldidhash));
1416         memset(header.VolidHash, 0, sizeof(header.VolidHash));
1417         quiet_println("Rebuilding %u entries\n", maxentries);
1418     } else {
1419         quiet_println("Scanning %u entries for possible repairs\n", maxentries);
1420     }
1421     for (i = 0; i < maxentries; i++) {
1422         afs_uint32 hash;
1423         if (record[i].type & VL) {
1424             readentry(record[i].addr, &vlentry, &type);
1425             if (!(record[i].type & REFN)) {
1426                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a name chain\n", i, 
1427                        record[i].addr, record[i].type);
1428             }
1429             if (vlentry.volumeId[0] && !(record[i].type & REFRW)) {
1430                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a RW chain\n", i,
1431                        record[i].addr, record[i].type);
1432             }
1433             if (vlentry.volumeId[1] && !(record[i].type & REFRO)) {
1434                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a RO chain\n", i, 
1435                        record[i].addr, record[i].type);
1436             }
1437             if (vlentry.volumeId[2] && !(record[i].type & REFBK)) {
1438                 log_error(VLDB_CHECK_ERROR,"%d: Record %ld (type 0x%x) not in a BK chain\n", i, 
1439                        record[i].addr, record[i].type);
1440             }
1441             if (fix) {
1442                 afs_uint32 oldhash, newhash;
1443                 char oldNameBuffer[10 + VL_MAXNAMELEN];
1444                 char newNameBuffer[10 + VL_MAXNAMELEN];
1445                 char *oldname, *newname;
1446
1447                 /*
1448                  * Put the current hash table contexts into our 'next'
1449                  * and our address into the hash table.
1450                  */
1451                 hash = NameHash(vlentry.name);
1452
1453                 if (vlentry.nextNameHash != header.VolnameHash[hash]) {
1454                     oldname = nameForAddr(vlentry.nextNameHash, MAXTYPES, &oldhash, oldNameBuffer);
1455                     newname = nameForAddr(header.VolnameHash[hash], MAXTYPES, &newhash, newNameBuffer);
1456                     if (verbose || ((oldhash != newhash) &&
1457                                     (0 != vlentry.nextNameHash) &&
1458                                     (0 != header.VolnameHash[hash]))) {
1459                         /*
1460                          * That is, only report if we are verbose
1461                          * or the hash is changing (and one side wasn't NULL
1462                          */
1463                         quiet_println("FIX: Name hash link for '%s' was %s, is now %s\n",
1464                               vlentry.name, oldname, newname);
1465                     }
1466                 }
1467
1468                 vlentry.nextNameHash = header.VolnameHash[hash];
1469                 header.VolnameHash[hash] = record[i].addr;
1470
1471                 for (j = 0; j < MAXTYPES; j++) {
1472
1473                     if (0 == vlentry.volumeId[j]) {
1474                         /*
1475                          * No volume of that type.  Continue
1476                          */
1477                         continue;
1478                     }
1479                     hash = IdHash(vlentry.volumeId[j]);
1480
1481                     if (vlentry.nextIdHash[j] != header.VolidHash[j][hash]) {
1482                         oldname = nameForAddr(vlentry.nextIdHash[j], j, &oldhash, oldNameBuffer);
1483                         newname = nameForAddr(header.VolidHash[j][hash], j, &newhash, newNameBuffer);
1484                         if (verbose || ((oldhash != newhash) &&
1485                                         (0 != vlentry.nextIdHash[j]) &&
1486                                         (0 != header.VolidHash[j][hash]))) {
1487                             quiet_println("FIX: %s hash link for '%s' was %s, is now %s\n",
1488                                           vtype(j), vlentry.name, oldname, newname);
1489                         }
1490                     }
1491
1492                     vlentry.nextIdHash[j] = header.VolidHash[j][hash];
1493                     header.VolidHash[j][hash] = record[i].addr;
1494                 }
1495                 writeentry(record[i].addr, &vlentry);
1496             }
1497         }
1498     }
1499     if (fix) {
1500         reportHashChanges(&header, oldnamehash, oldidhash);
1501         writeheader(&header);
1502     }
1503
1504     close(fd);
1505
1506     return error_level;
1507 }
1508
1509 int
1510 main(int argc, char **argv)
1511 {
1512     struct cmd_syndesc *ts;
1513
1514     setlinebuf(stdout);
1515
1516     ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "vldb check");
1517     cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "vldb_file");
1518     cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1519                 "Display UBIK header");
1520     cmd_AddParm(ts, "-vheader", CMD_FLAG, CMD_OPTIONAL,
1521                 "Display VLDB header");
1522     cmd_AddParm(ts, "-servers", CMD_FLAG, CMD_OPTIONAL,
1523                 "Display server list");
1524     cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1525     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1526     cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL, "quiet");
1527     cmd_AddParm(ts, "-fix", CMD_FLAG, CMD_OPTIONAL, "attempt to patch the database (potentially dangerous)");
1528
1529     return cmd_Dispatch(argc, argv);
1530 }