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 <sys/file.h> | |
15 | #include <afs/venus.h> | |
16 | #include <afs/cmd.h> | |
17 | #include <afs/afs_consts.h> | |
18 | ||
19 | #include "cnvldb.h" /* CHANGEME! */ | |
20 | ||
21 | static char pn[] = "cnvldb"; | |
22 | static char tempname[] = "XXnewvldb"; | |
23 | static char space[AFS_PIOCTL_MAXSIZE]; | |
24 | static int MaxServers[2] = { 30, 254 }; /* max server # permitted in this version */ | |
25 | ||
26 | #ifdef notdef /* postpone this... */ | |
27 | static int | |
28 | saferead(fd, addr, osize) | |
29 | int fd, osize; | |
30 | char *addr; | |
31 | { | |
32 | int rc, size; | |
33 | char *ptr; | |
34 | ||
35 | if (size == EOF) | |
36 | return (EOF); | |
37 | ||
38 | ptr = addr; | |
39 | rc = osize = size; | |
40 | ||
41 | while (rc != EOF) { | |
42 | rc = read(fd, ptr, size)) { | |
43 | if (rc == size) | |
44 | return osize; | |
45 | else { | |
46 | if (errno != EINTR) { | |
47 | perror(pn); | |
48 | exit(-1); | |
49 | } | |
50 | } | |
51 | } | |
52 | } | |
53 | ||
54 | ||
55 | static int | |
56 | saferead(fd, addr, osize) | |
57 | int fd, osize; | |
58 | char *addr; | |
59 | { | |
60 | int rc; | |
61 | ||
62 | rc = read(fd, addr, osize); | |
63 | if (rc != osize && rc != EOF) { | |
64 | perror(pn); | |
65 | exit(-1); | |
66 | } | |
67 | return (rc); | |
68 | } | |
69 | #else | |
70 | #define saferead(fd,addr,siz) read((fd),(addr),(siz)) | |
71 | #endif | |
72 | ||
73 | static char tspace[1024]; /* chdir can't handle anything bigger, anyway */ | |
74 | /* return a static pointer to a buffer */ | |
75 | static char * | |
76 | Parent(apath) | |
77 | char *apath; | |
78 | { | |
79 | char *tp; | |
80 | strcpy(tspace, apath); | |
81 | tp = strrchr(tspace, '/'); | |
82 | if (tp) { | |
83 | *tp = 0; | |
84 | } else | |
85 | strcpy(tspace, "."); | |
86 | return tspace; | |
87 | } | |
88 | ||
89 | #ifdef notdef | |
90 | ||
91 | /* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */ | |
92 | static int | |
93 | InAFS(apath) | |
94 | char *apath; | |
95 | { | |
96 | struct ViceIoctl blob; | |
97 | afs_int32 code; | |
98 | ||
99 | blob.in_size = 0; | |
100 | blob.out_size = AFS_PIOCTL_MAXSIZE; | |
101 | blob.out = space; | |
102 | ||
103 | code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1); | |
104 | if (code) { | |
105 | if ((errno == EINVAL) || (errno == ENOENT)) | |
106 | return 0; | |
107 | } | |
108 | return 1; | |
109 | } | |
110 | ||
111 | QuickPrintStatus(status, name) | |
112 | struct VolumeStatus *status; | |
113 | char *name; | |
114 | { | |
115 | double QuotaUsed = 0.0; | |
116 | double PartUsed = 0.0; | |
117 | int WARN = 0; | |
118 | ||
119 | if (status->MaxQuota != 0) { | |
120 | QuotaUsed = | |
121 | ((((double)status->BlocksInUse) / status->MaxQuota) * 100.0); | |
122 | } else { | |
123 | /* no limit */ | |
124 | } | |
125 | PartUsed = | |
126 | (100.0 - | |
127 | ((((double)status->PartBlocksAvail) / status->PartMaxBlocks) * | |
128 | 100.0)); | |
129 | } | |
130 | ||
131 | ||
132 | static int | |
133 | ListQuotaCmd(struct cmd_syndesc *as, void *arock) | |
134 | { | |
135 | afs_int32 code; | |
136 | struct ViceIoctl blob; | |
137 | struct cmd_item *ti; | |
138 | struct VolumeStatus *status; | |
139 | char *name; | |
140 | ||
141 | for (ti = as->parms[0].items; ti; ti = ti->next) { | |
142 | /* once per file */ | |
143 | blob.out_size = AFS_PIOCTL_MAXSIZE; | |
144 | blob.in_size = 0; | |
145 | blob.out = space; | |
146 | code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1); | |
147 | if (code) { | |
148 | Die(code, ti->data); | |
149 | continue; | |
150 | } | |
151 | status = (struct VolumeStatus *)space; | |
152 | name = (char *)status + sizeof(*status); | |
153 | QuickPrintStatus(status, name); | |
154 | } | |
155 | return 0; | |
156 | } | |
157 | #endif /* notdef */ | |
158 | ||
159 | int gc = 1, fromvers = 1, tovers = 2; | |
160 | char *pathname = NULL, *defaultpath = "/usr/afs/db/vl.DB0"; | |
161 | ||
162 | usage() | |
163 | { | |
164 | fprintf(stderr, "usage: %s ", pn); | |
165 | fprintf(stderr, "[-name <pathname>] [-help]\n"); | |
166 | } | |
167 | ||
168 | getargs(argc, argv) | |
169 | int argc; | |
170 | char **argv; | |
171 | { | |
172 | int pos, i; | |
173 | pos = 0; | |
174 | ||
175 | for (i = 1; i < argc; i++) { | |
176 | if (!argv[i]) | |
177 | break; | |
178 | else if (*(argv[i]) != '-') { /* positional params */ | |
179 | if (!pathname) | |
180 | pathname = argv[i]; | |
181 | else { | |
182 | fprintf(stderr, "%s: Too many parameters!\n"); | |
183 | usage(); | |
184 | exit(-1); | |
185 | } | |
186 | } else /* keyword params */ | |
187 | switch (argv[i][1]) { | |
188 | ||
189 | case 't': /* -to */ | |
190 | fprintf(stderr, "%s: can't specify version with this tool!\n", | |
191 | pn); | |
192 | exit(-1); | |
193 | break; | |
194 | ||
195 | case 'f': /* -from */ | |
196 | fprintf(stderr, "%s: can't specify version with this tool!\n", | |
197 | pn); | |
198 | break; | |
199 | ||
200 | case 'n': /* -name */ | |
201 | if (pathname) { | |
202 | fprintf(stderr, | |
203 | "%s: -name specified (or implied) twice!\n", pn); | |
204 | exit(-1); | |
205 | } | |
206 | pathname = argv[++i]; | |
207 | break; | |
208 | ||
209 | case 'h': /* -help */ | |
210 | usage(); | |
211 | exit(0); | |
212 | break; | |
213 | ||
214 | case 'g': /* -gc == No GC */ | |
215 | gc = 0; | |
216 | break; | |
217 | ||
218 | default: | |
219 | usage(); | |
220 | exit(EINVAL); | |
221 | } | |
222 | } | |
223 | ||
224 | if (!pathname) | |
225 | pathname = defaultpath; | |
226 | } | |
227 | ||
228 | #include "AFS_component_version_number.c" | |
229 | ||
230 | main(argc, argv) | |
231 | int argc; | |
232 | char **argv; | |
233 | { | |
234 | afs_int32 code; | |
235 | int old, new, rc; | |
236 | short uvers; | |
237 | char ubik[80]; /* space for some ubik header */ | |
238 | ||
239 | union { | |
240 | struct vlheader_1 header1; | |
241 | struct vlheader_2 header2; | |
242 | } oldheader, newheader; /* large enough for either */ | |
243 | ||
244 | union { | |
245 | struct vlentry_1 entry1; | |
246 | struct vlentry_2 entry2; | |
247 | } vlentry; | |
248 | ||
249 | ||
250 | getargs(argc, argv); | |
251 | ||
252 | /* should stat() the old vldb, get its size, and see if there's */ | |
253 | /* room for another. It might be in AFS, so check the quota, too */ | |
254 | if (!(old = open(pathname, O_RDONLY))) { | |
255 | perror(pn); | |
256 | exit(-1); | |
257 | } | |
258 | ||
259 | if (chdir(Parent(pathname))) { | |
260 | perror(pn); | |
261 | exit(-1); | |
262 | } | |
263 | ||
264 | if (!(new = open(tempname, O_WRONLY | O_CREAT | O_TRUNC, 0600))) { | |
265 | perror(pn); | |
266 | exit(-1); | |
267 | } | |
268 | ||
269 | if (fromvers == 0) { /* not set */ | |
270 | lseek(old, 64, L_SET); | |
271 | read(old, &fromvers, sizeof(int)); | |
272 | fromvers = ntohl(fromvers); | |
273 | lseek(old, 0, L_SET); /* go back to beginning */ | |
274 | } | |
275 | ||
276 | /* skip the UBIK data */ | |
277 | read(old, ubik, 64); | |
278 | #ifdef notdef | |
279 | uvers = ntohs(uvers); | |
280 | uvers += 10; /* hey, if you screw with the VLDB, you lose */ | |
281 | uvers = htons(uvers); | |
282 | #endif | |
283 | write(new, ubik, 64); | |
284 | ||
285 | readheader(old, fromvers, &oldheader); | |
286 | convert_header(new, fromvers, tovers, &oldheader, &newheader); | |
287 | while ((rc = read(old, &vlentry, sizeof(struct vlentry_1))) && rc != EOF) { | |
288 | convert_vlentry(new, fromvers, tovers, &oldheader, &newheader, | |
289 | &vlentry); | |
290 | } | |
291 | ||
292 | ||
293 | if (gc) | |
294 | rewrite_header(new, tovers, &newheader); | |
295 | ||
296 | close(old); | |
297 | if (fsync(new)) { | |
298 | perror(pn); | |
299 | exit(-1); | |
300 | } | |
301 | ||
302 | close(new); | |
303 | rename(tempname, pathname); | |
304 | exit(0); | |
305 | } | |
306 | ||
307 | readheader(fd, version, addr) | |
308 | int fd; | |
309 | int version; | |
310 | char *addr; | |
311 | { | |
312 | if (version == 1) { | |
313 | read(fd, addr, sizeof(struct vlheader_2)); /* it's not a bug, it's SAS */ | |
314 | } else if (version == 2) { | |
315 | read(fd, addr, sizeof(struct vlheader_2)); | |
316 | } else | |
317 | return EINVAL; | |
318 | ||
319 | return 0; | |
320 | } | |
321 | ||
322 | /* SAS special */ | |
323 | convert_header(fd, fromv, tov, fromaddr, toaddr) | |
324 | int fd, fromv, tov; | |
325 | char *fromaddr, *toaddr; | |
326 | { | |
327 | struct vlheader_2 *tvp1; | |
328 | struct vlheader_2 *tvp2; | |
329 | int i, j, diff; | |
330 | ||
331 | memcpy(toaddr, fromaddr, sizeof(struct vlheader_2)); | |
332 | tvp2 = (struct vlheader_2 *)toaddr; | |
333 | tvp2->vital_header.vldbversion = htonl(2); | |
334 | ||
335 | write(fd, tvp2, sizeof(struct vlheader_2)); | |
336 | ||
337 | /* for garbage-collecting... */ | |
338 | if (gc) | |
339 | for (i = 0; i < 254; i++) | |
340 | tvp2->IpMappedAddr[i] = 0; | |
341 | ||
342 | return 0; | |
343 | } | |
344 | ||
345 | static int | |
346 | convert_vlentry(new, fromvers, tovers, oldheader, newheader, vlentry) | |
347 | int new, fromvers, tovers; | |
348 | struct vlheader_1 *oldheader, *newheader; /* close enough */ | |
349 | struct vlentry_1 *vlentry; /* 1 and 2 are identical */ | |
350 | { | |
351 | int diff, i, s; | |
352 | ||
353 | #ifndef DEBUG | |
354 | if (fromvers != tovers) { /* only supports 1 and 2 currently */ | |
355 | #endif | |
356 | ||
357 | diff = | |
358 | (tovers == | |
359 | 1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2)) | |
360 | - (fromvers == | |
361 | 1 ? sizeof(struct vlheader_1) : sizeof(struct vlheader_2)); | |
362 | ||
363 | for (i = 0; i < 3; i++) | |
364 | vlentry->nextIdHash[i] = | |
365 | htonl(ntohl(vlentry->nextIdHash[i]) + diff); | |
366 | ||
367 | vlentry->nextNameHash = htonl(ntohl(vlentry->nextNameHash) + diff); | |
368 | ||
369 | #ifndef DEBUG | |
370 | } else { | |
371 | ; /* no change, we're just in it for the GC */ | |
372 | } | |
373 | #endif | |
374 | ||
375 | for (i = 0; i < 8; i++) { | |
376 | s = vlentry->serverNumber[i]; | |
377 | if (s != 255) { | |
378 | if (s > 254) { | |
379 | fprintf(stderr, | |
380 | "%s: Too Many Servers (%d) for this version!\n", pn, | |
381 | s + 1); | |
382 | exit(-1); | |
383 | } else { | |
384 | newheader->IpMappedAddr[s] = oldheader->IpMappedAddr[s]; | |
385 | } | |
386 | } | |
387 | } | |
388 | write(new, vlentry, sizeof(struct vlentry_2)); | |
389 | ||
390 | return; | |
391 | } | |
392 | ||
393 | static int | |
394 | rewrite_header(new, tovers, newheader) | |
395 | int new, tovers; | |
396 | char *newheader; | |
397 | { | |
398 | int pos; | |
399 | ||
400 | pos = lseek(new, 64, L_SET); /* leave room for ubik */ | |
401 | ||
402 | if (pos == -1) { | |
403 | perror(pn); | |
404 | fprintf(stderr, "%s: no garbage collection\n", pn); | |
405 | return; | |
406 | } else if (pos != 64) { | |
407 | fprintf(stderr, "%s: Can't rewind: no garbage collection\n", pn); | |
408 | return; | |
409 | } | |
410 | ||
411 | if (tovers = 1) { | |
412 | write(new, newheader, sizeof(struct vlheader_1)); | |
413 | } else { | |
414 | write(new, newheader, sizeof(struct vlheader_2)); | |
415 | } | |
416 | ||
417 | return; | |
418 | } |