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