dbe42d5aa92442f13635407de81c3968410b3a9a
[openafs.git] / src / vlserver / cnvldb.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #include <sys/types.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <sys/file.h>
21
22 #ifdef HAVE_STRING_H
23 #include <string.h>
24 #else
25 #ifdef HAVE_STRINGS_H
26 #include <strings.h>
27 #endif
28 #endif
29
30 #include "cnvldb.h"             /* CHANGEME! */
31 #include <netinet/in.h>
32 #include <afs/venus.h>
33 #include <afs/cmd.h>
34 #include <afs/afsutil.h>
35 #include <afs/fileutil.h>
36
37 #include "vlserver.h"
38
39 #define MAXSIZE 2048            /* most I'll get back from PIOCTL */
40 #define BADSERVERID     255     /* XXX */
41
42
43 extern struct cmd_syndesc *cmd_CreateSyntax();
44 static char pn[] = "cnvldb";
45 static char tempname[] = "XXnewvldb";
46 static char space[MAXSIZE];
47 static int MaxServers[3] = { 30, 254, 254 };    /* max server # permitted in this version */
48
49 static afs_int32 Conv4to3();
50
51 static int convert_vlentry();
52 static int rewrite_header();
53
54 static char tspace[1024];       /* chdir can't handle anything bigger, anyway */
55 /* return a static pointer to a buffer */
56 static char *
57 Parent(apath)
58      char *apath;
59 {
60     register char *tp;
61     strcpy(tspace, apath);
62     tp = strrchr(tspace, '/');
63     if (tp) {
64         *tp = 0;
65     } else
66         strcpy(tspace, ".");
67     return tspace;
68 }
69
70 int oldpos = 0;
71 int fromvers = 0, tovers = 0, showversion = 0;
72 afs_uint32 mhaddr;
73 afs_int32 dbsize;
74 char *pathname = NULL;
75 const char *dbPath;
76
77 static
78 handleit(as)
79      struct cmd_syndesc *as;
80 {
81     register struct cmd_item *ti;
82     register afs_int32 code;
83     int w, old, new, rc, dump = 0, fromv = 0;
84     short uvers;
85     char ubik[80];              /* space for some ubik header */
86     union {
87         struct vlheader_1 header1;
88         struct vlheader_2 header2;
89         struct vlheader_3 header3;
90     } oldheader, oldheader1, newheader; /* large enough for either */
91
92     union {
93         struct vlentry_1 entry1;
94         struct vlentry_2 entry2;
95         struct vlentry_3 entry3;
96         char mhinfo_block[VL_ADDREXTBLK_SIZE];
97     } xvlentry;
98
99     pathname = (as->parms[2].items ? as->parms[2].items->data : dbPath);        /* -name */
100     showversion = (as->parms[3].items ? 1 : 0); /* -showversion */
101     dump = (as->parms[4].items ? 1 : 0);        /* -dumpvldb */
102     fromvers = (as->parms[1].items ? atoi(as->parms[1].items->data) : 0);       /* -fromversion */
103     tovers = (as->parms[0].items ? atoi(as->parms[0].items->data) : 0); /* -toversion */
104
105     /* should stat() the old vldb, get its size, and see if there's */
106     /* room for another.  It might be in AFS, so check the quota, too */
107     old = open(pathname, O_RDONLY);
108     if (old < 0) {
109         perror(pn);
110         exit(-1);
111     }
112
113     /* Read the version */
114     lseek(old, 64, L_SET);
115     read(old, &fromv, sizeof(int));
116     fromv = ntohl(fromv);
117     if ((fromv < 1) || (fromv > 4)) {
118         fprintf(stderr, pn);
119         fprintf(stderr, ": Unrecognized VLDB version %d.\n", fromv);
120         exit(-1);
121     }
122
123     /* Sequentially read the database converting the entries as we go */
124     lseek(old, 0, L_SET);
125     read(old, ubik, 64);
126     readheader(old, fromv, &oldheader);
127     if (fromv == 1) {
128         dbsize = ntohl(oldheader.header1.vital_header.eofPtr);
129         fromv = ntohl(oldheader.header1.vital_header.vldbversion);
130         mhaddr = 0;
131     } else if (fromv == 2) {
132         dbsize = ntohl(oldheader.header2.vital_header.eofPtr);
133         fromv = ntohl(oldheader.header2.vital_header.vldbversion);
134         mhaddr = 0;
135     } else {
136         int pos;
137
138         dbsize = ntohl(oldheader.header3.vital_header.eofPtr);
139         fromv = ntohl(oldheader.header3.vital_header.vldbversion);
140         mhaddr = ntohl(oldheader.header3.SIT);
141
142         /* Read the multihomed extent blocks in */
143         pos = oldpos;
144         read_mhentries(mhaddr, old);
145
146         /* Position back to this after header */
147         lseek(old, pos + 64, L_SET);
148         oldpos = pos;
149     }
150
151     if (showversion || dump) {
152         if (showversion)
153             fprintf(stdout, "%s has a version of %d\n", pathname, fromv);
154         if (dump) {
155             while (oldpos < dbsize) {
156                 rc = readentry(old, fromv, &xvlentry);
157                 if ((rc == 0) || (rc == EOF))
158                     break;
159                 printentry(fromv, &xvlentry);
160             }
161         }
162         exit(0);
163     }
164
165     if (!fromvers) {            /* not set */
166         fromvers = fromv;
167     } else if (fromvers != fromv) {
168         fprintf(stdout,
169                 "%s has a version of %d while the -fromversion specified was %d - aborting\n",
170                 pathname, fromv, fromvers);
171         exit(0);
172     }
173
174     if ((fromvers < 1) || (fromvers > 4)) {
175         fprintf(stderr, pn);
176         fprintf(stderr, ": VLDB version %d is not supported.\n", fromvers);
177         fprintf(stderr, pn);
178         fprintf(stderr, ": Only versions 1-4 are currently supported.\n");
179         exit(-1);
180     }
181
182     if (!tovers)
183         tovers = fromvers + 1;
184
185     if (tovers < 1 || tovers > 4) {
186         fprintf(stderr, pn);
187         fprintf(stderr, ": VLDB version %d is not supported.\n", tovers);
188         fprintf(stderr, pn);
189         fprintf(stderr, ": Only versions 1 - 4 are currently supported.\n");
190         exit(-1);
191     }
192
193     if (mhaddr && (tovers < 3)) {
194         fprintf(stderr, pn);
195         fprintf(stderr, ": Cannot convert. VLDB contains multihome info.\n");
196         exit(-1);
197     }
198
199     /* OK! let's get down to business... */
200
201     if (chdir(Parent(pathname))) {
202         perror(pn);
203         exit(-1);
204     }
205
206     new = open(tempname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
207     if (new < 0) {
208         perror(pn);
209         exit(-1);
210     }
211
212     /* Write the UBIK data */
213     w = write(new, ubik, 64);
214     if (w != 64) {
215         printf("Write of ubik header failed %d; error %u\n", w, errno);
216         exit(1);
217     }
218
219     /* Because we know that all the vldb entries are the same size and type we 
220      * can just read them sequentially, fiddle with the fields, and write
221      * them out again.  If we invent a vldb format that has different
222      * types of entries, then we're going to have to invent new logic for
223      * converting the vldb-- we'll probably have to chase down the various
224      * linked lists in turn, doing lseeks and the like.
225      */
226
227     convert_header(old, new, fromvers, tovers, &oldheader, &newheader);
228     while (oldpos < dbsize) {
229         rc = readentry(old, fromvers, &xvlentry);
230         if ((rc == 0) || (rc == EOF))
231             break;
232         convert_vlentry(new, fromvers, tovers, &oldheader, &newheader,
233                         &xvlentry);
234     }
235
236     /* We have now finished sequentially reading and writing the database.
237      * Now randomly offset into database and update multihome entries.
238      */
239     convert_mhentries(old, new, &newheader, fromvers, tovers);
240     rewrite_header(new, tovers, &newheader);
241
242     close(old);
243     if (fsync(new)) {
244         perror(pn);
245         exit(-1);
246     }
247     close(new);
248
249     renamefile(tempname, pathname);
250     sleep(5);
251     exit(0);
252 }
253
254
255 readheader(fd, version, addr)
256      int fd;
257      int version;
258      char *addr;
259 {
260     int hdrsize, size = 0;
261
262     oldpos = 0;
263     if (version == 1)
264         hdrsize = sizeof(struct vlheader_1);
265     else
266         hdrsize = sizeof(struct vlheader_2);
267
268     size = read(fd, addr, hdrsize);
269     if (size > 0)
270         oldpos += size;
271
272     return;
273 }
274
275 readentry(fd, version, addr)
276      int fd;
277      int version;
278      char *addr;
279 {
280     int rc, rc1;
281     struct vlentry_3 *vl3p = (struct vlentry_3 *)addr;
282     int toread;
283
284     toread =
285         ((version ==
286           1) ? sizeof(struct vlentry_1) : sizeof(struct vlentry_2));
287     rc = read(fd, addr, toread);
288     if (rc != toread)
289         printf("Partial read of vlentry at pos %u: %d\n", oldpos, rc);
290     if (rc > 0)
291         oldpos += rc;
292
293     /* Read a mhblock entry if there is one */
294     if ((rc > 0) && (vl3p->flags == VLCONTBLOCK)) {
295         if (!mhaddr)            /* Remember first mh block */
296             mhaddr = oldpos - rc;
297
298         rc1 = read(fd, &addr[rc], VL_ADDREXTBLK_SIZE - rc);
299         if (rc1 != VL_ADDREXTBLK_SIZE - rc)
300             printf("Partial read of mhblock at pos %u: %d\n", oldpos + rc,
301                    rc1);
302         if (rc1 > 0) {
303             oldpos += rc1;
304             rc += rc1;
305         }
306     }
307
308     return rc;
309 }
310
311 printentry(version, addr)
312      int version;
313      char *addr;
314 {
315     struct vlentry_2 *vl2p = (struct vlentry_2 *)addr;
316     struct vlentry_3 *vl3p = (struct vlentry_3 *)addr;
317     int i;
318
319     /* Don't print anything if the entry is a mh info block */
320     if (vl3p->flags == VLCONTBLOCK) {
321         return;
322     }
323
324     if (version == 1 || version == 2) {
325         printf("%s\t%5d [%10d:%10d:%10d]%8X%8d\n", vl2p->name, vl2p->spares3,
326                vl2p->volumeId[0], vl2p->volumeId[1], vl2p->volumeId[2],
327                vl2p->flags, vl2p->LockAfsId);
328         printf("\t%8d%8d%8d [%7d%7d%7d]%7d% [%4d%4d%4d%4d][%4d%4d%4d%4d]\n",
329                vl2p->LockTimestamp, vl2p->cloneId, vl2p->spares0,
330                vl2p->nextIdHash[0], vl2p->nextIdHash[1], vl2p->nextIdHash[2],
331                vl2p->nextNameHash, vl2p->serverNumber[0],
332                vl2p->serverNumber[1], vl2p->serverNumber[2],
333                vl2p->serverNumber[3], vl2p->serverPartition[0],
334                vl2p->serverPartition[1], vl2p->serverPartition[2],
335                vl2p->serverPartition[3]);
336         printf("\t[%4d%4d%4d%4d]\n", vl2p->serverFlags[0],
337                vl2p->serverFlags[1], vl2p->serverFlags[2],
338                vl2p->serverFlags[3]);
339     } else {                    /* if (version >= 3) */
340
341         if (vl3p->flags == VLFREE)
342             return;
343         printf("%s\tPos=%d NextIdHash=[%d:%d:%d] NextNameHash=%d\n",
344                vl3p->name, (oldpos - sizeof(struct vlentry_3)),
345                vl3p->nextIdHash[0], vl3p->nextIdHash[1], vl3p->nextIdHash[2],
346                vl3p->nextNameHash);
347         printf("\tRW=%u RO=%u BK=%u CL=%u flags=0x%X lockBy=%d lockTime=%u\n",
348                vl3p->volumeId[0], vl3p->volumeId[1], vl3p->volumeId[2],
349                vl3p->cloneId, vl3p->flags, vl3p->LockAfsId,
350                vl3p->LockTimestamp);
351         for (i = 0; i < OMAXNSERVERS; i++) {
352             if ((vl3p->serverNumber[i] & 0xff) != 0xff) {
353                 printf("\tServer=%d Partition=%d flags=%X\n",
354                        vl3p->serverNumber[i], vl3p->serverPartition[i],
355                        vl3p->serverFlags[i]);
356             }
357         }
358     }
359     return;
360 }
361
362 int readmhentries = 0;
363 struct extentaddr *base[VL_MAX_ADDREXTBLKS];
364
365 /* Read the multihome extent blocks in. Check if they are good by
366  * verifying their address is not pass the EOF and the flags are good.
367  * If it's not good, then don't read the block in.
368  */
369 read_mhentries(mh_addr, oldfd)
370      int oldfd;
371      afs_uint32 mh_addr;
372 {
373     afs_uint32 sit, a;
374     afs_int32 code;
375     int j;
376
377     if (readmhentries)
378         return;
379     readmhentries = 1;
380
381     /* Initialize base pointers */
382     for (j = 0; j < VL_MAX_ADDREXTBLKS; j++)
383         base[j] = 0;
384
385     if (!mh_addr)
386         return;
387
388     /* Check if the first extent block is beyond eof. If 
389      * it is, it's not real.
390      */
391     if (mh_addr > dbsize - VL_ADDREXTBLK_SIZE)
392         return;
393
394     /* Now read the first mh extent block */
395     code = lseek(oldfd, mh_addr + 64, L_SET);
396     if (code < 0) {
397         perror("seek MH block");
398         exit(1);
399     }
400     base[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
401     if (!base[0]) {
402         perror("malloc1");
403         exit(1);
404     }
405     code = read(oldfd, (char *)base[0], VL_ADDREXTBLK_SIZE);
406     if (code != VL_ADDREXTBLK_SIZE) {
407         perror("read MH block");
408         free(base[0]);
409         base[0] = 0;
410         exit(1);
411     }
412
413     /* Verify that this block is the right one */
414     if (ntohl(base[0]->ex_flags) != VLCONTBLOCK) {      /* check if flag is correct */
415         free(base[0]);
416         base[0] = 0;
417         return;
418     }
419
420     /* The first block contains pointers to the other extent blocks.
421      * Check to see if the pointers are good and read them in if they are.
422      */
423     a = mh_addr;
424     for (j = 1; j < VL_MAX_ADDREXTBLKS; j++) {
425         if (!base[0]->ex_contaddrs[j])
426             continue;
427
428         sit = ntohl(base[0]->ex_contaddrs[j]);
429
430         /* Every time we allocate a new extent block, it is allocated after 
431          * the previous ones. But it must be before the EOF.
432          */
433         if ((sit < (a + VL_ADDREXTBLK_SIZE))
434             || (sit > dbsize - VL_ADDREXTBLK_SIZE)) {
435             continue;
436         }
437
438         /* Read the extent block in */
439         sit += 64;
440         code = lseek(oldfd, sit, L_SET);
441         if (code < 0) {
442             perror("seek MH block");
443             exit(1);
444         }
445         base[j] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
446         if (!base[j]) {
447             perror("malloc1");
448             exit(1);
449         }
450         code = read(oldfd, (char *)base[j], VL_ADDREXTBLK_SIZE);
451         if (code != VL_ADDREXTBLK_SIZE) {
452             perror("read MH block");
453             exit(1);
454         }
455
456         /* Verify that this block knows its an extent block */
457         if (ntohl(base[j]->ex_flags) != VLCONTBLOCK) {
458             free(base[j]);
459             base[j] = 0;
460             continue;
461         }
462
463         /* The extent block passed our tests */
464         a = ntohl(base[0]->ex_contaddrs[j]);
465     }
466 }
467
468 /* Follow the SIT pointer in the header (mhaddr) to the multihomed
469  * extent blocks and verify that the pointers are good. And fix.
470  * Then convert the multihomed addresses to single address if we
471  * are converting back from version 4.
472  * 
473  * Before this can be called, the routine read_mhentries must be called.
474  */
475 convert_mhentries(oldfd, newfd, header, fromver, tover)
476      int oldfd, newfd;
477      struct vlheader_2 *header;
478      int fromver, tover;
479 {
480     afs_uint32 sit;
481     afs_int32 code;
482     int i, j, modified = 0, w;
483     afs_uint32 raddr, addr;
484     struct extentaddr *exp;
485     int basei, index;
486
487     /* Check if the header says the extent block exists. If
488      * it does, then read_mhentries should have read it in.
489      */
490     if (mhaddr && !base[0]) {
491         printf("Fix Bad base extent block pointer\n");
492         header->SIT = mhaddr = 0;
493     } else if (mhaddr && base[0]) {
494
495         if ((ntohl(header->SIT) != mhaddr) && (tover == 4)) {
496             printf
497                 ("Fix pointer to first base extent block. Was 0x%x, now 0x%x\n",
498                  ntohl(header->SIT), mhaddr);
499             header->SIT = htonl(mhaddr);
500         }
501
502         /* Check if the first block points to itself. If not, then fix it */
503         if (ntohl(base[0]->ex_contaddrs[0]) != mhaddr) {
504             printf("Fix bad pointer in base extent block: Base 0\n");
505             base[0]->ex_contaddrs[0] = htonl(mhaddr);
506             modified = 1;
507         }
508
509         /* The first block contains pointers to the other extent blocks.
510          * Check to see if the pointers are good.
511          */
512         for (j = 1; j < VL_MAX_ADDREXTBLKS; j++) {
513             /* Check if the base extent block says the extent blocks exist.
514              * If it does, then read_mhentries should have read it in.
515              */
516             if (base[0]->ex_contaddrs[j] && !base[j]) {
517                 printf("Fix bad pointer in base extent block: Base %d\n", j);
518                 base[0]->ex_contaddrs[j] = 0;
519                 modified = 1;
520             }
521         }
522
523         /* Now write out the base extent blocks if it changed */
524         if (modified) {
525             code = lseek(newfd, mhaddr + 64, L_SET);
526             if (code < 0) {
527                 perror("seek MH Block");
528                 exit(1);
529             }
530             w = write(newfd, (char *)base[0], VL_ADDREXTBLK_SIZE);
531             if (w != VL_ADDREXTBLK_SIZE) {
532                 perror("write MH Block");
533                 exit(1);
534             }
535         }
536     }
537
538     /* If we are converting from version 4 to version 3, then 
539      * translate any multihome ptrs in the IpMappedAddr array
540      * to true IP addresses.
541      */
542     if ((fromver == 4) && (tover == 3)) {
543         /* Step through the fileserver addresses in the VLDB header
544          * and convert the pointers back to IP addresses.
545          */
546         for (i = 0; i < 254; i++) {
547             addr = ntohl(header->IpMappedAddr[i]);
548             if (addr && ((addr & 0xff000000) == 0xff000000)) {
549                 basei = (addr >> 16) & 0xff;
550                 index = addr & 0xffff;
551
552                 if ((basei >= VL_ADDREXTBLK_SIZE) || !base[basei]) {
553                     fprintf(stderr,
554                             "Warning: mh entry %d has no IP address; ignored!!\n",
555                             i);
556                     header->IpMappedAddr[i] = 0;
557                     continue;
558                 }
559                 exp = &base[basei][index];
560
561                 /* For now return the first ip address back */
562                 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
563                     if (exp->ex_addrs[j]) {
564                         raddr = ntohl(exp->ex_addrs[j]);
565                         break;
566                     }
567                 }
568                 if (j >= VL_MAXIPADDRS_PERMH) {
569                     fprintf(stderr,
570                             "Warning: mh entry %d has no ip address; ignored!!\n",
571                             i);
572                     raddr = 0;
573                 } else {
574                     printf
575                         ("Multi-homed addr: converting to single ip address %d.%d.%d.%d\n",
576                          (raddr >> 24 & 0xff), (raddr >> 16 & 0xff),
577                          (raddr >> 8 & 0xff), (raddr & 0xff));
578                 }
579                 header->IpMappedAddr[i] = htonl(raddr);
580             }
581         }
582         header->SIT = mhaddr = 0;       /* mhinfo block has been removed */
583
584         /* Now step through the hash tables in header updating them.
585          * Because we removed the mh info blocks and some entries they
586          * point to may have changed position.
587          * The VolnameHash
588          */
589         for (i = 0; i < 8191; i++) {
590             header->VolnameHash[i] = Conv4to3(header->VolnameHash[i]);
591         }
592         /* The VolidHash */
593         for (i = 0; i < 3; i++) {
594             for (j = 0; j < 8191; j++) {
595                 header->VolidHash[i][j] = Conv4to3(header->VolidHash[i][j]);
596             }
597         }
598
599         /* Update eofptr to take into account the removal of the mhinfo blocks */
600         header->vital_header.eofPtr = htonl(Conv4to3(dbsize));
601     }
602 }
603
604
605 convert_header(ofd, fd, fromv, tov, fromaddr, toaddr)
606      int ofd, fd, fromv, tov;
607      char *fromaddr, *toaddr;
608 {
609     struct vlheader_1 *tvp1;
610     struct vlheader_2 *tvp2;
611     int i, j, diff, w;
612
613     if (fromv == 1) {
614         if (tov == 1) {
615             memcpy(toaddr, fromaddr, sizeof(struct vlheader_1));
616             tvp1 = (struct vlheader_1 *)toaddr;
617
618             w = write(fd, tvp1, sizeof(struct vlheader_1));
619             if (w != sizeof(struct vlheader_1)) {
620                 printf("Write of header failed %d; error %u\n", w, errno);
621                 exit(1);
622             }
623
624             /* for garbage-collecting... */
625             for (i = 0; i < 31; i++)
626                 tvp1->IpMappedAddr[i] = 0;
627
628         } else if (tov == 2 || tov == 3) {
629             tvp1 = (struct vlheader_1 *)fromaddr;
630             tvp2 = (struct vlheader_2 *)toaddr;
631             memset(tvp2, 0, sizeof(struct vlheader_2));
632             tvp2->vital_header.vldbversion = htonl(tov);
633             tvp2->vital_header.headersize = htonl(sizeof(struct vlheader_2));
634             diff =
635                 ntohl(tvp2->vital_header.headersize) -
636                 ntohl(tvp1->vital_header.headersize);
637             if (ntohl(tvp1->vital_header.freePtr))
638                 tvp2->vital_header.freePtr =
639                     htonl(ntohl(tvp1->vital_header.freePtr) + diff);
640             if (ntohl(tvp1->vital_header.eofPtr))
641                 tvp2->vital_header.eofPtr =
642                     htonl(ntohl(tvp1->vital_header.eofPtr) + diff);
643             tvp2->vital_header.allocs = tvp1->vital_header.allocs;
644             tvp2->vital_header.frees = tvp1->vital_header.frees;
645             tvp2->vital_header.MaxVolumeId = tvp1->vital_header.MaxVolumeId;
646             for (i = 0; i < 3; i++)
647                 tvp2->vital_header.totalEntries[i] =
648                     tvp1->vital_header.totalEntries[i];
649
650             for (i = 0; i < 31; i++)
651                 tvp2->IpMappedAddr[i] = tvp1->IpMappedAddr[i];
652
653             for (i = 0; i < 8191; i++) {
654                 if (ntohl(tvp1->VolnameHash[i]))
655                     tvp2->VolnameHash[i] =
656                         htonl(ntohl(tvp1->VolnameHash[i]) + diff);
657             }
658
659             for (i = 0; i < 3; i++) {
660                 for (j = 0; j < 8191; j++) {
661                     if (ntohl(tvp1->VolidHash[i][j]))
662                         tvp2->VolidHash[i][j] =
663                             htonl(ntohl(tvp1->VolidHash[i][j]) + diff);
664                 }
665             }
666
667             w = write(fd, tvp2, sizeof(struct vlheader_2));
668             if (w != sizeof(struct vlheader_2)) {
669                 printf("Write of header failed %d; error %u\n", w, errno);
670                 exit(1);
671             }
672
673             /* for garbage-collecting... */
674             for (i = 0; i < 31; i++)
675                 tvp2->IpMappedAddr[i] = 0;
676         } else
677             return EINVAL;
678     } else if (fromv == 2 || fromv == 3 || fromv == 4) {
679         if (tov == 2 || tov == 3 || tov == 4) {
680             memcpy(toaddr, fromaddr, sizeof(struct vlheader_2));
681             tvp2 = (struct vlheader_2 *)toaddr;
682             tvp2->vital_header.vldbversion = htonl(tov);
683             w = write(fd, tvp2, sizeof(struct vlheader_2));
684             if (w != sizeof(struct vlheader_2)) {
685                 printf("Write of header failed %d; error %u\n", w, errno);
686                 exit(1);
687             }
688
689         } else if (tov == 1) {
690             tvp2 = (struct vlheader_2 *)fromaddr;
691             tvp1 = (struct vlheader_1 *)toaddr;
692             memset(tvp1, 0, sizeof(struct vlheader_1));
693             tvp1->vital_header.vldbversion = htonl(1);
694             tvp1->vital_header.headersize = htonl(sizeof(struct vlheader_1));
695             diff =
696                 ntohl(tvp1->vital_header.headersize) -
697                 ntohl(tvp2->vital_header.headersize);
698             if (ntohl(tvp2->vital_header.freePtr))
699                 tvp1->vital_header.freePtr =
700                     htonl(ntohl(tvp2->vital_header.freePtr) + diff);
701             if (ntohl(tvp2->vital_header.eofPtr))
702                 tvp1->vital_header.eofPtr =
703                     htonl(ntohl(tvp2->vital_header.eofPtr) + diff);
704             tvp1->vital_header.allocs = tvp2->vital_header.allocs;
705             tvp1->vital_header.frees = tvp2->vital_header.frees;
706             tvp1->vital_header.MaxVolumeId = tvp2->vital_header.MaxVolumeId;
707             for (i = 0; i < 3; i++)
708                 tvp1->vital_header.totalEntries[i] =
709                     tvp2->vital_header.totalEntries[i];
710
711             for (i = 0; i < 31; i++)
712                 tvp1->IpMappedAddr[i] = tvp2->IpMappedAddr[i];
713
714             for (i = 0; i < 8191; i++) {
715                 if (ntohl(tvp2->VolnameHash[i]))
716                     tvp1->VolnameHash[i] =
717                         htonl(ntohl(tvp2->VolnameHash[i]) + diff);
718             }
719
720             for (i = 0; i < 3; i++) {
721                 for (j = 0; j < 8191; j++) {
722                     if (ntohl(tvp2->VolidHash[i][j]))
723                         tvp1->VolidHash[i][j] =
724                             htonl(ntohl(tvp2->VolidHash[i][j]) + diff);
725                 }
726             }
727
728             w = write(fd, tvp1, sizeof(struct vlheader_1));
729             if (w != sizeof(struct vlheader_2)) {
730                 printf("Write of header failed %d; error %u\n", w, errno);
731                 exit(1);
732             }
733
734             /* for garbage-collecting... */
735             for (i = 0; i < 31; i++)
736                 tvp1->IpMappedAddr[i] = 0;
737         } else
738             return EINVAL;
739     } else
740         return EINVAL;
741     return 0;
742 }
743
744
745 /* Convert an address pointer to a vlentry from version 4 to version 3.
746  * This involves checking if the address is after any of the four
747  * MH block and if it is, subtract the size of the MH block. 
748  *
749  * In going from version 4 to 3, the mh blocks go away and all entries
750  * move up in their place. The adresses then need to be updated.
751  *
752  * Before this can be called, the routine read_mhentries must be called.
753  */
754 static afs_int32
755 Conv4to3(addr)
756      afs_int32 addr;
757 {
758     afs_int32 raddr;
759     int i;
760
761     if (!base[0] || !addr)
762         return (addr);
763
764     raddr = addr;
765     for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
766         if (base[i] && base[0]->ex_contaddrs[i]
767             && (addr > base[0]->ex_contaddrs[i]))
768             raddr -= VL_ADDREXTBLK_SIZE;
769     }
770
771     return (raddr);
772 }
773
774 /* this only works because the vlheader struct is essentially the same 
775  * from version 1 to version 2 -- that is, the first bunch of fields
776  * aren't any more or any larger, so they match up pretty well.
777 */
778
779 static int
780 convert_vlentry(new, fromvers, tovers, oldheader, newheader, vlentryp)
781      int new, fromvers, tovers;
782      struct vlheader_1 *oldheader, *newheader;  /* close enough */
783      struct vlentry_1 *vlentryp;        /* 1 and 2 are identical */
784 {
785     int diff, i, s, w;
786     struct vlentry_3 *vl3p = (struct vlentry_3 *)vlentryp;
787
788     /* For mh information blocks,
789      * If going to version 4 or greater, keep the mh info block.
790      * Otherwise, don't keep it (version 3 and earlier don't have them).
791      */
792     if (vl3p->flags == VLCONTBLOCK) {
793         if (tovers >= 4) {
794             w = write(new, vlentryp, VL_ADDREXTBLK_SIZE);
795             if (w != VL_ADDREXTBLK_SIZE) {
796                 printf("Write of mh info block failed %d; error %u\n", w,
797                        errno);
798                 exit(1);
799             }
800         }
801         return 0;
802     }
803
804     if (fromvers == 2 && tovers == 3) {
805         struct vlentry_3 vl;
806
807         vl.volumeId[0] = vlentryp->volumeId[0];
808         vl.volumeId[1] = vlentryp->volumeId[1];
809         vl.volumeId[2] = vlentryp->volumeId[2];
810         vl.flags = vlentryp->flags;
811         vl.LockAfsId = vlentryp->LockAfsId;
812         vl.LockTimestamp = vlentryp->LockTimestamp;
813         vl.cloneId = vlentryp->cloneId;
814         vl.nextIdHash[0] = vlentryp->nextIdHash[0];
815         vl.nextIdHash[1] = vlentryp->nextIdHash[1];
816         vl.nextIdHash[2] = vlentryp->nextIdHash[2];
817         vl.nextNameHash = vlentryp->nextNameHash;
818         memcpy(vl.name, vlentryp->name, 65);
819         for (i = 0; i < 8; i++) {
820             vl.serverNumber[i] = vlentryp->serverNumber[i];
821             vl.serverPartition[i] = vlentryp->serverPartition[i];
822             vl.serverFlags[i] = vlentryp->serverFlags[i];
823         }
824         for (; i < 13; i++)
825             vl.serverNumber[i] = vl.serverPartition[i] = vl.serverFlags[i] =
826                 BADSERVERID;
827         w = write(new, &vl, sizeof(struct vlentry_3));
828         if (w != sizeof(struct vlentry_3)) {
829             printf("Write of entry failed %d; error %u\n", w, errno);
830             exit(1);
831         }
832
833         return 0;
834     } else if (fromvers == 3 && tovers == 2) {
835         struct vlentry_2 vl;
836         struct vlentry_3 *xnvlentry = (struct vlentry_3 *)vlentryp;
837
838         memset((char *)&vl, 0, sizeof(struct vlentry_2));
839         vl.volumeId[0] = xnvlentry->volumeId[0];
840         vl.volumeId[1] = xnvlentry->volumeId[1];
841         vl.volumeId[2] = xnvlentry->volumeId[2];
842         vl.flags = xnvlentry->flags;
843         vl.LockAfsId = xnvlentry->LockAfsId;
844         vl.LockTimestamp = xnvlentry->LockTimestamp;
845         vl.cloneId = xnvlentry->cloneId;
846         for (i = 0; i < 3; i++) {
847             if (ntohl(xnvlentry->nextIdHash[i]))
848                 vl.nextIdHash[i] = xnvlentry->nextIdHash[i];
849         }
850         if (ntohl(xnvlentry->nextNameHash))
851             vl.nextNameHash = xnvlentry->nextNameHash;
852         memcpy(vl.name, xnvlentry->name, 65);
853         for (i = 0; i < 8; i++) {
854             vl.serverNumber[i] = xnvlentry->serverNumber[i];
855             vl.serverPartition[i] = xnvlentry->serverPartition[i];
856             vl.serverFlags[i] = xnvlentry->serverFlags[i];
857         }
858         w = write(new, &vl, sizeof(struct vlentry_2));
859         if (w != sizeof(struct vlentry_2)) {
860             printf("Write of entry failed %d; error %u\n", w, errno);
861             exit(1);
862         }
863         return 0;
864     } else if (fromvers == 3 && tovers == 1) {
865         struct vlentry_1 vl;
866         struct vlentry_3 *xnvlentry = (struct vlentry_3 *)vlentryp;
867
868         diff =
869             (tovers ==
870              1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2))
871             - (fromvers ==
872                1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2));
873         memset((char *)&vl, 0, sizeof(struct vlentry_1));
874         vl.volumeId[0] = xnvlentry->volumeId[0];
875         vl.volumeId[1] = xnvlentry->volumeId[1];
876         vl.volumeId[2] = xnvlentry->volumeId[2];
877         vl.flags = xnvlentry->flags;
878         vl.LockAfsId = xnvlentry->LockAfsId;
879         vl.LockTimestamp = xnvlentry->LockTimestamp;
880         vl.cloneId = xnvlentry->cloneId;
881         for (i = 0; i < 3; i++) {
882             if (ntohl(xnvlentry->nextIdHash[i]))
883                 vl.nextIdHash[i] =
884                     htonl(ntohl(xnvlentry->nextIdHash[i]) + diff);
885         }
886         if (ntohl(xnvlentry->nextNameHash))
887             vl.nextNameHash = htonl(ntohl(xnvlentry->nextNameHash) + diff);
888
889         memcpy(vl.name, xnvlentry->name, 65);
890         for (i = 0; i < 8; i++) {
891             vl.serverNumber[i] = xnvlentry->serverNumber[i];
892             vl.serverPartition[i] = xnvlentry->serverPartition[i];
893             vl.serverFlags[i] = xnvlentry->serverFlags[i];
894         }
895         for (i = 0; i < 8; i++) {
896             s = xnvlentry->serverNumber[i];
897             if (s != 255) {
898                 if (s > MaxServers[tovers - 1]) {
899                     fprintf(stderr,
900                             "%s: Too Many Servers (%d) for this version!\n",
901                             pn, s + 1);
902                     exit(-1);
903                 } else
904                     newheader->IpMappedAddr[s] = oldheader->IpMappedAddr[s];
905             }
906         }
907         w = write(new, &vl, sizeof(struct vlentry_1));
908         if (w != sizeof(struct vlentry_1)) {
909             printf("Write of entry failed %d; error %u\n", w, errno);
910             exit(1);
911         }
912         return 0;
913     } else if (fromvers == 4 && tovers == 3) {
914         struct vlentry_3 vl;
915         /* We are converting from version 4 to 3. In this conversion, mh info
916          * blocks go away and all vlentries after them move up in the vldb file.
917          * When this happens, the linked list pointers need to be updated.
918          */
919         memcpy(&vl, vlentryp, sizeof(vl));
920         for (i = 0; i < 3; i++) {
921             vl.nextIdHash[i] = Conv4to3(vl.nextIdHash[i]);
922         }
923         vl.nextNameHash = Conv4to3(vl.nextNameHash);
924
925         w = write(new, &vl, sizeof(vl));
926         if (w != sizeof(vl)) {
927             printf("Write of entry failed %d; error %u\n", w, errno);
928             exit(1);
929         }
930         return 0;
931     }
932
933     if (tovers == 1) {
934         w = write(new, vlentryp, sizeof(struct vlentry_1));
935         if (w != sizeof(struct vlentry_1)) {
936             printf("Write of entry failed %d; error %u\n", w, errno);
937             exit(1);
938         }
939     } else if (tovers == 2) {
940         w = write(new, vlentryp, sizeof(struct vlentry_2));
941         if (w != sizeof(struct vlentry_2)) {
942             printf("Write of entry failed %d; error %u\n", w, errno);
943             exit(1);
944         }
945     } else if (tovers == 3 || tovers == 4) {
946         w = write(new, vlentryp, sizeof(struct vlentry_3));
947         if (w != sizeof(struct vlentry_3)) {
948             printf("Write of entry failed %d; error %u\n", w, errno);
949             exit(1);
950         }
951     } else {
952         perror(pn);
953         fprintf(stderr,
954                 "Skipping vlentry write - db corrupted - bad toversion %d\n",
955                 tovers);
956     }
957
958     return;
959 }
960
961 static int
962 rewrite_header(new, tovers, newheader)
963      int new, tovers;
964      char *newheader;
965 {
966     int pos, w, towrite;
967
968     pos = lseek(new, 64, L_SET);        /* leave room for ubik */
969     if (pos == -1) {
970         perror(pn);
971         fprintf(stderr, "%s: no garbage colection\n", pn);
972         return;
973     } else if (pos != 64) {
974         fprintf(stderr, "%s: Can't rewind: no garbage collection\n", pn);
975         return;
976     }
977
978     towrite =
979         ((tovers ==
980           1) ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2));
981     w = write(new, newheader, towrite);
982     if (w != towrite) {
983         printf("Write of entry failed %d; error %u\n", w, errno);
984         exit(1);
985     }
986
987     return;
988 }
989
990
991 #include "AFS_component_version_number.c"
992
993 main(argc, argv)
994      int argc;
995      char **argv;
996 {
997     register struct cmd_syndesc *ts;
998     afs_int32 code;
999
1000     ts = cmd_CreateSyntax("initcmd", handleit, 0, "optional");
1001     cmd_AddParm(ts, "-to", CMD_SINGLE, CMD_OPTIONAL, "goal version");
1002     cmd_AddParm(ts, "-from", CMD_SINGLE, CMD_OPTIONAL, "current version");
1003     cmd_AddParm(ts, "-path", CMD_SINGLE, CMD_OPTIONAL, "pathname");
1004     cmd_AddParm(ts, "-showversion", CMD_FLAG, CMD_OPTIONAL,
1005                 "Just display version of current vldb");
1006     cmd_AddParm(ts, "-dumpvldb", CMD_FLAG, CMD_OPTIONAL,
1007                 "display all vldb entries");
1008
1009 #ifdef DEBUG
1010     cmd_AddParm(ts, "-noGC", CMD_FLAG, CMD_OPTIONAL,
1011                 "Don't do garbage collection");
1012 #endif /* DEBUG */
1013
1014     dbPath = AFSDIR_SERVER_VLDB_FILEPATH;
1015
1016     code = cmd_Dispatch(argc, argv);
1017     exit(code);
1018 }