~ubuntu-branches/ubuntu/feisty/openafs/feisty

« back to all changes in this revision

Viewing changes to src/vlserver/vldb_check.c

  • Committer: Package Import Robot
  • Author(s): Russ Allbery
  • Date: 2007-03-26 18:56:55 UTC
  • Revision ID: package-import@ubuntu.com-20070326185655-osce8n0y0dptgurh
* New upstream release.  (Closes: #415699)
  - Support newer Linux kernels.  (Closes: #409797, #410120)
  - Add aklog fallbacks for null realms to support the referral
    capability in MIT Kerberos 1.6 and later.  (Closes: #410314)
* Apply patch from Thomas Sesselmann to support setting options to pass
  to bosserver in /etc/default/openafs-fileserver.  (Closes: #409357)
* Remove the rx_Init calls in the PAM module.  The internal counters
  that had to be initialized that way have been removed.
* Now that we're running regen.sh as part of the build process, only
  patch the Autoconf source files and not the generated output to make
  the diff easier to audit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#define MHC 0x100               /* on multihomed chain */
22
22
#define FRC 0x200               /* on free chain */
23
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 vldbread(x,y,z) vldbio(x,y,z,0)
 
30
#define vldbwrite(x,y,z) vldbio(x,y,z,1)
 
31
 
24
32
#include <afsconfig.h>
25
33
#include <afs/param.h>
26
34
 
27
35
RCSID
28
 
    ("$Header: /cvs/openafs/src/vlserver/vldb_check.c,v 1.11 2003/11/29 21:38:04 jaltman Exp $");
 
36
    ("$Header: /cvs/openafs/src/vlserver/vldb_check.c,v 1.11.2.1 2006/12/16 06:26:42 shadow Exp $");
29
37
 
30
38
#include <sys/types.h>
31
39
#include <sys/stat.h>
55
63
#include <afs/afsutil.h>
56
64
#include <afs/cmd.h>
57
65
 
 
66
#define ADDR(x) (x/sizeof(struct nvlentry))
 
67
 
58
68
int fd;
59
69
int listentries, listservers, listheader, listuheader, verbose;
60
70
 
 
71
int fix = 0;
 
72
 
61
73
struct er {
62
74
    long addr;
63
75
    int type;
64
76
} *record;
65
77
int serveraddrs[MAXSERVERID + 2];
66
78
 
 
79
#if 0
 
80
int
 
81
writeUbikHeader()
 
82
{
 
83
    /* Bump the version number?? We could cheat and push a new db... */
 
84
}
 
85
#endif
67
86
 
68
87
#define HDRSIZE 64
69
88
int
110
129
}
111
130
 
112
131
int
113
 
vldbread(position, buffer, size)
114
 
     int position;
115
 
     char *buffer;
116
 
     int size;
 
132
vldbio(int position, char *buffer, int size, int rdwr)
117
133
{
118
134
    int offset, r, p;
119
135
 
125
141
        return (-1);
126
142
    }
127
143
 
128
 
    /* now read the info */
129
 
    r = read(fd, buffer, size);
 
144
    if (rdwr == 1) 
 
145
        r = write(fd, buffer, size);
 
146
    else 
 
147
        r = read(fd, buffer, size);
 
148
 
130
149
    if (r != size) {
131
 
        printf("error: read of %d bytes failed: %d %d\n", size, r, errno);
 
150
        printf("error: %s of %d bytes failed: %d %d\n", rdwr==1?"write":"read",
 
151
               size, r, errno);
132
152
        return (-1);
133
153
    }
134
154
    return (0);
135
155
}
136
156
 
137
157
char *
138
 
vtype(type)
139
 
     int type;
 
158
vtype(int type)
140
159
{
141
160
    static char Type[3];
142
161
 
152
171
}
153
172
 
154
173
afs_int32
155
 
NameHash(volname)
156
 
     char *volname;
 
174
NameHash(char *volname)
157
175
{
158
176
    unsigned int hash;
159
177
    char *vchar;
165
183
}
166
184
 
167
185
afs_int32
168
 
IdHash(volid)
169
 
     afs_int32 volid;
 
186
IdHash(afs_int32 volid)
170
187
{
171
188
    return ((abs(volid)) % HASHSIZE);
172
189
}
173
190
 
174
191
#define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
175
192
int
176
 
InvalidVolname(volname)
177
 
     char *volname;
 
193
InvalidVolname(char *volname)
178
194
{
179
195
    char *map;
180
196
    size_t slen;
186
202
    return (slen != strspn(volname, map));
187
203
}
188
204
 
189
 
readheader(headerp)
190
 
     struct vlheader *headerp;
 
205
void
 
206
readheader(struct vlheader *headerp)
191
207
{
192
208
    int i, j;
193
209
 
251
267
               headerp->vital_header.headersize, sizeof(*headerp));
252
268
}
253
269
 
254
 
readMH(addr, mhblockP)
255
 
     afs_int32 addr;
256
 
     struct extentaddr *mhblockP;
 
270
void
 
271
writeheader(struct vlheader *headerp)
 
272
{
 
273
    int i, j;
 
274
 
 
275
    headerp->vital_header.vldbversion =
 
276
        htonl(headerp->vital_header.vldbversion);
 
277
    headerp->vital_header.headersize =
 
278
        htonl(headerp->vital_header.headersize);
 
279
    headerp->vital_header.freePtr = htonl(headerp->vital_header.freePtr);
 
280
    headerp->vital_header.eofPtr = htonl(headerp->vital_header.eofPtr);
 
281
    headerp->vital_header.allocs = htonl(headerp->vital_header.allocs);
 
282
    headerp->vital_header.frees = htonl(headerp->vital_header.frees);
 
283
    headerp->vital_header.MaxVolumeId =
 
284
        htonl(headerp->vital_header.MaxVolumeId);
 
285
    headerp->vital_header.totalEntries[0] =
 
286
        htonl(headerp->vital_header.totalEntries[0]);
 
287
    for (i = 0; i < MAXTYPES; i++)
 
288
        headerp->vital_header.totalEntries[i] =
 
289
            htonl(headerp->vital_header.totalEntries[1]);
 
290
 
 
291
    headerp->SIT = htonl(headerp->SIT);
 
292
    for (i = 0; i < MAXSERVERID; i++)
 
293
        headerp->IpMappedAddr[i] = htonl(headerp->IpMappedAddr[i]);
 
294
    for (i = 0; i < HASHSIZE; i++)
 
295
        headerp->VolnameHash[i] = htonl(headerp->VolnameHash[i]);
 
296
    for (i = 0; i < MAXTYPES; i++)
 
297
        for (j = 0; j < HASHSIZE; j++)
 
298
            headerp->VolidHash[i][j] = htonl(headerp->VolidHash[i][j]);
 
299
 
 
300
    vldbwrite(0, headerp, sizeof(*headerp));
 
301
}
 
302
 
 
303
void
 
304
readMH(afs_int32 addr, struct extentaddr *mhblockP)
257
305
{
258
306
    int i, j;
259
307
    struct extentaddr *e;
275
323
    }
276
324
}
277
325
 
278
 
readentry(addr, vlentryp, type)
279
 
     afs_int32 addr;
280
 
     struct nvlentry *vlentryp;
281
 
     afs_int32 *type;
 
326
void
 
327
readentry(afs_int32 addr, struct nvlentry *vlentryp, afs_int32 *type)
282
328
{
283
329
    int i;
284
330
 
356
402
}
357
403
 
358
404
void
359
 
readSIT(base, addr)
360
 
     int base;
361
 
     int addr;
 
405
writeentry(afs_int32 addr, struct nvlentry *vlentryp)
 
406
{
 
407
    int i;
 
408
 
 
409
    if (verbose)
 
410
        printf("Writing back entry at addr %u\n", addr);
 
411
 
 
412
    for (i = 0; i < MAXTYPES; i++)
 
413
        vlentryp->volumeId[i] = htonl(vlentryp->volumeId[i]);
 
414
    vlentryp->flags = htonl(vlentryp->flags);
 
415
    vlentryp->LockAfsId = htonl(vlentryp->LockAfsId);
 
416
    vlentryp->LockTimestamp = htonl(vlentryp->LockTimestamp);
 
417
    vlentryp->cloneId = htonl(vlentryp->cloneId);
 
418
    for (i = 0; i < MAXTYPES; i++)
 
419
        vlentryp->nextIdHash[i] = htonl(vlentryp->nextIdHash[i]);
 
420
    vlentryp->nextNameHash = htonl(vlentryp->nextNameHash);
 
421
    for (i = 0; i < NMAXNSERVERS; i++) {
 
422
        vlentryp->serverNumber[i] = htonl(vlentryp->serverNumber[i]);
 
423
        vlentryp->serverPartition[i] = htonl(vlentryp->serverPartition[i]);
 
424
        vlentryp->serverFlags[i] = htonl(vlentryp->serverFlags[i]);
 
425
    }
 
426
    vldbwrite(addr, vlentryp, sizeof(*vlentryp));
 
427
}
 
428
 
 
429
void
 
430
readSIT(int base, int addr)
362
431
{
363
432
    int i, j, a;
364
433
    char sitbuf[VL_ADDREXTBLK_SIZE];
418
487
 * Remember what the maximum volume id we found is and check against the header.
419
488
 */
420
489
void
421
 
ReadAllEntries(header)
422
 
     struct vlheader *header;
 
490
ReadAllEntries(struct vlheader *header)
423
491
{
424
492
    afs_int32 type, rindex, i, j, e;
425
493
    int freecount = 0, mhcount = 0, vlcount = 0;
457
525
                        bkcount++;
458
526
                    continue;
459
527
                }
 
528
                if (!vlentry.serverFlags[j]) {
 
529
                    /*e = 0;*/
 
530
                    continue;
 
531
                }
460
532
                if (e) {
461
533
                    printf
462
534
                        ("VLDB entry '%s' contains an unknown RW/RO index serverFlag\n",
508
580
}
509
581
 
510
582
 
 
583
void
 
584
SetHashEnd(long addr, int type, long new)
 
585
{
 
586
    struct nvlentry vlentry;
 
587
    afs_int32 i, rindex, type2, next = -1;
 
588
 
 
589
    for (; addr; addr = next) {
 
590
        readentry(addr, &vlentry, &type2);
 
591
        switch(type & 0xf0) {
 
592
        case RWH:
 
593
            next = vlentry.nextIdHash[0];
 
594
            break;
 
595
        case ROH:
 
596
            next = vlentry.nextIdHash[1];
 
597
            break;
 
598
        case BKH:
 
599
            next = vlentry.nextIdHash[2];
 
600
            break;
 
601
        case NH:
 
602
            next = vlentry.nextNameHash;
 
603
            break;
 
604
        default:
 
605
            next = -1;
 
606
        }
 
607
 
 
608
        if (next < 1) {
 
609
            switch(type & 0xf0) {
 
610
            case RWH:
 
611
              if (vlentry.nextIdHash[0] != 0) {printf("bwoop\n");}
 
612
                vlentry.nextIdHash[0] = new;
 
613
                break;
 
614
            case ROH:
 
615
              if (vlentry.nextIdHash[1] != 0) {printf("bwoop\n");}
 
616
                vlentry.nextIdHash[1] = new;
 
617
                break;
 
618
            case BKH:
 
619
              if (vlentry.nextIdHash[2] != 0) {printf("bwoop\n");}
 
620
                vlentry.nextIdHash[2] = new;
 
621
                break;
 
622
            case NH:
 
623
              if (vlentry.nextNameHash != 0) {printf("bwoop\n");}
 
624
                vlentry.nextNameHash = new;
 
625
                break;
 
626
            }
 
627
            writeentry(addr, &vlentry);
 
628
            return;
 
629
        }
 
630
    }
 
631
}
 
632
 
511
633
/*
512
634
 * Follow each Name hash bucket marking it as read in the record array.
513
635
 * Record we found it in the name hash within the record array.
514
636
 * Check that the name is hashed correctly.
515
637
 */
516
 
FollowNameHash(header)
517
 
     struct vlheader *header;
 
638
void
 
639
FollowNameHash(struct vlheader *header)
518
640
{
519
641
    int count = 0, longest = 0, shortest = -1, chainlength;
520
642
    struct nvlentry vlentry;
549
671
            }
550
672
            record[rindex].type |= NH;
551
673
 
 
674
            record[rindex].type |= REFN;
 
675
 
552
676
            chainlength++;
553
677
            count++;
554
678
 
576
700
 * Record we found it in the id hash within the record array.
577
701
 * Check that the ID is hashed correctly.
578
702
 */
579
 
FollowIdHash(header)
580
 
     struct vlheader *header;
 
703
void
 
704
FollowIdHash(struct vlheader *header)
581
705
{
582
706
    int count = 0, longest = 0, shortest = -1, chainlength;
583
707
    struct nvlentry vlentry;
584
708
    afs_uint32 addr;
585
 
    afs_int32 i, j, hash, type, rindex;
 
709
    afs_int32 i, j, hash, type, rindex, ref;
586
710
 
587
711
    /* Now follow the RW, RO, and BK Hash Tables */
588
712
    if (verbose)
589
713
        printf("Check RW, RO, and BK id Hashes\n");
590
714
    for (i = 0; i < MAXTYPES; i++) {
591
715
        hash = ((i == 0) ? RWH : ((i == 1) ? ROH : BKH));
 
716
        ref = ((i == 0) ? REFRW : ((i == 1) ? REFRO : REFBK));
592
717
        count = longest = 0;
593
718
        shortest = -1;
594
719
 
617
742
                    break;
618
743
                }
619
744
                record[rindex].type |= hash;
 
745
                record[rindex].type |= ref;
620
746
 
621
747
                chainlength++;
622
748
                count++;
648
774
 * Follow the free chain.
649
775
 * Record we found it in the free chain within the record array.
650
776
 */
651
 
FollowFreeChain(header)
652
 
     struct vlheader *header;
 
777
void
 
778
FollowFreeChain(struct vlheader *header)
653
779
{
654
780
    afs_int32 count = 0;
655
781
    struct nvlentry vlentry;
704
830
 * The code does not verify if there are duplicate IP addresses in the 
705
831
 * list. The vlserver does this when a fileserver registeres itself.
706
832
 */
707
 
CheckIpAddrs(header)
708
 
     struct vlheader *header;
 
833
void
 
834
CheckIpAddrs(struct vlheader *header)
709
835
{
710
836
    int mhblocks = 0;
711
837
    afs_int32 i, j, m, rindex;
899
1025
 
900
1026
}
901
1027
 
 
1028
void 
 
1029
FixBad(afs_uint32 idx, afs_uint32 addr, afs_uint32 type, afs_uint32 tmp, 
 
1030
       struct nvlentry *vlentry) {
 
1031
    SetHashEnd(addr, type, tmp);
 
1032
    printf("linked unlinked chain %u (index %d) to end of chain\n", 
 
1033
           tmp, ADDR(tmp));
 
1034
}
 
1035
 
902
1036
int
903
 
WorkerBee(as, arock)
904
 
     struct cmd_syndesc *as;
905
 
     char *arock;
 
1037
WorkerBee(struct cmd_syndesc *as, char *arock)
906
1038
{
907
1039
    char *dbfile;
908
 
    afs_int32 maxentries, type;
 
1040
    afs_int32 maxentries, type, tmp;
909
1041
    struct vlheader header;
910
1042
    struct nvlentry vlentry;
911
1043
    int i, j, help = 0;
916
1048
    listservers = (as->parms[3].items ? 1 : 0); /* -servers  */
917
1049
    listentries = (as->parms[4].items ? 1 : 0); /* -entries  */
918
1050
    verbose = (as->parms[5].items ? 1 : 0);     /* -verbose  */
 
1051
    fix = (as->parms[6].items ? 1 : 0); /* -fix  */
919
1052
 
920
1053
    /* open the vldb database file */
921
 
    fd = open(dbfile, O_RDONLY, 0);
 
1054
    fd = open(dbfile, (fix > 0)?O_RDWR:O_RDONLY, 0);
922
1055
    if (fd < 0) {
923
1056
        printf("can't open file '%s'. error = %d\n", dbfile, errno);
924
1057
        return 0;
960
1093
    if (verbose)
961
1094
        printf("Verify each volume entry\n");
962
1095
    for (i = 0; i < maxentries; i++) {
 
1096
        int nextp;
 
1097
        int reft;
 
1098
        int hash;
 
1099
        int *nextpp;
 
1100
        char *which;
 
1101
 
963
1102
        if (record[i].type == 0)
964
1103
            continue;
965
1104
 
967
1106
         * on the hash chains, and its server numbers are good.
968
1107
         */
969
1108
        if (record[i].type & VL) {
 
1109
            int foundbad = 0;
 
1110
            char volidbuf[256];
 
1111
 
970
1112
            readentry(record[i].addr, &vlentry, &type);
971
1113
 
972
1114
            if (InvalidVolname(vlentry.name))
973
1115
                printf("Volume '%s' at addr %u has an invalid name\n",
974
1116
                       vlentry.name, record[i].addr);
975
1117
 
976
 
            if (!(record[i].type & NH))
977
 
                printf("Volume '%s' not found in name hash\n", vlentry.name);
978
 
 
979
 
            if (vlentry.volumeId[0] && !(record[i].type & RWH))
980
 
                printf("Volume '%s' id %u not found in RW hash chain\n",
981
 
                       vlentry.name, vlentry.volumeId[0]);
982
 
 
983
 
            if (vlentry.volumeId[1] && !(record[i].type & ROH))
984
 
                printf("Volume '%s' id %u not found in RO hash chain\n",
985
 
                       vlentry.name, vlentry.volumeId[1]);
986
 
 
987
 
            if (vlentry.volumeId[2] && !(record[i].type & BKH))
988
 
                printf("Volume '%s' id %u not found in BK hash chain\n",
989
 
                       vlentry.name, vlentry.volumeId[2]);
990
 
 
 
1118
            if (!(record[i].type & NH)) {
 
1119
                nextp = ADDR(vlentry.nextNameHash);
 
1120
                reft = REFN;
 
1121
                hash = NameHash(vlentry.name);
 
1122
                nextpp = &vlentry.nextNameHash;
 
1123
                which = "name";
 
1124
                sprintf(volidbuf, "");
 
1125
                foundbad = 1;
 
1126
            }
 
1127
 
 
1128
            if (vlentry.volumeId[0] && !(record[i].type & RWH)) {
 
1129
                nextp = ADDR(vlentry.nextIdHash[0]);
 
1130
                reft = REFRW;
 
1131
                hash = IdHash(vlentry.volumeId[0]);
 
1132
                nextpp = &(vlentry.nextIdHash[0]);
 
1133
                which = "RW";
 
1134
                sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
 
1135
                foundbad = 1;
 
1136
            }
 
1137
 
 
1138
            if (vlentry.volumeId[1] && !(record[i].type & ROH)) {
 
1139
                nextp = ADDR(vlentry.nextIdHash[1]);
 
1140
                reft = REFRO;
 
1141
                hash = IdHash(vlentry.volumeId[1]);
 
1142
                nextpp = &(vlentry.nextIdHash[1]);
 
1143
                which = "RO";
 
1144
                sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
 
1145
                foundbad = 1;
 
1146
            }
 
1147
 
 
1148
            if (vlentry.volumeId[2] && !(record[i].type & BKH)) {
 
1149
                nextp = ADDR(vlentry.nextIdHash[2]);
 
1150
                reft = REFBK;
 
1151
                hash = IdHash(vlentry.volumeId[2]);
 
1152
                nextpp = &(vlentry.nextIdHash[2]);
 
1153
                which = "BK";
 
1154
                sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
 
1155
                foundbad = 1;
 
1156
            }
 
1157
 
 
1158
            if (foundbad) {
 
1159
                printf("%d: Volume '%s' %snot found in %s hash %d", i, 
 
1160
                       vlentry.name, volidbuf, which, hash);
 
1161
                if (nextp) {
 
1162
                    printf(" (next %d", nextp);
 
1163
                    if (!(record[nextp].type & reft)) {
 
1164
                        printf(" not in chain ");
 
1165
                        record[nextp].type |= reft;
 
1166
                    } else if (nextp != 0) {
 
1167
                        printf(" next in chain");
 
1168
                        if (fix) {
 
1169
                            printf(", unchaining");
 
1170
                            *nextpp = 0;
 
1171
                            writeentry(record[i].addr, &vlentry);
 
1172
                        }
 
1173
                    }
 
1174
                    printf(")");
 
1175
                }
 
1176
                printf("\n");
 
1177
            }
 
1178
        
991
1179
            for (j = 0; j < NMAXNSERVERS; j++) {
992
1180
                if ((vlentry.serverNumber[j] != 255)
993
1181
                    && (serveraddrs[vlentry.serverNumber[j]] == 0)) {
996
1184
                         vlentry.name, j, vlentry.serverNumber[j]);
997
1185
                }
998
1186
            }
999
 
 
1000
 
            if (record[i].type & 0xffffff00)
 
1187
        
 
1188
            if (record[i].type & 0xffff0f00)
1001
1189
                printf
1002
1190
                    ("Volume '%s' id %u also found on other chains (0x%x)\n",
1003
1191
                     vlentry.name, vlentry.volumeId[0], record[i].type);
1004
 
 
 
1192
            
1005
1193
            /* A free entry */
1006
1194
        } else if (record[i].type & FR) {
1007
1195
            if (!(record[i].type & FRC))
1008
1196
                printf("Free vlentry at %u not on free chain\n",
1009
1197
                       record[i].addr);
1010
 
 
 
1198
            
1011
1199
            if (record[i].type & 0xfffffdf0)
1012
1200
                printf
1013
1201
                    ("Free vlentry at %u also found on other chains (0x%x)\n",
1014
1202
                     record[i].addr, record[i].type);
1015
 
 
 
1203
            
1016
1204
            /* A multihomed entry */
1017
1205
        } else if (record[i].type & MH) {
1018
1206
            if (!(record[i].type & MHC))
1019
1207
                printf("Multihomed block at %u is orphaned\n",
1020
1208
                       record[i].addr);
1021
 
 
 
1209
            
1022
1210
            if (record[i].type & 0xfffffef0)
1023
1211
                printf
1024
1212
                    ("Multihomed block at %u also found on other chains (0x%x)\n",
1025
1213
                     record[i].addr, record[i].type);
1026
 
 
 
1214
            
1027
1215
        } else {
1028
1216
            printf("Unknown entry type at %u (0x%x)\n", record[i].addr,
1029
1217
                   record[i].type);
1030
1218
        }
1031
1219
    }
 
1220
 
 
1221
    /* By the time we get here, unchained entries are really unchained */
 
1222
    printf("Scanning %u entries for possible repairs\n", maxentries);
 
1223
    for (i = 0; i < maxentries; i++) {
 
1224
        if (record[i].type & VL) {
 
1225
            readentry(record[i].addr, &vlentry, &type);
 
1226
            if (!(record[i].type & REFN) && (strlen(vlentry.name)>0)) {
 
1227
                printf("%d: Record %u (type 0x%x) not in a name chain\n", i, 
 
1228
                       record[i].addr, record[i].type);
 
1229
                if (fix) {
 
1230
                    if (header.VolnameHash[NameHash(vlentry.name)] == 0)
 
1231
                        header.VolnameHash[NameHash(vlentry.name)] = record[i].addr;
 
1232
                    else
 
1233
                        FixBad(i, header.VolnameHash[NameHash(vlentry.name)], NH, record[i].addr, &vlentry);
 
1234
                }
 
1235
            }
 
1236
            if (vlentry.volumeId[0] && !(record[i].type & REFRW)) {
 
1237
                printf("%d: Record %u (type 0x%x) not in a RW chain\n", i,
 
1238
                       record[i].addr, record[i].type);
 
1239
                if (fix) {
 
1240
                    if (header.VolidHash[0][IdHash(vlentry.volumeId[0])] == 0)
 
1241
                        header.VolidHash[0][IdHash(vlentry.volumeId[0])] = record[i].addr;
 
1242
                    else
 
1243
                        FixBad(i, header.VolidHash[0][IdHash(vlentry.volumeId[0])], RWH, record[i].addr, &vlentry);
 
1244
                }
 
1245
            }
 
1246
            if (vlentry.volumeId[1] && !(record[i].type & REFRO)) {
 
1247
                printf("%d: Record %u (type 0x%x) not in a RO chain\n", i, 
 
1248
                       record[i].addr, record[i].type);
 
1249
                if (fix) {
 
1250
                    if (header.VolidHash[1][IdHash(vlentry.volumeId[1])] == 0)
 
1251
                        header.VolidHash[1][IdHash(vlentry.volumeId[1])] = record[i].addr;
 
1252
                    else
 
1253
                        FixBad(i, header.VolidHash[1][IdHash(vlentry.volumeId[1])], ROH, record[i].addr, &vlentry);
 
1254
                }
 
1255
            }
 
1256
            if (vlentry.volumeId[2] && !(record[i].type & REFBK)) {
 
1257
                printf("%d: Record %u (type 0x%x) not in a BK chain\n", i, 
 
1258
                       record[i].addr, record[i].type);
 
1259
                if (fix) {
 
1260
                    if (header.VolidHash[2][IdHash(vlentry.volumeId[2])] == 0)
 
1261
                        header.VolidHash[2][IdHash(vlentry.volumeId[2])] = record[i].addr;
 
1262
                    else
 
1263
                        FixBad(i, header.VolidHash[2][IdHash(vlentry.volumeId[2])], BKH, record[i].addr, &vlentry);
 
1264
                }
 
1265
 
 
1266
            }
 
1267
        }
 
1268
    }
 
1269
    if (fix) 
 
1270
        writeheader(&header);
 
1271
 
1032
1272
    return 0;
1033
1273
}
1034
1274
 
1035
 
main(argc, argv)
1036
 
     int argc;
1037
 
     char **argv;
 
1275
int
 
1276
main(int argc, char **argv)
1038
1277
{
1039
1278
    struct cmd_syndesc *ts;
1040
1279
 
1050
1289
                "Display server list");
1051
1290
    cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1052
1291
    cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
 
1292
    cmd_AddParm(ts, "-fix", CMD_FLAG, CMD_OPTIONAL, "attempt to patch the database (potentially dangerous)");
1053
1293
 
1054
1294
    return cmd_Dispatch(argc, argv);
1055
1295
}