Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / bucoord / restore.c
CommitLineData
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
33extern struct bc_dumpTask bc_dumpTasks[BC_MAXSIMDUMPS];
34extern 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 */
43struct 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
53struct 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 */
63struct 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. */
75struct 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 */
88static int
89StripBackup(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
100int
101BackupName(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
113int
114extractTapeSeq(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
125void
126viceName(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 */
144int
145bc_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}