2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #include <afs/venus.h>
20 #include <afs/afsutil.h>
21 #include <afs/fileutil.h>
24 #include "cnvldb.h" /* CHANGEME! */
26 #define BADSERVERID 255 /* XXX */
29 static char pn
[] = "cnvldb";
30 static char tempname
[] = "XXnewvldb";
31 static int MaxServers
[3] = { 30, 254, 254 }; /* max server # permitted in this version */
33 static afs_int32
Conv4to3(afs_uint32 addr
);
35 static void convert_vlentry(int, int, int, struct vlheader_1
*,
36 struct vlheader_1
*, struct vlentry_1
*);
37 static void rewrite_header(int, int, void *);
38 static void readheader(int fd
, int version
, void *addr
);
39 static int readentry(int fd
, int version
, void *addr
);
40 static void printentry(int version
, void *addr
);
42 static char tspace
[1024]; /* chdir can't handle anything bigger, anyway */
44 void read_mhentries(afs_uint32 mh_addr
, int oldfd
);
45 void convert_mhentries(int oldfd
, int newfd
, struct vlheader_2
*header
, int fromver
, int tover
);
47 static int convert_header(int ofd
, int fd
, int fromv
, int tov
, void *fromaddr
,
50 /* return a static pointer to a buffer */
52 Parent(const char *apath
)
55 strcpy(tspace
, apath
);
56 tp
= strrchr(tspace
, '/');
65 int fromvers
= 0, tovers
= 0, showversion
= 0;
68 const char *pathname
= NULL
;
72 handleit(struct cmd_syndesc
*as
, void *arock
)
74 int w
, old
, new, rc
, dump
= 0, fromv
= 0;
77 char ubik
[80]; /* space for some ubik header */
79 struct vlheader_1 header1
;
80 struct vlheader_2 header2
;
81 struct vlheader_3 header3
;
82 } oldheader
, newheader
; /* large enough for either */
85 struct vlentry_1 entry1
;
86 struct vlentry_2 entry2
;
87 struct vlentry_3 entry3
;
88 char mhinfo_block
[VL_ADDREXTBLK_SIZE
];
91 pathname
= (as
->parms
[2].items
? as
->parms
[2].items
->data
: dbPath
); /* -name */
92 showversion
= (as
->parms
[3].items
? 1 : 0); /* -showversion */
93 dump
= (as
->parms
[4].items
? 1 : 0); /* -dumpvldb */
94 fromvers
= (as
->parms
[1].items
? atoi(as
->parms
[1].items
->data
) : 0); /* -fromversion */
95 tovers
= (as
->parms
[0].items
? atoi(as
->parms
[0].items
->data
) : 0); /* -toversion */
97 /* should stat() the old vldb, get its size, and see if there's */
98 /* room for another. It might be in AFS, so check the quota, too */
99 old
= open(pathname
, O_RDONLY
);
105 /* Read the version */
106 if (lseek(old
, 64, L_SET
) == (off_t
)-1) {
110 count
= read(old
, &fromv
, sizeof(int));
114 } else if (count
!= sizeof(int)) {
115 fprintf(stderr
, "%s: Premature EOF reading database version.\n", pn
);
118 fromv
= ntohl(fromv
);
119 if ((fromv
< 1) || (fromv
> 4)) {
120 fprintf(stderr
, "%s", pn
);
121 fprintf(stderr
, ": Unrecognized VLDB version %d.\n", fromv
);
125 /* Sequentially read the database converting the entries as we go */
126 if (lseek(old
, 0, L_SET
) == (off_t
)-1) {
130 count
= read(old
, ubik
, 64);
134 } else if (count
!= 64) {
135 fprintf(stderr
, "%s: Premature EOF reading database header.\n", pn
);
138 readheader(old
, fromv
, &oldheader
);
140 dbsize
= ntohl(oldheader
.header1
.vital_header
.eofPtr
);
141 fromv
= ntohl(oldheader
.header1
.vital_header
.vldbversion
);
143 } else if (fromv
== 2) {
144 dbsize
= ntohl(oldheader
.header2
.vital_header
.eofPtr
);
145 fromv
= ntohl(oldheader
.header2
.vital_header
.vldbversion
);
150 dbsize
= ntohl(oldheader
.header3
.vital_header
.eofPtr
);
151 fromv
= ntohl(oldheader
.header3
.vital_header
.vldbversion
);
152 mhaddr
= ntohl(oldheader
.header3
.SIT
);
154 /* Read the multihomed extent blocks in */
156 read_mhentries(mhaddr
, old
);
158 /* Position back to this after header */
159 lseek(old
, pos
+ 64, L_SET
);
163 if (showversion
|| dump
) {
165 fprintf(stdout
, "%s has a version of %d\n", pathname
, fromv
);
167 while (oldpos
< dbsize
) {
168 rc
= readentry(old
, fromv
, &xvlentry
);
169 if ((rc
== 0) || (rc
== EOF
))
171 printentry(fromv
, &xvlentry
);
177 if (!fromvers
) { /* not set */
179 } else if (fromvers
!= fromv
) {
181 "%s has a version of %d while the -fromversion specified was %d - aborting\n",
182 pathname
, fromv
, fromvers
);
186 if ((fromvers
< 1) || (fromvers
> 4)) {
187 fprintf(stderr
, "%s", pn
);
188 fprintf(stderr
, ": VLDB version %d is not supported.\n", fromvers
);
189 fprintf(stderr
, "%s", pn
);
190 fprintf(stderr
, ": Only versions 1-4 are currently supported.\n");
195 tovers
= fromvers
+ 1;
197 if (tovers
< 1 || tovers
> 4) {
198 fprintf(stderr
, "%s", pn
);
199 fprintf(stderr
, ": VLDB version %d is not supported.\n", tovers
);
200 fprintf(stderr
, "%s", pn
);
201 fprintf(stderr
, ": Only versions 1 - 4 are currently supported.\n");
205 if (mhaddr
&& (tovers
< 3)) {
206 fprintf(stderr
, "%s", pn
);
207 fprintf(stderr
, ": Cannot convert. VLDB contains multihome info.\n");
211 /* OK! let's get down to business... */
213 if (chdir(Parent(pathname
))) {
218 new = open(tempname
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
224 /* Write the UBIK data */
225 w
= write(new, ubik
, 64);
227 printf("Write of ubik header failed %d; error %u\n", w
, errno
);
231 /* Because we know that all the vldb entries are the same size and type we
232 * can just read them sequentially, fiddle with the fields, and write
233 * them out again. If we invent a vldb format that has different
234 * types of entries, then we're going to have to invent new logic for
235 * converting the vldb-- we'll probably have to chase down the various
236 * linked lists in turn, doing lseeks and the like.
239 convert_header(old
, new, fromvers
, tovers
, &oldheader
, &newheader
);
240 while (oldpos
< dbsize
) {
241 rc
= readentry(old
, fromvers
, &xvlentry
);
242 if ((rc
== 0) || (rc
== EOF
))
244 convert_vlentry(new, fromvers
, tovers
,
245 (struct vlheader_1
*)&oldheader
,
246 (struct vlheader_1
*)&newheader
,
247 (struct vlentry_1
*)&xvlentry
);
250 /* We have now finished sequentially reading and writing the database.
251 * Now randomly offset into database and update multihome entries.
253 convert_mhentries(old
, new, (struct vlheader_2
*)&newheader
,
255 rewrite_header(new, tovers
, &newheader
);
264 rk_rename(tempname
, pathname
);
271 readheader(int fd
, int version
, void *addr
)
273 int hdrsize
, size
= 0;
277 hdrsize
= sizeof(struct vlheader_1
);
279 hdrsize
= sizeof(struct vlheader_2
);
281 size
= read(fd
, addr
, hdrsize
);
289 readentry(int fd
, int version
, void *addr
)
292 struct vlentry_3
*vl3p
= (struct vlentry_3
*)addr
;
294 char *caddr
= (char *)addr
;
298 1) ? sizeof(struct vlentry_1
) : sizeof(struct vlentry_2
));
299 rc
= read(fd
, addr
, toread
);
301 printf("Partial read of vlentry at pos %u: %d\n", oldpos
, rc
);
305 /* Read a mhblock entry if there is one */
306 if ((rc
> 0) && (vl3p
->flags
== VLCONTBLOCK
)) {
307 if (!mhaddr
) /* Remember first mh block */
308 mhaddr
= oldpos
- rc
;
310 rc1
= read(fd
, &caddr
[rc
], VL_ADDREXTBLK_SIZE
- rc
);
311 if (rc1
!= VL_ADDREXTBLK_SIZE
- rc
)
312 printf("Partial read of mhblock at pos %u: %d\n", oldpos
+ rc
,
324 printentry(int version
, void *addr
)
326 struct vlentry_2
*vl2p
= (struct vlentry_2
*)addr
;
327 struct vlentry_3
*vl3p
= (struct vlentry_3
*)addr
;
330 /* Don't print anything if the entry is a mh info block */
331 if (vl3p
->flags
== VLCONTBLOCK
) {
335 if (version
== 1 || version
== 2) {
336 printf("%s\t%5d [%10d:%10d:%10d]%8X%8d\n", vl2p
->name
, vl2p
->spares3
,
337 vl2p
->volumeId
[0], vl2p
->volumeId
[1], vl2p
->volumeId
[2],
338 vl2p
->flags
, vl2p
->LockAfsId
);
339 printf("\t%8d%8d%8d [%7d%7d%7d]%7d [%4d%4d%4d%4d][%4d%4d%4d%4d]\n",
340 vl2p
->LockTimestamp
, vl2p
->cloneId
, vl2p
->spares0
,
341 vl2p
->nextIdHash
[0], vl2p
->nextIdHash
[1], vl2p
->nextIdHash
[2],
342 vl2p
->nextNameHash
, vl2p
->serverNumber
[0],
343 vl2p
->serverNumber
[1], vl2p
->serverNumber
[2],
344 vl2p
->serverNumber
[3], vl2p
->serverPartition
[0],
345 vl2p
->serverPartition
[1], vl2p
->serverPartition
[2],
346 vl2p
->serverPartition
[3]);
347 printf("\t[%4d%4d%4d%4d]\n", vl2p
->serverFlags
[0],
348 vl2p
->serverFlags
[1], vl2p
->serverFlags
[2],
349 vl2p
->serverFlags
[3]);
350 } else { /* if (version >= 3) */
352 if (vl3p
->flags
== VLFREE
)
354 printf("%s\tPos=%" AFS_SIZET_FMT
" NextIdHash=[%d:%d:%d] NextNameHash=%d\n",
355 vl3p
->name
, (oldpos
- sizeof(struct vlentry_3
)),
356 vl3p
->nextIdHash
[0], vl3p
->nextIdHash
[1], vl3p
->nextIdHash
[2],
358 printf("\tRW=%u RO=%u BK=%u CL=%u flags=0x%X lockBy=%d lockTime=%u\n",
359 vl3p
->volumeId
[0], vl3p
->volumeId
[1], vl3p
->volumeId
[2],
360 vl3p
->cloneId
, vl3p
->flags
, vl3p
->LockAfsId
,
361 vl3p
->LockTimestamp
);
362 for (i
= 0; i
< OMAXNSERVERS
; i
++) {
363 if ((vl3p
->serverNumber
[i
] & 0xff) != 0xff) {
364 printf("\tServer=%d Partition=%d flags=%X\n",
365 vl3p
->serverNumber
[i
], vl3p
->serverPartition
[i
],
366 vl3p
->serverFlags
[i
]);
373 int readmhentries
= 0;
374 struct extentaddr
*base
[VL_MAX_ADDREXTBLKS
];
376 /* Read the multihome extent blocks in. Check if they are good by
377 * verifying their address is not pass the EOF and the flags are good.
378 * If it's not good, then don't read the block in.
381 read_mhentries(afs_uint32 mh_addr
, int oldfd
)
391 /* Initialize base pointers */
392 for (j
= 0; j
< VL_MAX_ADDREXTBLKS
; j
++)
398 /* Check if the first extent block is beyond eof. If
399 * it is, it's not real.
401 if (mh_addr
> dbsize
- VL_ADDREXTBLK_SIZE
)
404 /* Now read the first mh extent block */
405 code
= lseek(oldfd
, mh_addr
+ 64, L_SET
);
407 perror("seek MH block");
410 base
[0] = malloc(VL_ADDREXTBLK_SIZE
);
415 code
= read(oldfd
, (char *)base
[0], VL_ADDREXTBLK_SIZE
);
416 if (code
!= VL_ADDREXTBLK_SIZE
) {
417 perror("read MH block");
423 /* Verify that this block is the right one */
424 if (ntohl(base
[0]->ex_hdrflags
) != VLCONTBLOCK
) { /* check if flag is correct */
430 /* The first block contains pointers to the other extent blocks.
431 * Check to see if the pointers are good and read them in if they are.
434 for (j
= 1; j
< VL_MAX_ADDREXTBLKS
; j
++) {
435 if (!base
[0]->ex_contaddrs
[j
])
438 sit
= ntohl(base
[0]->ex_contaddrs
[j
]);
440 /* Every time we allocate a new extent block, it is allocated after
441 * the previous ones. But it must be before the EOF.
443 if ((sit
< (a
+ VL_ADDREXTBLK_SIZE
))
444 || (sit
> dbsize
- VL_ADDREXTBLK_SIZE
)) {
448 /* Read the extent block in */
450 code
= lseek(oldfd
, sit
, L_SET
);
452 perror("seek MH block");
455 base
[j
] = malloc(VL_ADDREXTBLK_SIZE
);
460 code
= read(oldfd
, (char *)base
[j
], VL_ADDREXTBLK_SIZE
);
461 if (code
!= VL_ADDREXTBLK_SIZE
) {
462 perror("read MH block");
466 /* Verify that this block knows its an extent block */
467 if (ntohl(base
[j
]->ex_hdrflags
) != VLCONTBLOCK
) {
473 /* The extent block passed our tests */
474 a
= ntohl(base
[0]->ex_contaddrs
[j
]);
478 /* Follow the SIT pointer in the header (mhaddr) to the multihomed
479 * extent blocks and verify that the pointers are good. And fix.
480 * Then convert the multihomed addresses to single address if we
481 * are converting back from version 4.
483 * Before this can be called, the routine read_mhentries must be called.
486 convert_mhentries(int oldfd
, int newfd
, struct vlheader_2
*header
,
487 int fromver
, int tover
)
490 int i
, j
, modified
= 0, w
;
491 afs_uint32 raddr
, addr
;
492 struct extentaddr
*exp
;
495 /* Check if the header says the extent block exists. If
496 * it does, then read_mhentries should have read it in.
498 if (mhaddr
&& !base
[0]) {
499 printf("Fix Bad base extent block pointer\n");
500 header
->SIT
= mhaddr
= 0;
501 } else if (mhaddr
&& base
[0]) {
503 if ((ntohl(header
->SIT
) != mhaddr
) && (tover
== 4)) {
505 ("Fix pointer to first base extent block. Was 0x%x, now 0x%x\n",
506 ntohl(header
->SIT
), mhaddr
);
507 header
->SIT
= htonl(mhaddr
);
510 /* Check if the first block points to itself. If not, then fix it */
511 if (ntohl(base
[0]->ex_contaddrs
[0]) != mhaddr
) {
512 printf("Fix bad pointer in base extent block: Base 0\n");
513 base
[0]->ex_contaddrs
[0] = htonl(mhaddr
);
517 /* The first block contains pointers to the other extent blocks.
518 * Check to see if the pointers are good.
520 for (j
= 1; j
< VL_MAX_ADDREXTBLKS
; j
++) {
521 /* Check if the base extent block says the extent blocks exist.
522 * If it does, then read_mhentries should have read it in.
524 if (base
[0]->ex_contaddrs
[j
] && !base
[j
]) {
525 printf("Fix bad pointer in base extent block: Base %d\n", j
);
526 base
[0]->ex_contaddrs
[j
] = 0;
531 /* Now write out the base extent blocks if it changed */
533 code
= lseek(newfd
, mhaddr
+ 64, L_SET
);
535 perror("seek MH Block");
538 w
= write(newfd
, (char *)base
[0], VL_ADDREXTBLK_SIZE
);
539 if (w
!= VL_ADDREXTBLK_SIZE
) {
540 perror("write MH Block");
546 /* If we are converting from version 4 to version 3, then
547 * translate any multihome ptrs in the IpMappedAddr array
548 * to true IP addresses.
550 if ((fromver
== 4) && (tover
== 3)) {
551 /* Step through the fileserver addresses in the VLDB header
552 * and convert the pointers back to IP addresses.
554 for (i
= 0; i
< 254; i
++) {
555 addr
= ntohl(header
->IpMappedAddr
[i
]);
556 if (addr
&& ((addr
& 0xff000000) == 0xff000000)) {
557 basei
= (addr
>> 16) & 0xff;
558 index
= addr
& 0xffff;
560 if ((basei
>= VL_MAX_ADDREXTBLKS
) || !base
[basei
]) {
562 "Warning: mh entry %d has no IP address; ignored!!\n",
564 header
->IpMappedAddr
[i
] = 0;
567 exp
= &base
[basei
][index
];
569 /* For now return the first ip address back */
570 for (j
= 0; j
< VL_MAXIPADDRS_PERMH
; j
++) {
571 if (exp
->ex_addrs
[j
]) {
572 raddr
= ntohl(exp
->ex_addrs
[j
]);
576 if (j
>= VL_MAXIPADDRS_PERMH
) {
578 "Warning: mh entry %d has no ip address; ignored!!\n",
583 ("Multi-homed addr: converting to single ip address %d.%d.%d.%d\n",
584 (raddr
>> 24 & 0xff), (raddr
>> 16 & 0xff),
585 (raddr
>> 8 & 0xff), (raddr
& 0xff));
587 header
->IpMappedAddr
[i
] = htonl(raddr
);
590 header
->SIT
= mhaddr
= 0; /* mhinfo block has been removed */
592 /* Now step through the hash tables in header updating them.
593 * Because we removed the mh info blocks and some entries they
594 * point to may have changed position.
597 for (i
= 0; i
< 8191; i
++) {
598 header
->VolnameHash
[i
] = Conv4to3(header
->VolnameHash
[i
]);
601 for (i
= 0; i
< 3; i
++) {
602 for (j
= 0; j
< 8191; j
++) {
603 header
->VolidHash
[i
][j
] = Conv4to3(header
->VolidHash
[i
][j
]);
607 /* Update eofptr to take into account the removal of the mhinfo blocks */
608 header
->vital_header
.eofPtr
= htonl(Conv4to3(dbsize
));
614 convert_header(int ofd
, int fd
, int fromv
, int tov
, void *fromaddr
,
617 struct vlheader_1
*tvp1
;
618 struct vlheader_2
*tvp2
;
623 memcpy(toaddr
, fromaddr
, sizeof(struct vlheader_1
));
624 tvp1
= (struct vlheader_1
*)toaddr
;
626 w
= write(fd
, tvp1
, sizeof(struct vlheader_1
));
627 if (w
!= sizeof(struct vlheader_1
)) {
628 printf("Write of header failed %d; error %u\n", w
, errno
);
632 /* for garbage-collecting... */
633 for (i
= 0; i
< 31; i
++)
634 tvp1
->IpMappedAddr
[i
] = 0;
636 } else if (tov
== 2 || tov
== 3) {
637 tvp1
= (struct vlheader_1
*)fromaddr
;
638 tvp2
= (struct vlheader_2
*)toaddr
;
639 memset(tvp2
, 0, sizeof(struct vlheader_2
));
640 tvp2
->vital_header
.vldbversion
= htonl(tov
);
641 tvp2
->vital_header
.headersize
= htonl(sizeof(struct vlheader_2
));
643 ntohl(tvp2
->vital_header
.headersize
) -
644 ntohl(tvp1
->vital_header
.headersize
);
645 if (ntohl(tvp1
->vital_header
.freePtr
))
646 tvp2
->vital_header
.freePtr
=
647 htonl(ntohl(tvp1
->vital_header
.freePtr
) + diff
);
648 if (ntohl(tvp1
->vital_header
.eofPtr
))
649 tvp2
->vital_header
.eofPtr
=
650 htonl(ntohl(tvp1
->vital_header
.eofPtr
) + diff
);
651 tvp2
->vital_header
.allocs
= tvp1
->vital_header
.allocs
;
652 tvp2
->vital_header
.frees
= tvp1
->vital_header
.frees
;
653 tvp2
->vital_header
.MaxVolumeId
= tvp1
->vital_header
.MaxVolumeId
;
654 for (i
= 0; i
< 3; i
++)
655 tvp2
->vital_header
.totalEntries
[i
] =
656 tvp1
->vital_header
.totalEntries
[i
];
658 for (i
= 0; i
< 31; i
++)
659 tvp2
->IpMappedAddr
[i
] = tvp1
->IpMappedAddr
[i
];
661 for (i
= 0; i
< 8191; i
++) {
662 if (ntohl(tvp1
->VolnameHash
[i
]))
663 tvp2
->VolnameHash
[i
] =
664 htonl(ntohl(tvp1
->VolnameHash
[i
]) + diff
);
667 for (i
= 0; i
< 3; i
++) {
668 for (j
= 0; j
< 8191; j
++) {
669 if (ntohl(tvp1
->VolidHash
[i
][j
]))
670 tvp2
->VolidHash
[i
][j
] =
671 htonl(ntohl(tvp1
->VolidHash
[i
][j
]) + diff
);
675 w
= write(fd
, tvp2
, sizeof(struct vlheader_2
));
676 if (w
!= sizeof(struct vlheader_2
)) {
677 printf("Write of header failed %d; error %u\n", w
, errno
);
681 /* for garbage-collecting... */
682 for (i
= 0; i
< 31; i
++)
683 tvp2
->IpMappedAddr
[i
] = 0;
686 } else if (fromv
== 2 || fromv
== 3 || fromv
== 4) {
687 if (tov
== 2 || tov
== 3 || tov
== 4) {
688 memcpy(toaddr
, fromaddr
, sizeof(struct vlheader_2
));
689 tvp2
= (struct vlheader_2
*)toaddr
;
690 tvp2
->vital_header
.vldbversion
= htonl(tov
);
691 w
= write(fd
, tvp2
, sizeof(struct vlheader_2
));
692 if (w
!= sizeof(struct vlheader_2
)) {
693 printf("Write of header failed %d; error %u\n", w
, errno
);
697 } else if (tov
== 1) {
698 tvp2
= (struct vlheader_2
*)fromaddr
;
699 tvp1
= (struct vlheader_1
*)toaddr
;
700 memset(tvp1
, 0, sizeof(struct vlheader_1
));
701 tvp1
->vital_header
.vldbversion
= htonl(1);
702 tvp1
->vital_header
.headersize
= htonl(sizeof(struct vlheader_1
));
704 ntohl(tvp1
->vital_header
.headersize
) -
705 ntohl(tvp2
->vital_header
.headersize
);
706 if (ntohl(tvp2
->vital_header
.freePtr
))
707 tvp1
->vital_header
.freePtr
=
708 htonl(ntohl(tvp2
->vital_header
.freePtr
) + diff
);
709 if (ntohl(tvp2
->vital_header
.eofPtr
))
710 tvp1
->vital_header
.eofPtr
=
711 htonl(ntohl(tvp2
->vital_header
.eofPtr
) + diff
);
712 tvp1
->vital_header
.allocs
= tvp2
->vital_header
.allocs
;
713 tvp1
->vital_header
.frees
= tvp2
->vital_header
.frees
;
714 tvp1
->vital_header
.MaxVolumeId
= tvp2
->vital_header
.MaxVolumeId
;
715 for (i
= 0; i
< 3; i
++)
716 tvp1
->vital_header
.totalEntries
[i
] =
717 tvp2
->vital_header
.totalEntries
[i
];
719 for (i
= 0; i
< 31; i
++)
720 tvp1
->IpMappedAddr
[i
] = tvp2
->IpMappedAddr
[i
];
722 for (i
= 0; i
< 8191; i
++) {
723 if (ntohl(tvp2
->VolnameHash
[i
]))
724 tvp1
->VolnameHash
[i
] =
725 htonl(ntohl(tvp2
->VolnameHash
[i
]) + diff
);
728 for (i
= 0; i
< 3; i
++) {
729 for (j
= 0; j
< 8191; j
++) {
730 if (ntohl(tvp2
->VolidHash
[i
][j
]))
731 tvp1
->VolidHash
[i
][j
] =
732 htonl(ntohl(tvp2
->VolidHash
[i
][j
]) + diff
);
736 w
= write(fd
, tvp1
, sizeof(struct vlheader_1
));
737 if (w
!= sizeof(struct vlheader_2
)) {
738 printf("Write of header failed %d; error %u\n", w
, errno
);
742 /* for garbage-collecting... */
743 for (i
= 0; i
< 31; i
++)
744 tvp1
->IpMappedAddr
[i
] = 0;
753 /* Convert an address pointer to a vlentry from version 4 to version 3.
754 * This involves checking if the address is after any of the four
755 * MH block and if it is, subtract the size of the MH block.
757 * In going from version 4 to 3, the mh blocks go away and all entries
758 * move up in their place. The adresses then need to be updated.
760 * Before this can be called, the routine read_mhentries must be called.
763 Conv4to3(afs_uint32 addr
)
768 if (!base
[0] || !addr
)
772 for (i
= 0; i
< VL_MAX_ADDREXTBLKS
; i
++) {
773 if (base
[i
] && base
[0]->ex_contaddrs
[i
]
774 && (addr
> base
[0]->ex_contaddrs
[i
]))
775 raddr
-= VL_ADDREXTBLK_SIZE
;
781 /* this only works because the vlheader struct is essentially the same
782 * from version 1 to version 2 -- that is, the first bunch of fields
783 * aren't any more or any larger, so they match up pretty well.
787 convert_vlentry(int new, int fromvers
, int tovers
,
788 struct vlheader_1
*oldheader
, struct vlheader_1
*newheader
,
789 struct vlentry_1
*vlentryp
)
792 struct vlentry_3
*vl3p
= (struct vlentry_3
*)vlentryp
;
794 /* For mh information blocks,
795 * If going to version 4 or greater, keep the mh info block.
796 * Otherwise, don't keep it (version 3 and earlier don't have them).
798 if (vl3p
->flags
== VLCONTBLOCK
) {
800 w
= write(new, vlentryp
, VL_ADDREXTBLK_SIZE
);
801 if (w
!= VL_ADDREXTBLK_SIZE
) {
802 printf("Write of mh info block failed %d; error %u\n", w
,
810 if (fromvers
== 2 && tovers
== 3) {
813 vl
.volumeId
[0] = vlentryp
->volumeId
[0];
814 vl
.volumeId
[1] = vlentryp
->volumeId
[1];
815 vl
.volumeId
[2] = vlentryp
->volumeId
[2];
816 vl
.flags
= vlentryp
->flags
;
817 vl
.LockAfsId
= vlentryp
->LockAfsId
;
818 vl
.LockTimestamp
= vlentryp
->LockTimestamp
;
819 vl
.cloneId
= vlentryp
->cloneId
;
820 vl
.nextIdHash
[0] = vlentryp
->nextIdHash
[0];
821 vl
.nextIdHash
[1] = vlentryp
->nextIdHash
[1];
822 vl
.nextIdHash
[2] = vlentryp
->nextIdHash
[2];
823 vl
.nextNameHash
= vlentryp
->nextNameHash
;
824 memcpy(vl
.name
, vlentryp
->name
, 65);
825 for (i
= 0; i
< 8; i
++) {
826 vl
.serverNumber
[i
] = vlentryp
->serverNumber
[i
];
827 vl
.serverPartition
[i
] = vlentryp
->serverPartition
[i
];
828 vl
.serverFlags
[i
] = vlentryp
->serverFlags
[i
];
831 vl
.serverNumber
[i
] = vl
.serverPartition
[i
] = vl
.serverFlags
[i
] =
833 w
= write(new, &vl
, sizeof(struct vlentry_3
));
834 if (w
!= sizeof(struct vlentry_3
)) {
835 printf("Write of entry failed %d; error %u\n", w
, errno
);
840 } else if (fromvers
== 3 && tovers
== 2) {
842 struct vlentry_3
*xnvlentry
= (struct vlentry_3
*)vlentryp
;
844 memset(&vl
, 0, sizeof(struct vlentry_2
));
845 vl
.volumeId
[0] = xnvlentry
->volumeId
[0];
846 vl
.volumeId
[1] = xnvlentry
->volumeId
[1];
847 vl
.volumeId
[2] = xnvlentry
->volumeId
[2];
848 vl
.flags
= xnvlentry
->flags
;
849 vl
.LockAfsId
= xnvlentry
->LockAfsId
;
850 vl
.LockTimestamp
= xnvlentry
->LockTimestamp
;
851 vl
.cloneId
= xnvlentry
->cloneId
;
852 for (i
= 0; i
< 3; i
++) {
853 if (ntohl(xnvlentry
->nextIdHash
[i
]))
854 vl
.nextIdHash
[i
] = xnvlentry
->nextIdHash
[i
];
856 if (ntohl(xnvlentry
->nextNameHash
))
857 vl
.nextNameHash
= xnvlentry
->nextNameHash
;
858 memcpy(vl
.name
, xnvlentry
->name
, 65);
859 for (i
= 0; i
< 8; i
++) {
860 vl
.serverNumber
[i
] = xnvlentry
->serverNumber
[i
];
861 vl
.serverPartition
[i
] = xnvlentry
->serverPartition
[i
];
862 vl
.serverFlags
[i
] = xnvlentry
->serverFlags
[i
];
864 w
= write(new, &vl
, sizeof(struct vlentry_2
));
865 if (w
!= sizeof(struct vlentry_2
)) {
866 printf("Write of entry failed %d; error %u\n", w
, errno
);
870 } else if (fromvers
== 3 && tovers
== 1) {
872 struct vlentry_3
*xnvlentry
= (struct vlentry_3
*)vlentryp
;
876 1 ? sizeof(struct vlheader_1
) : sizeof(struct vlheader_2
))
878 1 ? sizeof(struct vlheader_1
) : sizeof(struct vlheader_2
));
879 memset(&vl
, 0, sizeof(struct vlentry_1
));
880 vl
.volumeId
[0] = xnvlentry
->volumeId
[0];
881 vl
.volumeId
[1] = xnvlentry
->volumeId
[1];
882 vl
.volumeId
[2] = xnvlentry
->volumeId
[2];
883 vl
.flags
= xnvlentry
->flags
;
884 vl
.LockAfsId
= xnvlentry
->LockAfsId
;
885 vl
.LockTimestamp
= xnvlentry
->LockTimestamp
;
886 vl
.cloneId
= xnvlentry
->cloneId
;
887 for (i
= 0; i
< 3; i
++) {
888 if (ntohl(xnvlentry
->nextIdHash
[i
]))
890 htonl(ntohl(xnvlentry
->nextIdHash
[i
]) + diff
);
892 if (ntohl(xnvlentry
->nextNameHash
))
893 vl
.nextNameHash
= htonl(ntohl(xnvlentry
->nextNameHash
) + diff
);
895 memcpy(vl
.name
, xnvlentry
->name
, 65);
896 for (i
= 0; i
< 8; i
++) {
897 vl
.serverNumber
[i
] = xnvlentry
->serverNumber
[i
];
898 vl
.serverPartition
[i
] = xnvlentry
->serverPartition
[i
];
899 vl
.serverFlags
[i
] = xnvlentry
->serverFlags
[i
];
901 for (i
= 0; i
< 8; i
++) {
902 s
= xnvlentry
->serverNumber
[i
];
904 if (s
> MaxServers
[tovers
- 1]) {
906 "%s: Too Many Servers (%d) for this version!\n",
910 newheader
->IpMappedAddr
[s
] = oldheader
->IpMappedAddr
[s
];
913 w
= write(new, &vl
, sizeof(struct vlentry_1
));
914 if (w
!= sizeof(struct vlentry_1
)) {
915 printf("Write of entry failed %d; error %u\n", w
, errno
);
919 } else if (fromvers
== 4 && tovers
== 3) {
921 /* We are converting from version 4 to 3. In this conversion, mh info
922 * blocks go away and all vlentries after them move up in the vldb file.
923 * When this happens, the linked list pointers need to be updated.
925 memcpy(&vl
, vlentryp
, sizeof(vl
));
926 for (i
= 0; i
< 3; i
++) {
927 vl
.nextIdHash
[i
] = Conv4to3(vl
.nextIdHash
[i
]);
929 vl
.nextNameHash
= Conv4to3(vl
.nextNameHash
);
931 w
= write(new, &vl
, sizeof(vl
));
932 if (w
!= sizeof(vl
)) {
933 printf("Write of entry failed %d; error %u\n", w
, errno
);
940 w
= write(new, vlentryp
, sizeof(struct vlentry_1
));
941 if (w
!= sizeof(struct vlentry_1
)) {
942 printf("Write of entry failed %d; error %u\n", w
, errno
);
945 } else if (tovers
== 2) {
946 w
= write(new, vlentryp
, sizeof(struct vlentry_2
));
947 if (w
!= sizeof(struct vlentry_2
)) {
948 printf("Write of entry failed %d; error %u\n", w
, errno
);
951 } else if (tovers
== 3 || tovers
== 4) {
952 w
= write(new, vlentryp
, sizeof(struct vlentry_3
));
953 if (w
!= sizeof(struct vlentry_3
)) {
954 printf("Write of entry failed %d; error %u\n", w
, errno
);
960 "Skipping vlentry write - db corrupted - bad toversion %d\n",
968 rewrite_header(int new, int tovers
, void *newheader
)
972 pos
= lseek(new, 64, L_SET
); /* leave room for ubik */
975 fprintf(stderr
, "%s: no garbage colection\n", pn
);
977 } else if (pos
!= 64) {
978 fprintf(stderr
, "%s: Can't rewind: no garbage collection\n", pn
);
984 1) ? sizeof(struct vlheader_1
) : sizeof(struct vlheader_2
));
985 w
= write(new, newheader
, towrite
);
987 printf("Write of entry failed %d; error %u\n", w
, errno
);
995 #include "AFS_component_version_number.c"
998 main(int argc
, char **argv
)
1000 struct cmd_syndesc
*ts
;
1003 ts
= cmd_CreateSyntax("initcmd", handleit
, NULL
, 0, "optional");
1004 cmd_AddParm(ts
, "-to", CMD_SINGLE
, CMD_OPTIONAL
, "goal version");
1005 cmd_AddParm(ts
, "-from", CMD_SINGLE
, CMD_OPTIONAL
, "current version");
1006 cmd_AddParm(ts
, "-path", CMD_SINGLE
, CMD_OPTIONAL
, "pathname");
1007 cmd_AddParm(ts
, "-showversion", CMD_FLAG
, CMD_OPTIONAL
,
1008 "Just display version of current vldb");
1009 cmd_AddParm(ts
, "-dumpvldb", CMD_FLAG
, CMD_OPTIONAL
,
1010 "display all vldb entries");
1013 cmd_AddParm(ts
, "-noGC", CMD_FLAG
, CMD_OPTIONAL
,
1014 "Don't do garbage collection");
1017 dbPath
= AFSDIR_SERVER_VLDB_FILEPATH
;
1019 code
= cmd_Dispatch(argc
, argv
);