backport to buster
[hcoop/debian/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 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <sys/file.h>
17
18 #include <afs/venus.h>
19 #include <afs/cmd.h>
20 #include <afs/afsutil.h>
21 #include <afs/fileutil.h>
22
23 #include "vlserver.h"
24 #include "cnvldb.h" /* CHANGEME! */
25
26 #define BADSERVERID 255 /* XXX */
27
28
29 static char pn[] = "cnvldb";
30 static char tempname[] = "XXnewvldb";
31 static int MaxServers[3] = { 30, 254, 254 }; /* max server # permitted in this version */
32
33 static afs_int32 Conv4to3(afs_uint32 addr);
34
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);
41
42 static char tspace[1024]; /* chdir can't handle anything bigger, anyway */
43
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);
46
47 static int convert_header(int ofd, int fd, int fromv, int tov, void *fromaddr,
48 void *toaddr);
49
50 /* return a static pointer to a buffer */
51 static char *
52 Parent(const char *apath)
53 {
54 char *tp;
55 strcpy(tspace, apath);
56 tp = strrchr(tspace, '/');
57 if (tp) {
58 *tp = 0;
59 } else
60 strcpy(tspace, ".");
61 return tspace;
62 }
63
64 int oldpos = 0;
65 int fromvers = 0, tovers = 0, showversion = 0;
66 afs_uint32 mhaddr;
67 afs_int32 dbsize;
68 const char *pathname = NULL;
69 const char *dbPath;
70
71 static int
72 handleit(struct cmd_syndesc *as, void *arock)
73 {
74 int w, old, new, rc, dump = 0, fromv = 0;
75 ssize_t count;
76
77 char ubik[80]; /* space for some ubik header */
78 union {
79 struct vlheader_1 header1;
80 struct vlheader_2 header2;
81 struct vlheader_3 header3;
82 } oldheader, newheader; /* large enough for either */
83
84 union {
85 struct vlentry_1 entry1;
86 struct vlentry_2 entry2;
87 struct vlentry_3 entry3;
88 char mhinfo_block[VL_ADDREXTBLK_SIZE];
89 } xvlentry;
90
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 */
96
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);
100 if (old < 0) {
101 perror(pn);
102 exit(-1);
103 }
104
105 /* Read the version */
106 if (lseek(old, 64, L_SET) == (off_t)-1) {
107 perror(pn);
108 exit(-1);
109 }
110 count = read(old, &fromv, sizeof(int));
111 if (count < 0) {
112 perror(pn);
113 exit(-1);
114 } else if (count != sizeof(int)) {
115 fprintf(stderr, "%s: Premature EOF reading database version.\n", pn);
116 exit(-1);
117 }
118 fromv = ntohl(fromv);
119 if ((fromv < 1) || (fromv > 4)) {
120 fprintf(stderr, "%s", pn);
121 fprintf(stderr, ": Unrecognized VLDB version %d.\n", fromv);
122 exit(-1);
123 }
124
125 /* Sequentially read the database converting the entries as we go */
126 if (lseek(old, 0, L_SET) == (off_t)-1) {
127 perror(pn);
128 exit(-1);
129 }
130 count = read(old, ubik, 64);
131 if (count < 0) {
132 perror(pn);
133 exit(-1);
134 } else if (count != 64) {
135 fprintf(stderr, "%s: Premature EOF reading database header.\n", pn);
136 exit(-1);
137 }
138 readheader(old, fromv, &oldheader);
139 if (fromv == 1) {
140 dbsize = ntohl(oldheader.header1.vital_header.eofPtr);
141 fromv = ntohl(oldheader.header1.vital_header.vldbversion);
142 mhaddr = 0;
143 } else if (fromv == 2) {
144 dbsize = ntohl(oldheader.header2.vital_header.eofPtr);
145 fromv = ntohl(oldheader.header2.vital_header.vldbversion);
146 mhaddr = 0;
147 } else {
148 int pos;
149
150 dbsize = ntohl(oldheader.header3.vital_header.eofPtr);
151 fromv = ntohl(oldheader.header3.vital_header.vldbversion);
152 mhaddr = ntohl(oldheader.header3.SIT);
153
154 /* Read the multihomed extent blocks in */
155 pos = oldpos;
156 read_mhentries(mhaddr, old);
157
158 /* Position back to this after header */
159 lseek(old, pos + 64, L_SET);
160 oldpos = pos;
161 }
162
163 if (showversion || dump) {
164 if (showversion)
165 fprintf(stdout, "%s has a version of %d\n", pathname, fromv);
166 if (dump) {
167 while (oldpos < dbsize) {
168 rc = readentry(old, fromv, &xvlentry);
169 if ((rc == 0) || (rc == EOF))
170 break;
171 printentry(fromv, &xvlentry);
172 }
173 }
174 exit(0);
175 }
176
177 if (!fromvers) { /* not set */
178 fromvers = fromv;
179 } else if (fromvers != fromv) {
180 fprintf(stdout,
181 "%s has a version of %d while the -fromversion specified was %d - aborting\n",
182 pathname, fromv, fromvers);
183 exit(0);
184 }
185
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");
191 exit(-1);
192 }
193
194 if (!tovers)
195 tovers = fromvers + 1;
196
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");
202 exit(-1);
203 }
204
205 if (mhaddr && (tovers < 3)) {
206 fprintf(stderr, "%s", pn);
207 fprintf(stderr, ": Cannot convert. VLDB contains multihome info.\n");
208 exit(-1);
209 }
210
211 /* OK! let's get down to business... */
212
213 if (chdir(Parent(pathname))) {
214 perror(pn);
215 exit(-1);
216 }
217
218 new = open(tempname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
219 if (new < 0) {
220 perror(pn);
221 exit(-1);
222 }
223
224 /* Write the UBIK data */
225 w = write(new, ubik, 64);
226 if (w != 64) {
227 printf("Write of ubik header failed %d; error %u\n", w, errno);
228 exit(1);
229 }
230
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.
237 */
238
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))
243 break;
244 convert_vlentry(new, fromvers, tovers,
245 (struct vlheader_1 *)&oldheader,
246 (struct vlheader_1 *)&newheader,
247 (struct vlentry_1 *)&xvlentry);
248 }
249
250 /* We have now finished sequentially reading and writing the database.
251 * Now randomly offset into database and update multihome entries.
252 */
253 convert_mhentries(old, new, (struct vlheader_2 *)&newheader,
254 fromvers, tovers);
255 rewrite_header(new, tovers, &newheader);
256
257 close(old);
258 if (fsync(new)) {
259 perror(pn);
260 exit(-1);
261 }
262 close(new);
263
264 rk_rename(tempname, pathname);
265 sleep(5);
266 exit(0);
267 }
268
269
270 static void
271 readheader(int fd, int version, void *addr)
272 {
273 int hdrsize, size = 0;
274
275 oldpos = 0;
276 if (version == 1)
277 hdrsize = sizeof(struct vlheader_1);
278 else
279 hdrsize = sizeof(struct vlheader_2);
280
281 size = read(fd, addr, hdrsize);
282 if (size > 0)
283 oldpos += size;
284
285 return;
286 }
287
288 static int
289 readentry(int fd, int version, void *addr)
290 {
291 int rc, rc1;
292 struct vlentry_3 *vl3p = (struct vlentry_3 *)addr;
293 int toread;
294 char *caddr = (char *)addr;
295
296 toread =
297 ((version ==
298 1) ? sizeof(struct vlentry_1) : sizeof(struct vlentry_2));
299 rc = read(fd, addr, toread);
300 if (rc != toread)
301 printf("Partial read of vlentry at pos %u: %d\n", oldpos, rc);
302 if (rc > 0)
303 oldpos += rc;
304
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;
309
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,
313 rc1);
314 if (rc1 > 0) {
315 oldpos += rc1;
316 rc += rc1;
317 }
318 }
319
320 return rc;
321 }
322
323 static void
324 printentry(int version, void *addr)
325 {
326 struct vlentry_2 *vl2p = (struct vlentry_2 *)addr;
327 struct vlentry_3 *vl3p = (struct vlentry_3 *)addr;
328 int i;
329
330 /* Don't print anything if the entry is a mh info block */
331 if (vl3p->flags == VLCONTBLOCK) {
332 return;
333 }
334
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) */
351
352 if (vl3p->flags == VLFREE)
353 return;
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],
357 vl3p->nextNameHash);
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]);
367 }
368 }
369 }
370 return;
371 }
372
373 int readmhentries = 0;
374 struct extentaddr *base[VL_MAX_ADDREXTBLKS];
375
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.
379 */
380 void
381 read_mhentries(afs_uint32 mh_addr, int oldfd)
382 {
383 afs_uint32 sit, a;
384 afs_int32 code;
385 int j;
386
387 if (readmhentries)
388 return;
389 readmhentries = 1;
390
391 /* Initialize base pointers */
392 for (j = 0; j < VL_MAX_ADDREXTBLKS; j++)
393 base[j] = 0;
394
395 if (!mh_addr)
396 return;
397
398 /* Check if the first extent block is beyond eof. If
399 * it is, it's not real.
400 */
401 if (mh_addr > dbsize - VL_ADDREXTBLK_SIZE)
402 return;
403
404 /* Now read the first mh extent block */
405 code = lseek(oldfd, mh_addr + 64, L_SET);
406 if (code < 0) {
407 perror("seek MH block");
408 exit(1);
409 }
410 base[0] = malloc(VL_ADDREXTBLK_SIZE);
411 if (!base[0]) {
412 perror("malloc1");
413 exit(1);
414 }
415 code = read(oldfd, (char *)base[0], VL_ADDREXTBLK_SIZE);
416 if (code != VL_ADDREXTBLK_SIZE) {
417 perror("read MH block");
418 free(base[0]);
419 base[0] = 0;
420 exit(1);
421 }
422
423 /* Verify that this block is the right one */
424 if (ntohl(base[0]->ex_hdrflags) != VLCONTBLOCK) { /* check if flag is correct */
425 free(base[0]);
426 base[0] = 0;
427 return;
428 }
429
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.
432 */
433 a = mh_addr;
434 for (j = 1; j < VL_MAX_ADDREXTBLKS; j++) {
435 if (!base[0]->ex_contaddrs[j])
436 continue;
437
438 sit = ntohl(base[0]->ex_contaddrs[j]);
439
440 /* Every time we allocate a new extent block, it is allocated after
441 * the previous ones. But it must be before the EOF.
442 */
443 if ((sit < (a + VL_ADDREXTBLK_SIZE))
444 || (sit > dbsize - VL_ADDREXTBLK_SIZE)) {
445 continue;
446 }
447
448 /* Read the extent block in */
449 sit += 64;
450 code = lseek(oldfd, sit, L_SET);
451 if (code < 0) {
452 perror("seek MH block");
453 exit(1);
454 }
455 base[j] = malloc(VL_ADDREXTBLK_SIZE);
456 if (!base[j]) {
457 perror("malloc1");
458 exit(1);
459 }
460 code = read(oldfd, (char *)base[j], VL_ADDREXTBLK_SIZE);
461 if (code != VL_ADDREXTBLK_SIZE) {
462 perror("read MH block");
463 exit(1);
464 }
465
466 /* Verify that this block knows its an extent block */
467 if (ntohl(base[j]->ex_hdrflags) != VLCONTBLOCK) {
468 free(base[j]);
469 base[j] = 0;
470 continue;
471 }
472
473 /* The extent block passed our tests */
474 a = ntohl(base[0]->ex_contaddrs[j]);
475 }
476 }
477
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.
482 *
483 * Before this can be called, the routine read_mhentries must be called.
484 */
485 void
486 convert_mhentries(int oldfd, int newfd, struct vlheader_2 *header,
487 int fromver, int tover)
488 {
489 afs_int32 code;
490 int i, j, modified = 0, w;
491 afs_uint32 raddr, addr;
492 struct extentaddr *exp;
493 int basei, index;
494
495 /* Check if the header says the extent block exists. If
496 * it does, then read_mhentries should have read it in.
497 */
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]) {
502
503 if ((ntohl(header->SIT) != mhaddr) && (tover == 4)) {
504 printf
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);
508 }
509
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);
514 modified = 1;
515 }
516
517 /* The first block contains pointers to the other extent blocks.
518 * Check to see if the pointers are good.
519 */
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.
523 */
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;
527 modified = 1;
528 }
529 }
530
531 /* Now write out the base extent blocks if it changed */
532 if (modified) {
533 code = lseek(newfd, mhaddr + 64, L_SET);
534 if (code < 0) {
535 perror("seek MH Block");
536 exit(1);
537 }
538 w = write(newfd, (char *)base[0], VL_ADDREXTBLK_SIZE);
539 if (w != VL_ADDREXTBLK_SIZE) {
540 perror("write MH Block");
541 exit(1);
542 }
543 }
544 }
545
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.
549 */
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.
553 */
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;
559
560 if ((basei >= VL_MAX_ADDREXTBLKS) || !base[basei]) {
561 fprintf(stderr,
562 "Warning: mh entry %d has no IP address; ignored!!\n",
563 i);
564 header->IpMappedAddr[i] = 0;
565 continue;
566 }
567 exp = &base[basei][index];
568
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]);
573 break;
574 }
575 }
576 if (j >= VL_MAXIPADDRS_PERMH) {
577 fprintf(stderr,
578 "Warning: mh entry %d has no ip address; ignored!!\n",
579 i);
580 raddr = 0;
581 } else {
582 printf
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));
586 }
587 header->IpMappedAddr[i] = htonl(raddr);
588 }
589 }
590 header->SIT = mhaddr = 0; /* mhinfo block has been removed */
591
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.
595 * The VolnameHash
596 */
597 for (i = 0; i < 8191; i++) {
598 header->VolnameHash[i] = Conv4to3(header->VolnameHash[i]);
599 }
600 /* The VolidHash */
601 for (i = 0; i < 3; i++) {
602 for (j = 0; j < 8191; j++) {
603 header->VolidHash[i][j] = Conv4to3(header->VolidHash[i][j]);
604 }
605 }
606
607 /* Update eofptr to take into account the removal of the mhinfo blocks */
608 header->vital_header.eofPtr = htonl(Conv4to3(dbsize));
609 }
610 }
611
612
613 int
614 convert_header(int ofd, int fd, int fromv, int tov, void *fromaddr,
615 void *toaddr)
616 {
617 struct vlheader_1 *tvp1;
618 struct vlheader_2 *tvp2;
619 int i, j, diff, w;
620
621 if (fromv == 1) {
622 if (tov == 1) {
623 memcpy(toaddr, fromaddr, sizeof(struct vlheader_1));
624 tvp1 = (struct vlheader_1 *)toaddr;
625
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);
629 exit(1);
630 }
631
632 /* for garbage-collecting... */
633 for (i = 0; i < 31; i++)
634 tvp1->IpMappedAddr[i] = 0;
635
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));
642 diff =
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];
657
658 for (i = 0; i < 31; i++)
659 tvp2->IpMappedAddr[i] = tvp1->IpMappedAddr[i];
660
661 for (i = 0; i < 8191; i++) {
662 if (ntohl(tvp1->VolnameHash[i]))
663 tvp2->VolnameHash[i] =
664 htonl(ntohl(tvp1->VolnameHash[i]) + diff);
665 }
666
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);
672 }
673 }
674
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);
678 exit(1);
679 }
680
681 /* for garbage-collecting... */
682 for (i = 0; i < 31; i++)
683 tvp2->IpMappedAddr[i] = 0;
684 } else
685 return EINVAL;
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);
694 exit(1);
695 }
696
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));
703 diff =
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];
718
719 for (i = 0; i < 31; i++)
720 tvp1->IpMappedAddr[i] = tvp2->IpMappedAddr[i];
721
722 for (i = 0; i < 8191; i++) {
723 if (ntohl(tvp2->VolnameHash[i]))
724 tvp1->VolnameHash[i] =
725 htonl(ntohl(tvp2->VolnameHash[i]) + diff);
726 }
727
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);
733 }
734 }
735
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);
739 exit(1);
740 }
741
742 /* for garbage-collecting... */
743 for (i = 0; i < 31; i++)
744 tvp1->IpMappedAddr[i] = 0;
745 } else
746 return EINVAL;
747 } else
748 return EINVAL;
749 return 0;
750 }
751
752
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.
756 *
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.
759 *
760 * Before this can be called, the routine read_mhentries must be called.
761 */
762 static afs_int32
763 Conv4to3(afs_uint32 addr)
764 {
765 afs_uint32 raddr;
766 int i;
767
768 if (!base[0] || !addr)
769 return (addr);
770
771 raddr = 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;
776 }
777
778 return (raddr);
779 }
780
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.
784 */
785
786 static void
787 convert_vlentry(int new, int fromvers, int tovers,
788 struct vlheader_1 *oldheader, struct vlheader_1 *newheader,
789 struct vlentry_1 *vlentryp)
790 {
791 int diff, i, s, w;
792 struct vlentry_3 *vl3p = (struct vlentry_3 *)vlentryp;
793
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).
797 */
798 if (vl3p->flags == VLCONTBLOCK) {
799 if (tovers >= 4) {
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,
803 errno);
804 exit(1);
805 }
806 }
807 return;
808 }
809
810 if (fromvers == 2 && tovers == 3) {
811 struct vlentry_3 vl;
812
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];
829 }
830 for (; i < 13; i++)
831 vl.serverNumber[i] = vl.serverPartition[i] = vl.serverFlags[i] =
832 BADSERVERID;
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);
836 exit(1);
837 }
838
839 return;
840 } else if (fromvers == 3 && tovers == 2) {
841 struct vlentry_2 vl;
842 struct vlentry_3 *xnvlentry = (struct vlentry_3 *)vlentryp;
843
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];
855 }
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];
863 }
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);
867 exit(1);
868 }
869 return;
870 } else if (fromvers == 3 && tovers == 1) {
871 struct vlentry_1 vl;
872 struct vlentry_3 *xnvlentry = (struct vlentry_3 *)vlentryp;
873
874 diff =
875 (tovers ==
876 1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2))
877 - (fromvers ==
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]))
889 vl.nextIdHash[i] =
890 htonl(ntohl(xnvlentry->nextIdHash[i]) + diff);
891 }
892 if (ntohl(xnvlentry->nextNameHash))
893 vl.nextNameHash = htonl(ntohl(xnvlentry->nextNameHash) + diff);
894
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];
900 }
901 for (i = 0; i < 8; i++) {
902 s = xnvlentry->serverNumber[i];
903 if (s != 255) {
904 if (s > MaxServers[tovers - 1]) {
905 fprintf(stderr,
906 "%s: Too Many Servers (%d) for this version!\n",
907 pn, s + 1);
908 exit(-1);
909 } else
910 newheader->IpMappedAddr[s] = oldheader->IpMappedAddr[s];
911 }
912 }
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);
916 exit(1);
917 }
918 return;
919 } else if (fromvers == 4 && tovers == 3) {
920 struct vlentry_3 vl;
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.
924 */
925 memcpy(&vl, vlentryp, sizeof(vl));
926 for (i = 0; i < 3; i++) {
927 vl.nextIdHash[i] = Conv4to3(vl.nextIdHash[i]);
928 }
929 vl.nextNameHash = Conv4to3(vl.nextNameHash);
930
931 w = write(new, &vl, sizeof(vl));
932 if (w != sizeof(vl)) {
933 printf("Write of entry failed %d; error %u\n", w, errno);
934 exit(1);
935 }
936 return;
937 }
938
939 if (tovers == 1) {
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);
943 exit(1);
944 }
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);
949 exit(1);
950 }
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);
955 exit(1);
956 }
957 } else {
958 perror(pn);
959 fprintf(stderr,
960 "Skipping vlentry write - db corrupted - bad toversion %d\n",
961 tovers);
962 }
963
964 return;
965 }
966
967 static void
968 rewrite_header(int new, int tovers, void *newheader)
969 {
970 int pos, w, towrite;
971
972 pos = lseek(new, 64, L_SET); /* leave room for ubik */
973 if (pos == -1) {
974 perror(pn);
975 fprintf(stderr, "%s: no garbage colection\n", pn);
976 return;
977 } else if (pos != 64) {
978 fprintf(stderr, "%s: Can't rewind: no garbage collection\n", pn);
979 return;
980 }
981
982 towrite =
983 ((tovers ==
984 1) ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2));
985 w = write(new, newheader, towrite);
986 if (w != towrite) {
987 printf("Write of entry failed %d; error %u\n", w, errno);
988 exit(1);
989 }
990
991 return;
992 }
993
994
995 #include "AFS_component_version_number.c"
996
997 int
998 main(int argc, char **argv)
999 {
1000 struct cmd_syndesc *ts;
1001 afs_int32 code;
1002
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");
1011
1012 #ifdef DEBUG
1013 cmd_AddParm(ts, "-noGC", CMD_FLAG, CMD_OPTIONAL,
1014 "Don't do garbage collection");
1015 #endif /* DEBUG */
1016
1017 dbPath = AFSDIR_SERVER_VLDB_FILEPATH;
1018
1019 code = cmd_Dispatch(argc, argv);
1020 exit(code);
1021 }