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