Commit | Line | Data |
---|---|---|
805e021f CE |
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 | } |