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 | /* | |
11 | * ALL RIGHTS RESERVED | |
12 | */ | |
13 | ||
14 | #include <afsconfig.h> | |
15 | #include <afs/param.h> | |
16 | #include <afs/stds.h> | |
17 | ||
18 | #include <roken.h> | |
19 | ||
20 | #include <afs/cmd.h> | |
21 | #include <lwp.h> | |
22 | #include <afs/bubasics.h> | |
23 | #include "bc.h" | |
24 | #include <afs/com_err.h> | |
25 | #include <afs/butc.h> | |
26 | #include <afs/budb.h> | |
27 | #include <afs/vlserver.h> | |
28 | ||
29 | #include "error_macros.h" | |
30 | #include "bucoord_internal.h" | |
31 | #include "bucoord_prototypes.h" | |
32 | ||
33 | extern struct bc_dumpTask bc_dumpTasks[BC_MAXSIMDUMPS]; | |
34 | extern char *whoami; | |
35 | ||
36 | #define MAXTAPESATONCE 10 | |
37 | ||
38 | #define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr | |
39 | ||
40 | /* local structure to keep track of volumes and the dumps from which | |
41 | * they should be restored | |
42 | */ | |
43 | struct dumpinfo { | |
44 | struct dumpinfo *next; | |
45 | struct volinfo *volinfolist; | |
46 | struct volinfo *lastinlist; | |
47 | afs_int32 DumpId; | |
48 | afs_int32 initialDumpId; | |
49 | afs_int32 parentDumpId; | |
50 | afs_int32 level; | |
51 | }; | |
52 | ||
53 | struct volinfo { | |
54 | struct volinfo *next; | |
55 | char *volname; | |
56 | afs_uint32 server; | |
57 | afs_int32 partition; | |
58 | }; | |
59 | ||
60 | /* local structure used to keep track of a tape, including a list of | |
61 | * volumes to restore from that tape (bc_tapeItem) | |
62 | */ | |
63 | struct bc_tapeList { | |
64 | struct bc_tapeList *next; /* next guy in list */ | |
65 | char *tapeName; /* name of the tape */ | |
66 | afs_int32 dumpID; /* dump located on this tape */ | |
67 | afs_int32 initialDumpID; /* initial dump located on this tape */ | |
68 | afs_int32 tapeNumber; /* which tape in the dump */ | |
69 | struct bc_tapeItem *restoreList; /* volumes to restore from this tape */ | |
70 | }; | |
71 | ||
72 | /* each tape has a list of volumes to restore; hangs off of a struct | |
73 | bc_tapeList. Kept sorted so that we can read the tape once to do | |
74 | everything we need to do. */ | |
75 | struct bc_tapeItem { | |
76 | struct bc_tapeItem *next; | |
77 | char *volumeName; /* volume to restore */ | |
78 | afs_int32 position; /* file slot on this tape */ | |
79 | afs_int32 oid; /* id of the volume */ | |
80 | afs_int32 dumplevel; /* level # of the containing dump (0 == top level) */ | |
81 | afs_int32 vollevel; /* level # of the containing volume (0 == full dump) */ | |
82 | afs_uint32 server; | |
83 | afs_int32 partition; | |
84 | int lastdump; /* The last incremental to restore */ | |
85 | }; | |
86 | ||
87 | /* strip .backup from the end of a name */ | |
88 | static int | |
89 | StripBackup(char *aname) | |
90 | { | |
91 | int j; | |
92 | ||
93 | if ((j = BackupName(aname))) { | |
94 | aname[j] = 0; | |
95 | return 0; | |
96 | } | |
97 | return -1; | |
98 | } | |
99 | ||
100 | int | |
101 | BackupName(char *aname) | |
102 | { | |
103 | int j; | |
104 | ||
105 | j = strlen(aname); | |
106 | if ((j > 7) && (strcmp(".backup", aname + j - 7) == 0)) | |
107 | return (j - 7); | |
108 | if ((j > 9) && (strcmp(".readonly", aname + j - 9) == 0)) | |
109 | return (j - 9); | |
110 | return 0; | |
111 | } | |
112 | ||
113 | int | |
114 | extractTapeSeq(char *tapename) | |
115 | { | |
116 | char *sptr; | |
117 | ||
118 | sptr = strrchr(tapename, '.'); | |
119 | if (!sptr) | |
120 | return (-1); | |
121 | sptr++; | |
122 | return (atol(sptr)); | |
123 | } | |
124 | ||
125 | void | |
126 | viceName(long value) | |
127 | { | |
128 | char *alph; | |
129 | int r; | |
130 | ||
131 | alph = "abcdefjhijklmnopqrstuvwxyz"; | |
132 | ||
133 | if (value > 25) | |
134 | viceName(value / 26 - 1); | |
135 | ||
136 | r = value % 26; | |
137 | printf("%c", alph[r]); | |
138 | } | |
139 | ||
140 | /* bc_DoRestore | |
141 | * entry: | |
142 | * aindex - index into bc_dumpTasks that describes this dump. | |
143 | */ | |
144 | int | |
145 | bc_Restorer(afs_int32 aindex) | |
146 | { | |
147 | struct bc_dumpTask *dumpTaskPtr; | |
148 | ||
149 | char vname[BU_MAXNAMELEN]; | |
150 | struct budb_dumpEntry *dumpDescr, dumpDescr1, dumpDescr2; | |
151 | struct budb_volumeEntry *volumeEntries; | |
152 | struct bc_volumeDump *tvol; | |
153 | afs_int32 code = 0, tcode; | |
154 | afs_int32 tapedumpid, parent; | |
155 | ||
156 | afs_int32 nentries = 0; | |
157 | afs_int32 last = 0; | |
158 | afs_int32 next, ve, vecount; | |
159 | struct bc_tapeItem *ti, *pti, *nti; | |
160 | struct bc_tapeList *tapeList = (struct bc_tapeList *)0; | |
161 | struct bc_tapeList *tle, *ptle, *ntle; | |
162 | afs_int32 tlid; | |
163 | afs_int32 tapeid, tid; | |
164 | ||
165 | struct tc_restoreArray rpcArray; /* the rpc structure we use */ | |
166 | struct tc_restoreDesc *tcarray = (struct tc_restoreDesc *)0; | |
167 | ||
168 | afs_int32 i, startentry, todump; | |
169 | afs_int32 port, nextport; | |
170 | afs_int32 level, tapeseq; | |
171 | afs_int32 foundvolume, voldumplevel; | |
172 | struct rx_connection *aconn = (struct rx_connection *)0; | |
173 | statusP statusPtr, newStatusPtr; | |
174 | ||
175 | struct dumpinfo *dumpinfolist = NULL; | |
176 | struct dumpinfo *pdi, *ndi, *di, *dlevels; | |
177 | struct volinfo *nvi, *vi; | |
178 | afs_int32 lvl, lv; | |
179 | int num_dlevels = 20; | |
180 | ||
181 | afs_uint32 serverAll; /* The server to which all volumes are to be restore to */ | |
182 | afs_int32 partitionAll; /* Likewise for partition */ | |
183 | struct hostent *hostPtr; | |
184 | long haddr; | |
185 | time_t did; | |
186 | int foundtape, c; | |
187 | ||
188 | dlevels = malloc(num_dlevels * sizeof(*dlevels)); | |
189 | ||
190 | dumpTaskPtr = &bc_dumpTasks[aindex]; | |
191 | serverAll = HOSTADDR(&dumpTaskPtr->destServer); | |
192 | partitionAll = dumpTaskPtr->destPartition; | |
193 | ||
194 | volumeEntries = malloc(MAXTAPESATONCE * sizeof(struct budb_volumeEntry)); | |
195 | if (!volumeEntries) { | |
196 | afs_com_err(whoami, BC_NOMEM, NULL); | |
197 | ERROR(BC_NOMEM); | |
198 | } | |
199 | ||
200 | /* For each volume to restore, find which dump it's most recent full or | |
201 | * incremental is on and thread onto our dump list (from oldest to newest | |
202 | * dump). Also hang the volume off of the dump (no particular order). | |
203 | */ | |
204 | for (tvol = dumpTaskPtr->volumes; tvol; tvol = tvol->next) { /*tvol */ | |
205 | strcpy(vname, tvol->name); | |
206 | dumpDescr = &dumpDescr1; | |
207 | if (dumpTaskPtr->parentDumpID > 0) /* Told which dump to try */ | |
208 | { | |
209 | /* Right now, this assumes that all volumes listed will be | |
210 | * from the given dumpID. FIXME | |
211 | */ | |
212 | code = bcdb_FindDumpByID(dumpTaskPtr->parentDumpID, dumpDescr); | |
213 | if (code) | |
214 | { | |
215 | afs_com_err(whoami, code, "Couldn't look up info for dump %d\n", | |
216 | dumpTaskPtr->parentDumpID); | |
217 | continue; | |
218 | } | |
219 | code = bcdb_FindVolumes(dumpTaskPtr->parentDumpID, vname, volumeEntries, | |
220 | last, &next, MAXTAPESATONCE, &vecount); | |
221 | if (code) | |
222 | { | |
223 | if (!BackupName(vname)) | |
224 | { | |
225 | strcat(vname, ".backup"); | |
226 | code = bcdb_FindVolumes(dumpTaskPtr->parentDumpID, vname, volumeEntries, | |
227 | last, &next, MAXTAPESATONCE, &vecount); | |
228 | } | |
229 | } | |
230 | } | |
231 | else | |
232 | { | |
233 | code = bcdb_FindDump(vname, dumpTaskPtr->fromDate, dumpDescr); | |
234 | if (!BackupName(vname)) { /* See if backup volume is there */ | |
235 | strcat(vname, ".backup"); | |
236 | dumpDescr = &dumpDescr2; | |
237 | tcode = code; | |
238 | code = bcdb_FindDump(vname, dumpTaskPtr->fromDate, dumpDescr); | |
239 | ||
240 | if (code) { /* Can't find backup, go with first results */ | |
241 | strcpy(vname, tvol->name); | |
242 | dumpDescr = &dumpDescr1; | |
243 | code = tcode; | |
244 | } else if (!tcode) { /* Both found an entry, go with latest result */ | |
245 | if (dumpDescr1.created > dumpDescr2.created) { | |
246 | strcpy(vname, tvol->name); | |
247 | dumpDescr = &dumpDescr1; | |
248 | code = tcode; | |
249 | } | |
250 | } | |
251 | } | |
252 | } | |
253 | ||
254 | if (code) { /* If FindDump took an error */ | |
255 | afs_com_err(whoami, code, "; Can't find any dump for volume %s", | |
256 | tvol->name); | |
257 | continue; | |
258 | } | |
259 | ||
260 | /* look to see if this dump has already been found */ | |
261 | for (pdi = 0, di = dumpinfolist; di; pdi = di, di = di->next) { | |
262 | if (di->DumpId < dumpDescr->id) { | |
263 | di = 0; | |
264 | break; | |
265 | } else if (di->DumpId == dumpDescr->id) { | |
266 | break; | |
267 | } | |
268 | } | |
269 | ||
270 | /* If didn't find it, create one and thread into list */ | |
271 | if (!di) { | |
272 | di = calloc(1, sizeof(struct dumpinfo)); | |
273 | if (!di) { | |
274 | afs_com_err(whoami, BC_NOMEM, NULL); | |
275 | ERROR(BC_NOMEM); | |
276 | } | |
277 | ||
278 | di->DumpId = dumpDescr->id; | |
279 | di->initialDumpId = dumpDescr->initialDumpID; | |
280 | di->parentDumpId = dumpDescr->parent; | |
281 | di->level = dumpDescr->level; | |
282 | ||
283 | if (!pdi) { | |
284 | di->next = dumpinfolist; | |
285 | dumpinfolist = di; | |
286 | } else { | |
287 | di->next = pdi->next; | |
288 | pdi->next = di; | |
289 | } | |
290 | } | |
291 | ||
292 | /* Create one and thread into list */ | |
293 | vi = calloc(1, sizeof(struct volinfo)); | |
294 | if (!vi) { | |
295 | afs_com_err(whoami, BC_NOMEM, NULL); | |
296 | ERROR(BC_NOMEM); | |
297 | } | |
298 | ||
299 | vi->volname = strdup(vname); | |
300 | if (!vi->volname) { | |
301 | free(vi); | |
302 | afs_com_err(whoami, BC_NOMEM, NULL); | |
303 | ERROR(BC_NOMEM); | |
304 | } | |
305 | ||
306 | if (serverAll) { | |
307 | vi->server = serverAll; | |
308 | vi->partition = partitionAll; | |
309 | } else { | |
310 | vi->server = HOSTADDR(&tvol->server); | |
311 | vi->partition = tvol->partition; | |
312 | } | |
313 | ||
314 | /* thread onto end of list */ | |
315 | if (!di->lastinlist) | |
316 | di->volinfolist = vi; | |
317 | else | |
318 | di->lastinlist->next = vi; | |
319 | di->lastinlist = vi; | |
320 | } /*tvol */ | |
321 | ||
322 | /* For each of the above dumps we found (they could be increments), find | |
323 | * the dump's lineage (up to the full dump). | |
324 | */ | |
325 | for (di = dumpinfolist; di; di = di->next) { | |
326 | /* Find each of the parent dumps */ | |
327 | memcpy(&dlevels[0], di, sizeof(struct dumpinfo)); | |
328 | for (lvl = 1, parent = dlevels[0].parentDumpId; parent; | |
329 | parent = dlevels[lvl].parentDumpId, lvl++) { | |
330 | if (lvl >= num_dlevels) { /* running out of dump levels */ | |
331 | struct dumpinfo *tdl = dlevels; | |
332 | ||
333 | num_dlevels += num_dlevels; /* double */ | |
334 | dlevels = malloc(num_dlevels * sizeof(*dlevels)); | |
335 | memcpy(dlevels, tdl, (num_dlevels/2) * sizeof(*dlevels)); | |
336 | free(tdl); | |
337 | } | |
338 | code = bcdb_FindDumpByID(parent, &dumpDescr1); | |
339 | if (code) { | |
340 | for (vi = di->volinfolist; vi; vi = vi->next) { | |
341 | afs_com_err(whoami, code, | |
342 | "; Can't find parent DumpID %u for volume %s", | |
343 | parent, vi->volname); | |
344 | } | |
345 | break; | |
346 | } | |
347 | ||
348 | dlevels[lvl].DumpId = dumpDescr1.id; | |
349 | dlevels[lvl].initialDumpId = dumpDescr1.initialDumpID; | |
350 | dlevels[lvl].parentDumpId = dumpDescr1.parent; | |
351 | dlevels[lvl].level = dumpDescr1.level; | |
352 | } | |
353 | ||
354 | /* For each of the volumes that has a dump in this lineage (vi), | |
355 | * find where it is in each dump level (lv) starting at level 0 and | |
356 | * going to higest. Each dump level could contain one or more | |
357 | * fragments (vecount) of the volume (volume fragments span tapes). | |
358 | * Each volume fragment is sorted by tapeid, tape sequence, and tape | |
359 | * position. | |
360 | */ | |
361 | for (vi = di->volinfolist; vi; vi = vi->next) { | |
362 | tle = tapeList; /* Use for searching the tapelist */ | |
363 | ptle = 0; /* The previous tape list entry */ | |
364 | tlid = 0; /* tapeid of first entry */ | |
365 | /* Volume's dump-level. May not be same as dump's dump-level. This | |
366 | * value gets incremented everytime the volume is found on a dump. | |
367 | */ | |
368 | voldumplevel = 0; | |
369 | ||
370 | /* Do from level 0 dump to highest level dump */ | |
371 | for (lv = (lvl - 1); lv >= 0; lv--) { | |
372 | foundvolume = 0; /* If found volume on this dump */ | |
373 | tapeid = | |
374 | (dlevels[lv].initialDumpId ? dlevels[lv]. | |
375 | initialDumpId : dlevels[lv].DumpId); | |
376 | ||
377 | /* Cycle through the volume fragments for this volume on the tape */ | |
378 | for (last = 0, c = 0; last >= 0; last = next, c++) { | |
379 | code = | |
380 | bcdb_FindVolumes(dlevels[lv].DumpId, vi->volname, | |
381 | volumeEntries, last, &next, | |
382 | MAXTAPESATONCE, &vecount); | |
383 | if (code) { | |
384 | /* Volume wasn't found on the tape - so continue. | |
385 | * This can happen when volume doesn't exist during level 0 dump | |
386 | * but exists for incremental dump. | |
387 | */ | |
388 | if (code == BUDB_ENDOFLIST) { | |
389 | code = 0; | |
390 | break; | |
391 | } | |
392 | ||
393 | afs_com_err(whoami, code, | |
394 | "; Can't find volume %s in DumpID %u", | |
395 | vi->volname, dlevels[lv].DumpId); | |
396 | ERROR(code); | |
397 | } | |
398 | ||
399 | /* If we have made the Findvolumes call more than once for the same | |
400 | * volume, then begin the search at the top. This sort assumes that | |
401 | * we are collecting information from lowest level dump (full dump) | |
402 | * to the highest level dump (highest incremental) | |
403 | * and from first fragment to last fragment at each level. If | |
404 | * there is more than one call to FindVolumes, this is not true | |
405 | * anymore. | |
406 | */ | |
407 | if (c) { | |
408 | tle = tapeList; | |
409 | ptle = 0; | |
410 | tlid = 0; | |
411 | } | |
412 | ||
413 | /* For each of the volume fragments that we read, sort them into | |
414 | * the list of tapes they are on. Sort by tapeid, then tape sequence. | |
415 | * Do from first fragment (where volume begins) to last fragment. | |
416 | */ | |
417 | for (ve = (vecount - 1); ve >= 0; ve--) { | |
418 | foundvolume = 1; /* Found the volume on this dump */ | |
419 | foundtape = 0; | |
420 | tapeseq = volumeEntries[ve].tapeSeq; | |
421 | ||
422 | /* Determine where in the list of tapes this should go */ | |
423 | for (; tle; ptle = tle, tle = tle->next) { | |
424 | tid = | |
425 | (tle->initialDumpID ? tle-> | |
426 | initialDumpID : tle->dumpID); | |
427 | ||
428 | /* Sort by tapeids. BUT, we don't want add an entry in the middle | |
429 | * of a dumpset (might split a volume fragmented across tapes). | |
430 | * So make sure we step to next dumpset. tlid is the tapeid of | |
431 | * the last tape we added a volume to. This can happen when an | |
432 | * incremental was appended to a tape created prior its parent- | |
433 | * dump's tape, and needs to be restored after it. | |
434 | */ | |
435 | if (tapeid < tid) { | |
436 | if (tlid != tid) { | |
437 | tle = 0; | |
438 | break; | |
439 | } /* Allocate and insert a tape entry */ | |
440 | } | |
441 | ||
442 | /* Found the tapeid (the dumpset). Check if its the correct | |
443 | * tape sequence | |
444 | */ | |
445 | else if (tapeid == tid) { | |
446 | if (tapeseq < tle->tapeNumber) { | |
447 | tle = 0; | |
448 | break; | |
449 | } | |
450 | /* Allocate and insert a tape entry */ | |
451 | if (tapeseq == tle->tapeNumber) { | |
452 | break; | |
453 | } | |
454 | /* Don't allocate tape entry */ | |
455 | foundtape = 1; /* Found dumpset but not the tape */ | |
456 | } | |
457 | ||
458 | /* Prevously found the tapeid (the dumpset) but this tape | |
459 | * sequence not included (the tapeid has changed). So add | |
460 | * this tape entry to the end of its dumpset. | |
461 | */ | |
462 | else if (foundtape) { | |
463 | tle = 0; | |
464 | break; | |
465 | } | |
466 | /* Allocate and insert a tape entry */ | |
467 | } | |
468 | ||
469 | /* Allocate a new tapelist entry if one not found */ | |
470 | if (!tle) { | |
471 | tle = calloc(1, sizeof(struct bc_tapeList)); | |
472 | if (!tle) { | |
473 | afs_com_err(whoami, BC_NOMEM, NULL); | |
474 | return (BC_NOMEM); | |
475 | } | |
476 | ||
477 | tle->tapeName = strdup(volumeEntries[ve].tape); | |
478 | if (!tle->tapeName) { | |
479 | free(tle); | |
480 | afs_com_err(whoami, BC_NOMEM, NULL); | |
481 | return (BC_NOMEM); | |
482 | } | |
483 | ||
484 | tle->dumpID = dlevels[lv].DumpId; | |
485 | tle->initialDumpID = dlevels[lv].initialDumpId; | |
486 | tle->tapeNumber = tapeseq; | |
487 | ||
488 | /* Now thread the tape onto the list */ | |
489 | if (!ptle) { | |
490 | tle->next = tapeList; | |
491 | tapeList = tle; | |
492 | } else { | |
493 | tle->next = ptle->next; | |
494 | ptle->next = tle; | |
495 | } | |
496 | } | |
497 | tlid = | |
498 | (tle->initialDumpID ? tle->initialDumpID : tle-> | |
499 | dumpID); | |
500 | ||
501 | /* Now place the volume fragment into the correct position on | |
502 | * this tapelist entry. Duplicate entries are ignored. | |
503 | */ | |
504 | for (pti = 0, ti = tle->restoreList; ti; | |
505 | pti = ti, ti = ti->next) { | |
506 | if (volumeEntries[ve].position < ti->position) { | |
507 | ti = 0; | |
508 | break; | |
509 | } | |
510 | /* Allocate an entry */ | |
511 | else if (volumeEntries[ve].position == | |
512 | ti->position) { | |
513 | break; | |
514 | } /* Duplicate entry */ | |
515 | } | |
516 | ||
517 | /* If didn't find one, allocate and thread onto list. | |
518 | * Remember the server and partition. | |
519 | */ | |
520 | if (!ti) { | |
521 | ti = calloc(1, sizeof(struct bc_tapeItem)); | |
522 | if (!ti) { | |
523 | afs_com_err(whoami, BC_NOMEM, NULL); | |
524 | return (BC_NOMEM); | |
525 | } | |
526 | ||
527 | ti->volumeName = strdup(volumeEntries[ve].name); | |
528 | if (!ti->volumeName) { | |
529 | free(ti); | |
530 | afs_com_err(whoami, BC_NOMEM, NULL); | |
531 | return (BC_NOMEM); | |
532 | } | |
533 | ||
534 | ti->server = vi->server; | |
535 | ti->partition = vi->partition; | |
536 | ti->oid = volumeEntries[ve].id; | |
537 | ti->position = volumeEntries[ve].position; | |
538 | ti->vollevel = voldumplevel; | |
539 | ti->dumplevel = dlevels[lv].level; | |
540 | ti->lastdump = ((lv == 0) ? 1 : 0); | |
541 | ||
542 | if (!pti) { | |
543 | ti->next = tle->restoreList; | |
544 | tle->restoreList = ti; | |
545 | } else { | |
546 | ti->next = pti->next; | |
547 | pti->next = ti; | |
548 | } | |
549 | ||
550 | nentries++; | |
551 | } /* !ti */ | |
552 | } /* ve: for each returned volume fragment by bcdb_FindVolumes() */ | |
553 | } /* last: Multiple calls to bcdb_FindVolumes() */ | |
554 | ||
555 | if (foundvolume) | |
556 | voldumplevel++; | |
557 | } /* lv: For each dump level */ | |
558 | } /* vi: For each volume to search for in the dump hierarchy */ | |
559 | } /* di: For each dump */ | |
560 | ||
561 | if (!nentries) { | |
562 | afs_com_err(whoami, 0, "No volumes to restore"); | |
563 | ERROR(0); | |
564 | } | |
565 | ||
566 | if (dumpTaskPtr->dontExecute) { | |
567 | for (tle = tapeList; tle; tle = tle->next) { | |
568 | for (ti = tle->restoreList; ti; ti = ti->next) { | |
569 | tapedumpid = | |
570 | (tle->initialDumpID ? tle->initialDumpID : tle->dumpID); | |
571 | strcpy(vname, ti->volumeName); | |
572 | StripBackup(vname); | |
573 | if (dumpTaskPtr->newExt) | |
574 | strcat(vname, dumpTaskPtr->newExt); | |
575 | ||
576 | /* print volume to restore and the tape and position its on */ | |
577 | if (serverAll) { | |
578 | printf | |
579 | ("Restore volume %s (ID %d) from tape %s (%u), position %d", | |
580 | ti->volumeName, ti->oid, tle->tapeName, tapedumpid, | |
581 | ti->position); | |
582 | ||
583 | if (strcmp(ti->volumeName, vname) != 0) | |
584 | printf(" as %s", vname); | |
585 | ||
586 | printf(".\n"); | |
587 | } | |
588 | ||
589 | /* print in format recognized by volsetrestore */ | |
590 | else { | |
591 | haddr = ti->server; | |
592 | hostPtr = | |
593 | gethostbyaddr((char *)&haddr, sizeof(haddr), AF_INET); | |
594 | if (hostPtr) | |
595 | printf("%s", hostPtr->h_name); | |
596 | else | |
597 | printf("%u", ti->server); | |
598 | ||
599 | printf(" /vicep"); | |
600 | viceName(ti->partition); | |
601 | ||
602 | printf(" %s # as %s; %s (%u); pos %d;", ti->volumeName, | |
603 | vname, tle->tapeName, tapedumpid, ti->position); | |
604 | ||
605 | did = tle->dumpID; | |
606 | printf(" %s", ctime(&did)); | |
607 | } | |
608 | } | |
609 | } | |
610 | ||
611 | ERROR(0); | |
612 | } | |
613 | ||
614 | /* Allocate a list of volumes to restore */ | |
615 | tcarray = calloc(nentries, sizeof(struct tc_restoreDesc)); | |
616 | if (!tcarray) { | |
617 | afs_com_err(whoami, BC_NOMEM, NULL); | |
618 | ERROR(BC_NOMEM); | |
619 | } | |
620 | ||
621 | /* Fill in the array with the list above */ | |
622 | i = 0; | |
623 | for (tle = tapeList; tle; tle = tle->next) { | |
624 | for (ti = tle->restoreList; ti; ti = ti->next) { | |
625 | tcarray[i].origVid = ti->oid; /* means unknown */ | |
626 | tcarray[i].vid = 0; | |
627 | tcarray[i].flags = 0; | |
628 | if (ti->vollevel == 0) | |
629 | tcarray[i].flags |= RDFLAG_FIRSTDUMP; | |
630 | if (ti->lastdump) | |
631 | tcarray[i].flags |= RDFLAG_LASTDUMP; | |
632 | tcarray[i].position = ti->position; | |
633 | tcarray[i].dbDumpId = tle->dumpID; | |
634 | tcarray[i].initialDumpId = tle->initialDumpID; | |
635 | tcarray[i].hostAddr = ti->server; /* just the internet address */ | |
636 | tcarray[i].partition = ti->partition; | |
637 | ||
638 | strcpy(tcarray[i].tapeName, tle->tapeName); | |
639 | strcpy(tcarray[i].oldName, ti->volumeName); | |
640 | strcpy(tcarray[i].newName, ti->volumeName); | |
641 | StripBackup(tcarray[i].newName); | |
642 | if (dumpTaskPtr->newExt) | |
643 | strcat(tcarray[i].newName, dumpTaskPtr->newExt); | |
644 | ||
645 | tcarray[i].dumpLevel = ti->dumplevel; | |
646 | i++; | |
647 | } | |
648 | } | |
649 | ||
650 | printf("Starting restore\n"); | |
651 | ||
652 | /* Loop until all of the tape entries are used */ | |
653 | for (startentry = 0; startentry < nentries; startentry += todump) { | |
654 | /* Get all the next tape entries with the same port offset */ | |
655 | if (dumpTaskPtr->portCount == 0) { | |
656 | port = 0; | |
657 | todump = nentries - startentry; | |
658 | } else if (dumpTaskPtr->portCount == 1) { | |
659 | port = dumpTaskPtr->portOffset[0]; | |
660 | todump = nentries - startentry; | |
661 | } else { | |
662 | level = tcarray[startentry].dumpLevel; | |
663 | port = | |
664 | dumpTaskPtr-> | |
665 | portOffset[(level <= | |
666 | dumpTaskPtr->portCount - | |
667 | 1 ? level : dumpTaskPtr->portCount - 1)]; | |
668 | ||
669 | for (todump = 1; ((startentry + todump) < nentries); todump++) { | |
670 | level = tcarray[startentry + todump].dumpLevel; | |
671 | nextport = | |
672 | dumpTaskPtr-> | |
673 | portOffset[(level <= | |
674 | dumpTaskPtr->portCount - | |
675 | 1 ? level : dumpTaskPtr->portCount - 1)]; | |
676 | if (port != nextport) | |
677 | break; /* break if we change ports */ | |
678 | } | |
679 | } | |
680 | ||
681 | rpcArray.tc_restoreArray_len = todump; | |
682 | rpcArray.tc_restoreArray_val = &tcarray[startentry]; | |
683 | ||
684 | code = ConnectButc(dumpTaskPtr->config, port, &aconn); | |
685 | if (code) | |
686 | return (code); | |
687 | ||
688 | if (tcarray[startentry].dumpLevel == 0) | |
689 | printf("\nFull restore being processed on port %d\n", port); | |
690 | else | |
691 | printf("\nIncremental restore being processed on port %d\n", | |
692 | port); | |
693 | ||
694 | code = | |
695 | TC_PerformRestore(aconn, "DumpSetName", &rpcArray, | |
696 | &dumpTaskPtr->dumpID); | |
697 | if (code) { | |
698 | afs_com_err(whoami, code, "; Failed to start restore"); | |
699 | break; | |
700 | } | |
701 | ||
702 | /* setup status monitor node */ | |
703 | statusPtr = createStatusNode(); | |
704 | lock_Status(); | |
705 | statusPtr->port = port; | |
706 | statusPtr->taskId = dumpTaskPtr->dumpID; | |
707 | statusPtr->jobNumber = bc_jobNumber(); | |
708 | statusPtr->flags &= ~STARTING; /* clearStatus to examine */ | |
709 | if (tcarray[startentry].dumpLevel == 0) | |
710 | sprintf(statusPtr->taskName, "Full Restore"); | |
711 | else | |
712 | sprintf(statusPtr->taskName, "Incremental Restore"); | |
713 | unlock_Status(); | |
714 | ||
715 | /* Wait until this restore pass is complete before starting the next | |
716 | * pass. Query the statusWatcher for the status | |
717 | */ | |
718 | while (1) { | |
719 | lock_Status(); | |
720 | newStatusPtr = findStatus(dumpTaskPtr->dumpID); | |
721 | if (!newStatusPtr | |
722 | || (newStatusPtr-> | |
723 | flags & (ABORT_REQUEST | ABORT_SENT | ABORT_DONE | | |
724 | TASK_ERROR))) { | |
725 | unlock_Status(); | |
726 | ERROR(0); | |
727 | } else if (newStatusPtr->flags & (TASK_DONE)) { | |
728 | unlock_Status(); | |
729 | break; | |
730 | } | |
731 | ||
732 | unlock_Status(); | |
733 | IOMGR_Sleep(2); | |
734 | } | |
735 | ||
736 | if (aconn) | |
737 | rx_DestroyConnection(aconn); | |
738 | aconn = (struct rx_connection *)0; | |
739 | } /* while */ | |
740 | ||
741 | /* free up everything */ | |
742 | error_exit: | |
743 | if (aconn) | |
744 | rx_DestroyConnection(aconn); | |
745 | ||
746 | if (tcarray) | |
747 | free(tcarray); | |
748 | ||
749 | /* Free the dumpinfo list and its volumes */ | |
750 | for (di = dumpinfolist; di; di = ndi) { | |
751 | for (vi = di->volinfolist; vi; vi = nvi) { | |
752 | if (vi->volname) | |
753 | free(vi->volname); | |
754 | nvi = vi->next; | |
755 | free(vi); | |
756 | } | |
757 | ndi = di->next; | |
758 | free(di); | |
759 | } | |
760 | ||
761 | /* Free the tape lists and items */ | |
762 | for (tle = tapeList; tle; tle = ntle) { | |
763 | for (ti = tle->restoreList; ti; ti = nti) { | |
764 | nti = ti->next; | |
765 | if (ti->volumeName) | |
766 | free(ti->volumeName); | |
767 | free(ti); | |
768 | } | |
769 | ntle = tle->next; | |
770 | if (tle->tapeName) | |
771 | free(tle->tapeName); | |
772 | free(tle); | |
773 | } | |
774 | ||
775 | /* free local-like things we alloacted to save stack space */ | |
776 | if (volumeEntries) | |
777 | free(volumeEntries); | |
778 | ||
779 | free(dlevels); | |
780 | ||
781 | return code; | |
782 | } |