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>
16 #include <sys/types.h>
20 #include "cnvldb.h" /* CHANGEME! */
21 #include <netinet/in.h>
22 #include <afs/venus.h>
24 #include <afs/afsutil.h>
25 #include <afs/fileutil.h>
30 #define MAXSIZE 2048 /* most I'll get back from PIOCTL */
31 #define BADSERVERID 255 /* XXX */
34 extern struct cmd_syndesc *cmd_CreateSyntax();
35 static char pn[] = "cnvldb";
36 static char tempname[] = "XXnewvldb";
37 static char space[MAXSIZE];
38 static int MaxServers[3] = {30,254,254};/* max server # permitted in this version*/
40 static afs_int32 Conv4to3();
42 static int convert_vlentry();
43 static int rewrite_header();
45 static char tspace[1024]; /* chdir can't handle anything bigger, anyway */
46 /* return a static pointer to a buffer */
47 static char *Parent(apath)
50 strcpy(tspace, apath);
51 tp = strrchr(tspace, '/');
55 else strcpy(tspace, ".");
60 int fromvers = 0, tovers = 0, showversion = 0;
63 char *pathname = NULL;
67 struct cmd_syndesc *as;
69 register struct cmd_item *ti;
70 register afs_int32 code;
71 int w, old, new, rc, dump=0, fromv=0;
73 char ubik[80]; /* space for some ubik header */
75 struct vlheader_1 header1;
76 struct vlheader_2 header2;
77 struct vlheader_3 header3;
78 } oldheader, oldheader1, newheader; /* large enough for either */
81 struct vlentry_1 entry1;
82 struct vlentry_2 entry2;
83 struct vlentry_3 entry3;
84 char mhinfo_block[VL_ADDREXTBLK_SIZE];
87 pathname = (as->parms[2].items ? as->parms[2].items->data : dbPath); /* -name */
88 showversion = (as->parms[3].items ? 1 : 0); /* -showversion */
89 dump = (as->parms[4].items ? 1 : 0); /* -dumpvldb */
90 fromvers = (as->parms[1].items ? atoi(as->parms[1].items->data) : 0); /* -fromversion */
91 tovers = (as->parms[0].items ? atoi(as->parms[0].items->data) : 0); /* -toversion */
93 /* should stat() the old vldb, get its size, and see if there's */
94 /* room for another. It might be in AFS, so check the quota, too */
95 old = open(pathname,O_RDONLY);
101 /* Read the version */
102 lseek(old, 64, L_SET);
103 read (old, &fromv, sizeof(int));
104 fromv = ntohl(fromv);
105 if ((fromv < 1) || (fromv > 4)) {
107 fprintf(stderr,": Unrecognized VLDB version %d.\n", fromv);
111 /* Sequentially read the database converting the entries as we go */
112 lseek(old, 0, L_SET);
113 read (old, ubik, 64);
114 readheader (old, fromv, &oldheader);
116 dbsize = ntohl(oldheader.header1.vital_header.eofPtr);
117 fromv = ntohl(oldheader.header1.vital_header.vldbversion);
119 } else if (fromv == 2) {
120 dbsize = ntohl(oldheader.header2.vital_header.eofPtr);
121 fromv = ntohl(oldheader.header2.vital_header.vldbversion);
126 dbsize = ntohl(oldheader.header3.vital_header.eofPtr);
127 fromv = ntohl(oldheader.header3.vital_header.vldbversion);
128 mhaddr = ntohl(oldheader.header3.SIT);
130 /* Read the multihomed extent blocks in */
132 read_mhentries(mhaddr, old);
134 /* Position back to this after header */
135 lseek(old, pos+64, L_SET);
139 if (showversion || dump) {
141 fprintf(stdout, "%s has a version of %d\n", pathname, fromv);
143 while (oldpos < dbsize) {
144 rc = readentry(old, fromv, &xvlentry);
145 if ((rc == 0) || (rc == EOF)) break;
146 printentry(fromv, &xvlentry);
152 if (!fromvers) { /* not set */
154 } else if (fromvers != fromv) {
155 fprintf(stdout, "%s has a version of %d while the -fromversion specified was %d - aborting\n",
156 pathname, fromv, fromvers);
160 if ((fromvers < 1) || (fromvers > 4)) {
162 fprintf(stderr,": VLDB version %d is not supported.\n",fromvers);
164 fprintf(stderr, ": Only versions 1-4 are currently supported.\n");
169 tovers = fromvers + 1;
171 if (tovers < 1 || tovers > 4 ) {
173 fprintf(stderr,": VLDB version %d is not supported.\n",tovers);
175 fprintf(stderr, ": Only versions 1 - 4 are currently supported.\n");
179 if (mhaddr && (tovers < 3)) {
181 fprintf(stderr,": Cannot convert. VLDB contains multihome info.\n");
185 /* OK! let's get down to business... */
187 if (chdir(Parent(pathname))) {
192 new = open(tempname,O_WRONLY|O_CREAT|O_TRUNC,0600);
198 /* Write the UBIK data */
199 w = write (new, ubik, 64);
201 printf("Write of ubik header failed %d; error %u\n", w, errno);
205 /* Because we know that all the vldb entries are the same size and type we
206 * can just read them sequentially, fiddle with the fields, and write
207 * them out again. If we invent a vldb format that has different
208 * types of entries, then we're going to have to invent new logic for
209 * converting the vldb-- we'll probably have to chase down the various
210 * linked lists in turn, doing lseeks and the like.
213 convert_header(old, new, fromvers, tovers, &oldheader, &newheader);
214 while (oldpos < dbsize) {
215 rc = readentry(old, fromvers, &xvlentry);
216 if ((rc == 0) || (rc == EOF)) break;
217 convert_vlentry(new, fromvers, tovers, &oldheader, &newheader, &xvlentry);
220 /* We have now finished sequentially reading and writing the database.
221 * Now randomly offset into database and update multihome entries.
223 convert_mhentries(old, new, &newheader, fromvers, tovers);
224 rewrite_header(new, tovers, &newheader);
233 renamefile(tempname,pathname);
239 readheader(fd, version, addr)
248 hdrsize = sizeof(struct vlheader_1);
250 hdrsize = sizeof(struct vlheader_2);
252 size = read(fd, addr, hdrsize);
253 if (size > 0) oldpos += size;
258 readentry(fd, version, addr)
264 struct vlentry_3 *vl3p = (struct vlentry_3 *)addr;
267 toread = ((version == 1) ? sizeof(struct vlentry_1) : sizeof(struct vlentry_2));
268 rc = read(fd, addr, toread);
270 printf("Partial read of vlentry at pos %u: %d\n", oldpos, rc);
271 if (rc > 0) oldpos += rc;
273 /* Read a mhblock entry if there is one */
274 if ((rc > 0) && (vl3p->flags == VLCONTBLOCK)) {
275 if (!mhaddr) /* Remember first mh block */
276 mhaddr = oldpos - rc;
278 rc1 = read(fd, &addr[rc], VL_ADDREXTBLK_SIZE-rc);
279 if (rc1 != VL_ADDREXTBLK_SIZE-rc)
280 printf("Partial read of mhblock at pos %u: %d\n", oldpos+rc, rc1);
290 printentry(version, addr)
294 struct vlentry_2 *vl2p = (struct vlentry_2 *)addr;
295 struct vlentry_3 *vl3p = (struct vlentry_3 *)addr;
298 /* Don't print anything if the entry is a mh info block */
299 if (vl3p->flags == VLCONTBLOCK) {
303 if (version == 1 || version == 2) {
304 printf("%s\t%5d [%10d:%10d:%10d]%8X%8d\n",
305 vl2p->name, vl2p->spares3,
306 vl2p->volumeId[0], vl2p->volumeId[1], vl2p->volumeId[2],
307 vl2p->flags, vl2p->LockAfsId);
308 printf("\t%8d%8d%8d [%7d%7d%7d]%7d% [%4d%4d%4d%4d][%4d%4d%4d%4d]\n",
309 vl2p->LockTimestamp, vl2p->cloneId, vl2p->spares0,
310 vl2p->nextIdHash[0], vl2p->nextIdHash[1], vl2p->nextIdHash[2],
312 vl2p->serverNumber[0], vl2p->serverNumber[1],
313 vl2p->serverNumber[2], vl2p->serverNumber[3],
314 vl2p->serverPartition[0], vl2p->serverPartition[1],
315 vl2p->serverPartition[2], vl2p->serverPartition[3]);
316 printf("\t[%4d%4d%4d%4d]\n",
317 vl2p->serverFlags[0], vl2p->serverFlags[1],
318 vl2p->serverFlags[2], vl2p->serverFlags[3]);
319 } else /* if (version >= 3) */ {
320 if (vl3p->flags == VLFREE)
322 printf("%s\tPos=%d NextIdHash=[%d:%d:%d] NextNameHash=%d\n",
324 (oldpos - sizeof(struct vlentry_3)),
325 vl3p->nextIdHash[0], vl3p->nextIdHash[1], vl3p->nextIdHash[2],
327 printf("\tRW=%u RO=%u BK=%u CL=%u flags=0x%X lockBy=%d lockTime=%u\n",
328 vl3p->volumeId[0], vl3p->volumeId[1], vl3p->volumeId[2], vl3p->cloneId,
329 vl3p->flags, vl3p->LockAfsId, vl3p->LockTimestamp);
330 for (i=0; i<OMAXNSERVERS; i++) {
331 if ((vl3p->serverNumber[i] & 0xff) != 0xff) {
332 printf("\tServer=%d Partition=%d flags=%X\n",
333 vl3p->serverNumber[i], vl3p->serverPartition[i],
334 vl3p->serverFlags[i]);
341 int readmhentries = 0;
342 struct extentaddr *base[VL_MAX_ADDREXTBLKS];
344 /* Read the multihome extent blocks in. Check if they are good by
345 * verifying their address is not pass the EOF and the flags are good.
346 * If it's not good, then don't read the block in.
348 read_mhentries(mh_addr, oldfd)
360 /* Initialize base pointers */
361 for (j=0; j < VL_MAX_ADDREXTBLKS; j++)
367 /* Check if the first extent block is beyond eof. If
368 * it is, it's not real.
370 if (mh_addr > dbsize-VL_ADDREXTBLK_SIZE)
373 /* Now read the first mh extent block */
374 code = lseek(oldfd, mh_addr+64, L_SET);
376 perror("seek MH block");
379 base[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
384 code = read(oldfd, (char *)base[0], VL_ADDREXTBLK_SIZE);
385 if (code != VL_ADDREXTBLK_SIZE) {
386 perror("read MH block");
392 /* Verify that this block is the right one */
393 if (ntohl(base[0]->ex_flags) != VLCONTBLOCK) { /* check if flag is correct */
399 /* The first block contains pointers to the other extent blocks.
400 * Check to see if the pointers are good and read them in if they are.
403 for (j=1; j < VL_MAX_ADDREXTBLKS; j++) {
404 if (!base[0]->ex_contaddrs[j])
407 sit = ntohl(base[0]->ex_contaddrs[j]);
409 /* Every time we allocate a new extent block, it is allocated after
410 * the previous ones. But it must be before the EOF.
412 if ((sit < (a + VL_ADDREXTBLK_SIZE)) || (sit > dbsize - VL_ADDREXTBLK_SIZE)) {
416 /* Read the extent block in */
418 code = lseek(oldfd, sit, L_SET);
420 perror("seek MH block");
423 base[j] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
428 code = read(oldfd, (char *)base[j], VL_ADDREXTBLK_SIZE);
429 if (code != VL_ADDREXTBLK_SIZE) {
430 perror("read MH block");
434 /* Verify that this block knows its an extent block */
435 if (ntohl(base[j]->ex_flags) != VLCONTBLOCK) {
441 /* The extent block passed our tests */
442 a = ntohl(base[0]->ex_contaddrs[j]);
446 /* Follow the SIT pointer in the header (mhaddr) to the multihomed
447 * extent blocks and verify that the pointers are good. And fix.
448 * Then convert the multihomed addresses to single address if we
449 * are converting back from version 4.
451 * Before this can be called, the routine read_mhentries must be called.
453 convert_mhentries(oldfd, newfd, header, fromver, tover)
455 struct vlheader_2 *header;
460 int i, j, modified=0, w;
461 afs_uint32 raddr, addr;
462 struct extentaddr *exp;
465 /* Check if the header says the extent block exists. If
466 * it does, then read_mhentries should have read it in.
468 if (mhaddr && !base[0]) {
469 printf("Fix Bad base extent block pointer\n");
470 header->SIT = mhaddr = 0;
471 } else if (mhaddr && base[0]) {
473 if ((ntohl(header->SIT) != mhaddr) && (tover == 4)) {
474 printf("Fix pointer to first base extent block. Was 0x%x, now 0x%x\n",
475 ntohl(header->SIT), mhaddr);
476 header->SIT = htonl(mhaddr);
479 /* Check if the first block points to itself. If not, then fix it */
480 if (ntohl(base[0]->ex_contaddrs[0]) != mhaddr) {
481 printf("Fix bad pointer in base extent block: Base 0\n");
482 base[0]->ex_contaddrs[0] = htonl(mhaddr);
486 /* The first block contains pointers to the other extent blocks.
487 * Check to see if the pointers are good.
489 for (j=1; j < VL_MAX_ADDREXTBLKS; j++) {
490 /* Check if the base extent block says the extent blocks exist.
491 * If it does, then read_mhentries should have read it in.
493 if (base[0]->ex_contaddrs[j] && !base[j]) {
494 printf("Fix bad pointer in base extent block: Base %d\n", j);
495 base[0]->ex_contaddrs[j] = 0;
500 /* Now write out the base extent blocks if it changed */
502 code = lseek(newfd, mhaddr+64, L_SET);
504 perror("seek MH Block");
507 w = write(newfd, (char *)base[0], VL_ADDREXTBLK_SIZE);
508 if (w != VL_ADDREXTBLK_SIZE) {
509 perror("write MH Block");
515 /* If we are converting from version 4 to version 3, then
516 * translate any multihome ptrs in the IpMappedAddr array
517 * to true IP addresses.
519 if ((fromver == 4) && (tover == 3)) {
520 /* Step through the fileserver addresses in the VLDB header
521 * and convert the pointers back to IP addresses.
523 for (i=0; i<254; i++) {
524 addr = ntohl(header->IpMappedAddr[i]);
525 if (addr && ((addr & 0xff000000) == 0xff000000)) {
526 basei = (addr >> 16) & 0xff;
527 index = addr & 0xffff;
529 if ((basei >= VL_ADDREXTBLK_SIZE) || !base[basei]) {
530 fprintf(stderr, "Warning: mh entry %d has no IP address; ignored!!\n", i);
531 header->IpMappedAddr[i] = 0;
534 exp = &base[basei][index];
536 /* For now return the first ip address back */
537 for (j=0; j < VL_MAXIPADDRS_PERMH; j++) {
538 if (exp->ex_addrs[j]) {
539 raddr = ntohl(exp->ex_addrs[j]);
543 if (j >= VL_MAXIPADDRS_PERMH) {
544 fprintf(stderr, "Warning: mh entry %d has no ip address; ignored!!\n", i);
547 printf("Multi-homed addr: converting to single ip address %d.%d.%d.%d\n",
548 (raddr>>24 & 0xff), (raddr>>16 & 0xff),
549 (raddr>>8 & 0xff), (raddr & 0xff));
551 header->IpMappedAddr[i] = htonl(raddr);
554 header->SIT = mhaddr = 0; /* mhinfo block has been removed */
556 /* Now step through the hash tables in header updating them.
557 * Because we removed the mh info blocks and some entries they
558 * point to may have changed position.
561 for (i=0; i<8191; i++) {
562 header->VolnameHash[i] = Conv4to3(header->VolnameHash[i]);
565 for (i=0; i<3; i++) {
566 for (j=0; j<8191; j++) {
567 header->VolidHash[i][j] = Conv4to3(header->VolidHash[i][j]);
571 /* Update eofptr to take into account the removal of the mhinfo blocks */
572 header->vital_header.eofPtr = htonl(Conv4to3(dbsize));
577 convert_header(ofd, fd, fromv, tov, fromaddr, toaddr)
578 int ofd, fd, fromv, tov;
579 char *fromaddr, *toaddr;
581 struct vlheader_1 *tvp1;
582 struct vlheader_2 *tvp2;
587 memcpy(toaddr, fromaddr, sizeof(struct vlheader_1));
588 tvp1 = (struct vlheader_1 *) toaddr;
590 w = write (fd, tvp1, sizeof(struct vlheader_1));
591 if (w != sizeof(struct vlheader_1)) {
592 printf("Write of header failed %d; error %u\n", w, errno);
596 /* for garbage-collecting... */
598 tvp1->IpMappedAddr[i] = 0;
600 } else if (tov == 2 || tov == 3) {
601 tvp1 = (struct vlheader_1 *) fromaddr;
602 tvp2 = (struct vlheader_2 *) toaddr;
603 memset(tvp2, 0, sizeof(struct vlheader_2));
604 tvp2->vital_header.vldbversion = htonl(tov);
605 tvp2->vital_header.headersize = htonl(sizeof(struct vlheader_2));
606 diff = ntohl(tvp2->vital_header.headersize) -
607 ntohl(tvp1->vital_header.headersize);
608 if (ntohl(tvp1->vital_header.freePtr))
609 tvp2->vital_header.freePtr = htonl(ntohl(tvp1->vital_header.freePtr) + diff);
610 if (ntohl(tvp1->vital_header.eofPtr))
611 tvp2->vital_header.eofPtr = htonl(ntohl(tvp1->vital_header.eofPtr) + diff);
612 tvp2->vital_header.allocs = tvp1->vital_header.allocs;
613 tvp2->vital_header.frees = tvp1->vital_header.frees;
614 tvp2->vital_header.MaxVolumeId = tvp1->vital_header.MaxVolumeId;
616 tvp2->vital_header.totalEntries[i] = tvp1->vital_header.totalEntries[i];
619 tvp2->IpMappedAddr[i] = tvp1->IpMappedAddr[i];
621 for (i=0;i<8191;i++) {
622 if (ntohl(tvp1->VolnameHash[i]))
623 tvp2->VolnameHash[i] = htonl(ntohl(tvp1->VolnameHash[i]) + diff);
627 for (j=0;j<8191;j++) {
628 if (ntohl(tvp1->VolidHash[i][j]))
629 tvp2->VolidHash[i][j] = htonl(ntohl(tvp1->VolidHash[i][j]) + diff);
633 w = write (fd, tvp2, sizeof(struct vlheader_2));
634 if (w != sizeof(struct vlheader_2)) {
635 printf("Write of header failed %d; error %u\n", w, errno);
639 /* for garbage-collecting... */
641 tvp2->IpMappedAddr[i] = 0;
644 } else if (fromv == 2 || fromv == 3 || fromv == 4) {
645 if (tov == 2 || tov == 3 || tov == 4) {
646 memcpy(toaddr, fromaddr, sizeof(struct vlheader_2));
647 tvp2 = (struct vlheader_2 *) toaddr;
648 tvp2->vital_header.vldbversion = htonl(tov);
649 w = write (fd, tvp2, sizeof(struct vlheader_2));
650 if (w != sizeof(struct vlheader_2)) {
651 printf("Write of header failed %d; error %u\n", w, errno);
655 } else if (tov == 1) {
656 tvp2 = (struct vlheader_2 *) fromaddr;
657 tvp1 = (struct vlheader_1 *) toaddr;
658 memset(tvp1, 0, sizeof(struct vlheader_1));
659 tvp1->vital_header.vldbversion = htonl(1);
660 tvp1->vital_header.headersize = htonl(sizeof(struct vlheader_1));
661 diff = ntohl(tvp1->vital_header.headersize) - ntohl(tvp2->vital_header.headersize);
662 if (ntohl(tvp2->vital_header.freePtr))
663 tvp1->vital_header.freePtr = htonl(ntohl(tvp2->vital_header.freePtr) + diff);
664 if (ntohl(tvp2->vital_header.eofPtr))
665 tvp1->vital_header.eofPtr = htonl(ntohl(tvp2->vital_header.eofPtr) + diff);
666 tvp1->vital_header.allocs = tvp2->vital_header.allocs;
667 tvp1->vital_header.frees = tvp2->vital_header.frees;
668 tvp1->vital_header.MaxVolumeId = tvp2->vital_header.MaxVolumeId;
670 tvp1->vital_header.totalEntries[i] = tvp2->vital_header.totalEntries[i];
673 tvp1->IpMappedAddr[i] = tvp2->IpMappedAddr[i];
675 for (i=0;i<8191;i++) {
676 if (ntohl(tvp2->VolnameHash[i]))
677 tvp1->VolnameHash[i] = htonl(ntohl(tvp2->VolnameHash[i]) + diff);
681 for (j=0;j<8191;j++) {
682 if (ntohl(tvp2->VolidHash[i][j]))
683 tvp1->VolidHash[i][j] = htonl(ntohl(tvp2->VolidHash[i][j]) + diff);
687 w = write (fd, tvp1, sizeof(struct vlheader_1));
688 if (w != sizeof(struct vlheader_2)) {
689 printf("Write of header failed %d; error %u\n", w, errno);
693 /* for garbage-collecting... */
695 tvp1->IpMappedAddr[i] = 0;
704 /* Convert an address pointer to a vlentry from version 4 to version 3.
705 * This involves checking if the address is after any of the four
706 * MH block and if it is, subtract the size of the MH block.
708 * In going from version 4 to 3, the mh blocks go away and all entries
709 * move up in their place. The adresses then need to be updated.
711 * Before this can be called, the routine read_mhentries must be called.
713 static afs_int32 Conv4to3(addr)
719 if (!base[0] || !addr)
723 for (i=0; i<VL_MAX_ADDREXTBLKS; i++) {
724 if (base[i] && base[0]->ex_contaddrs[i] && (addr > base[0]->ex_contaddrs[i]))
725 raddr -= VL_ADDREXTBLK_SIZE;
731 /* this only works because the vlheader struct is essentially the same
732 * from version 1 to version 2 -- that is, the first bunch of fields
733 * aren't any more or any larger, so they match up pretty well.
737 convert_vlentry(new, fromvers, tovers, oldheader, newheader, vlentryp)
738 int new, fromvers, tovers;
739 struct vlheader_1 *oldheader, *newheader; /* close enough */
740 struct vlentry_1 *vlentryp; /* 1 and 2 are identical */
743 struct vlentry_3 *vl3p = (struct vlentry_3 *)vlentryp;
745 /* For mh information blocks,
746 * If going to version 4 or greater, keep the mh info block.
747 * Otherwise, don't keep it (version 3 and earlier don't have them).
749 if (vl3p->flags == VLCONTBLOCK) {
751 w = write (new, vlentryp, VL_ADDREXTBLK_SIZE);
752 if (w != VL_ADDREXTBLK_SIZE) {
753 printf("Write of mh info block failed %d; error %u\n", w, errno);
760 if (fromvers == 2 && tovers == 3) {
763 vl.volumeId[0] = vlentryp->volumeId[0];
764 vl.volumeId[1] = vlentryp->volumeId[1];
765 vl.volumeId[2] = vlentryp->volumeId[2];
766 vl.flags = vlentryp->flags;
767 vl.LockAfsId = vlentryp->LockAfsId;
768 vl.LockTimestamp = vlentryp->LockTimestamp;
769 vl.cloneId = vlentryp->cloneId;
770 vl.nextIdHash[0] = vlentryp->nextIdHash[0];
771 vl.nextIdHash[1] = vlentryp->nextIdHash[1];
772 vl.nextIdHash[2] = vlentryp->nextIdHash[2];
773 vl.nextNameHash = vlentryp->nextNameHash;
774 memcpy(vl.name, vlentryp->name, 65);
775 for (i = 0; i < 8; i++) {
776 vl.serverNumber[i] = vlentryp->serverNumber[i];
777 vl.serverPartition[i] = vlentryp->serverPartition[i];
778 vl.serverFlags[i] = vlentryp->serverFlags[i];
781 vl.serverNumber[i] = vl.serverPartition[i] = vl.serverFlags[i] = BADSERVERID;
782 w = write (new, &vl, sizeof(struct vlentry_3));
783 if (w != sizeof(struct vlentry_3)) {
784 printf("Write of entry failed %d; error %u\n", w, errno);
789 } else if (fromvers == 3 && tovers == 2) {
791 struct vlentry_3 *xnvlentry = (struct vlentry_3 *) vlentryp;
793 memset((char *)&vl, 0, sizeof (struct vlentry_2));
794 vl.volumeId[0] = xnvlentry->volumeId[0];
795 vl.volumeId[1] = xnvlentry->volumeId[1];
796 vl.volumeId[2] = xnvlentry->volumeId[2];
797 vl.flags = xnvlentry->flags;
798 vl.LockAfsId = xnvlentry->LockAfsId;
799 vl.LockTimestamp = xnvlentry->LockTimestamp;
800 vl.cloneId = xnvlentry->cloneId;
802 if (ntohl(xnvlentry->nextIdHash[i]))
803 vl.nextIdHash[i] = xnvlentry->nextIdHash[i];
805 if (ntohl(xnvlentry->nextNameHash))
806 vl.nextNameHash = xnvlentry->nextNameHash;
807 memcpy(vl.name, xnvlentry->name, 65);
808 for (i = 0; i < 8; i++) {
809 vl.serverNumber[i] = xnvlentry->serverNumber[i];
810 vl.serverPartition[i] = xnvlentry->serverPartition[i];
811 vl.serverFlags[i] = xnvlentry->serverFlags[i];
813 w = write (new, &vl, sizeof(struct vlentry_2));
814 if (w != sizeof(struct vlentry_2)) {
815 printf("Write of entry failed %d; error %u\n", w, errno);
819 } else if (fromvers == 3 && tovers == 1) {
821 struct vlentry_3 *xnvlentry = (struct vlentry_3 *) vlentryp;
823 diff = (tovers == 1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2))
824 - (fromvers == 1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2));
825 memset((char *)&vl, 0, sizeof (struct vlentry_1));
826 vl.volumeId[0] = xnvlentry->volumeId[0];
827 vl.volumeId[1] = xnvlentry->volumeId[1];
828 vl.volumeId[2] = xnvlentry->volumeId[2];
829 vl.flags = xnvlentry->flags;
830 vl.LockAfsId = xnvlentry->LockAfsId;
831 vl.LockTimestamp = xnvlentry->LockTimestamp;
832 vl.cloneId = xnvlentry->cloneId;
834 if (ntohl(xnvlentry->nextIdHash[i]))
835 vl.nextIdHash[i] = htonl(ntohl(xnvlentry->nextIdHash[i]) + diff);
837 if (ntohl(xnvlentry->nextNameHash))
838 vl.nextNameHash = htonl(ntohl(xnvlentry->nextNameHash) + diff);
840 memcpy(vl.name, xnvlentry->name, 65);
841 for (i = 0; i < 8; i++) {
842 vl.serverNumber[i] = xnvlentry->serverNumber[i];
843 vl.serverPartition[i] = xnvlentry->serverPartition[i];
844 vl.serverFlags[i] = xnvlentry->serverFlags[i];
847 s = xnvlentry->serverNumber[i];
849 if (s > MaxServers[tovers-1]) {
850 fprintf(stderr, "%s: Too Many Servers (%d) for this version!\n",pn,s+1);
853 newheader->IpMappedAddr[s] = oldheader->IpMappedAddr[s];
856 w = write (new, &vl, sizeof(struct vlentry_1));
857 if (w != sizeof(struct vlentry_1)) {
858 printf("Write of entry failed %d; error %u\n", w, errno);
862 } else if (fromvers == 4 && tovers == 3) {
864 /* We are converting from version 4 to 3. In this conversion, mh info
865 * blocks go away and all vlentries after them move up in the vldb file.
866 * When this happens, the linked list pointers need to be updated.
868 memcpy(&vl, vlentryp, sizeof(vl));
869 for (i=0; i<3; i++) {
870 vl.nextIdHash[i] = Conv4to3(vl.nextIdHash[i]);
872 vl.nextNameHash = Conv4to3(vl.nextNameHash);
874 w = write (new, &vl, sizeof(vl));
875 if (w != sizeof(vl)) {
876 printf("Write of entry failed %d; error %u\n", w, errno);
883 w = write (new, vlentryp, sizeof(struct vlentry_1));
884 if (w != sizeof(struct vlentry_1)) {
885 printf("Write of entry failed %d; error %u\n", w, errno);
888 } else if (tovers == 2) {
889 w = write (new, vlentryp, sizeof(struct vlentry_2));
890 if (w != sizeof(struct vlentry_2)) {
891 printf("Write of entry failed %d; error %u\n", w, errno);
894 } else if (tovers == 3 || tovers == 4) {
895 w = write (new, vlentryp, sizeof(struct vlentry_3));
896 if (w != sizeof(struct vlentry_3)) {
897 printf("Write of entry failed %d; error %u\n", w, errno);
902 fprintf(stderr, "Skipping vlentry write - db corrupted - bad toversion %d\n",
910 rewrite_header(new, tovers, newheader)
916 pos = lseek (new, 64, L_SET); /* leave room for ubik */
919 fprintf(stderr, "%s: no garbage colection\n",pn);
921 } else if (pos != 64) {
922 fprintf(stderr,"%s: Can't rewind: no garbage collection\n",pn);
926 towrite = ((tovers == 1) ? sizeof(struct vlheader_1) :
927 sizeof(struct vlheader_2));
928 w = write (new, newheader, towrite);
930 printf("Write of entry failed %d; error %u\n", w, errno);
938 #include "AFS_component_version_number.c"
944 register struct cmd_syndesc *ts;
947 ts = cmd_CreateSyntax("initcmd", handleit, 0, "optional");
948 cmd_AddParm(ts, "-to", CMD_SINGLE, CMD_OPTIONAL, "goal version");
949 cmd_AddParm(ts, "-from", CMD_SINGLE, CMD_OPTIONAL, "current version");
950 cmd_AddParm(ts, "-path", CMD_SINGLE, CMD_OPTIONAL, "pathname");
951 cmd_AddParm(ts, "-showversion", CMD_FLAG, CMD_OPTIONAL, "Just display version of current vldb");
952 cmd_AddParm(ts, "-dumpvldb", CMD_FLAG, CMD_OPTIONAL, "display all vldb entries");
955 cmd_AddParm(ts, "-noGC", CMD_FLAG, CMD_OPTIONAL, "Don't do garbage collection");
958 dbPath = AFSDIR_SERVER_VLDB_FILEPATH;
960 code = cmd_Dispatch(argc, argv);