2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
15 #include <sys/types.h>
21 #include <netinet/in.h>
25 #include <afs/procmgmt.h>
31 #include <afs/tcdata.h>
32 #include <afs/bubasics.h> /* PA */
33 #include <afs/budb_client.h>
34 #include <afs/volser.h>
35 #include <afs/com_err.h>
36 #include "error_macros.h"
37 #include <afs/afsutil.h>
39 #include "butc_xbsa.h"
41 /* GLOBAL CONFIGURATION PARAMETERS */
42 extern int dump_namecheck;
43 extern int queryoperator;
44 extern int tapemounted;
45 extern char *opencallout;
46 extern char *closecallout;
48 extern char *extractDumpName();
49 extern int BufferSize; /* Size in B stored for header info */
50 extern char *restoretofile;
51 FILE *restoretofilefd;
52 extern int forcemultiple;
54 /* XBSA Global Parameters */
57 struct butx_transactionInfo butxInfo;
60 struct TapeBlock { /* A 16KB tapeblock */
61 char mark[BUTM_HDRSIZE]; /* Header info */
62 char data[BUTM_BLKSIZE]; /* data */
65 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
66 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
69 * Need to re-write to:
70 * 1) non-interactive tape handling (optional)
71 * 2) compute tape and volume sizes for the database
72 * 3) compute and use tape id's for tape tracking (put on tape label)
73 * 4) status management
76 /* All the relevant info shared between Restorer and restoreVolume */
79 struct dumpNode *nodePtr;
81 char mntTapeName[BU_MAXTAPELEN];
83 struct butm_tapeInfo *tapeInfoPtr;
86 /* Abort checks are done after each BIGCHUNK of data transfer */
87 #define BIGCHUNK 102400
89 #define HEADER_CHECKS(vhptr, header) \
91 afs_int32 magic, versionflags; \
93 versionflags = ntohl(vhptr.versionflags); \
94 if ( versionflags == TAPE_VERSION_0 || \
95 versionflags == TAPE_VERSION_1 || \
96 versionflags == TAPE_VERSION_2 || \
97 versionflags == TAPE_VERSION_3 || \
98 versionflags == TAPE_VERSION_4 ) { \
100 magic = ntohl(vhptr.magic); /* another sanity check */ \
101 if (magic == TC_VOLBEGINMAGIC || \
102 magic == TC_VOLENDMAGIC || \
103 magic == TC_VOLCONTD ) { \
105 bcopy (&vhptr, header, sizeof(struct volumeHeader)); \
108 } /* versionflags */ \
112 extern FILE *ErrorlogIO;
113 extern FILE *centralLogIO;
114 extern FILE *lastLogIO;
115 extern afs_int32 lastPass; /* Set true during last pass of dump */
116 extern int debugLevel;
117 extern int autoQuery;
118 extern struct tapeConfig globalTapeConfig;
119 extern struct deviceSyncNode *deviceLatch;
120 extern char globalCellName[];
124 /* forward declaration */
125 afs_int32 readVolumeHeader(/*char *buffer,afs_int32 bufloc,(struct volumeHeader *)vhptr*/);
127 /* The on-disk volume header or trailer can differ in size from platform to platform */
128 struct TapeBlock tapeBlock;
129 char tapeVolumeHT[sizeof(struct volumeHeader) + 2*sizeof(char)];
132 PrintLog(log, error1, error2, str, a,b,c,d,e,f,g,h,i,j)
134 afs_int32 error1, error2;
135 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
139 fprintf(log, str, a,b,c,d,e,f,g,h,i,j);
145 case VSALVAGE: err1 = "Volume needs to be salvaged"; break;
146 case VNOVNODE: err1 = "Bad vnode number quoted"; break;
147 case VNOVOL: err1 = "Volume not attached, does not exist, or not on line"; break;
148 case VVOLEXISTS: err1 = "Volume already exists"; break;
149 case VNOSERVICE: err1 = "Volume is not in service"; break;
150 case VOFFLINE: err1 = "Volume is off line"; break;
151 case VONLINE: err1 = "Volume is already on line"; break;
152 case VDISKFULL: err1 = "Partition is full"; break;
153 case VOVERQUOTA: err1 = "Volume max quota exceeded"; break;
154 case VBUSY: err1 = "Volume temporarily unavailable"; break;
155 case VMOVED: err1 = "Volume has moved to another server"; break;
157 err1 = (char *)error_message(error1);
158 err2 = (char *)error_table_name(error1);
161 if (error1 == -1) fprintf(log, " Possible communication failure");
162 else fprintf(log, " %s: %s", err2, err1);
163 if (error2) fprintf(log, ": %s", error_message(error2));
170 TapeLog(debug, task, error1, error2, str, a,b,c,d,e,f,g,h,i,j)
172 afs_int32 task, error1, error2;
173 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
176 char tbuffer[32], *timestr;
179 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
182 fprintf(logIO, "%s: ", timestr);
183 if (task) fprintf(logIO, "Task %u: ", task);
184 PrintLog(logIO, error1, error2, str, a,b,c,d,e,f,g,h,i,j);
186 if (lastPass && lastLogIO) {
187 fprintf(lastLogIO, "%s: ", timestr);
188 if (task) fprintf(lastLogIO, "Task %u: ", task);
189 PrintLog(lastLogIO, error1, error2, str, a,b,c,d,e,f,g,h,i,j);
192 /* Now print to the screen if debug level requires */
193 if (debug <= debugLevel)
194 PrintLog(stdout, error1, error2, str, a,b,c,d,e,f,g,h,i,j);
198 TLog(task, str, a,b,c,d,e,f,g,h,i,j)
200 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
202 /* Sends message to TapeLog and stdout */
203 TapeLog (0, task, 0,0, str, a,b,c,d,e,f,g,h,i,j);
207 ErrorLog(debug, task, error1, error2, str, a,b,c,d,e,f,g,h,i,j)
209 afs_int32 task, error1, error2;
210 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
213 char tbuffer[32], *timestr;
216 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
218 fprintf(ErrorlogIO, "%s: ", timestr);
220 /* Print the time and task number */
221 if (task) fprintf(ErrorlogIO, "Task %u: ", task);
222 PrintLog(ErrorlogIO, error1, error2, str, a,b,c,d,e,f,g,h,i,j);
224 TapeLog(debug, task, error1, error2, str, a,b,c,d,e,f,g,h,i,j);
228 ELog(task, str, a,b,c,d,e,f,g,h,i,j)
230 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
232 /* Sends message to ErrorLog, TapeLog and stdout */
233 ErrorLog (0, task, 0,0, str, a,b,c,d,e,f,g,h,i,j);
236 /* first proc called by anybody who intends to use the device */
237 void EnterDeviceQueue(devLatch)
238 struct deviceSyncNode *devLatch;
240 ObtainWriteLock(&(devLatch->lock));
241 devLatch->flags = TC_DEVICEINUSE;
244 /* last proc called by anybody finishing using the device */
245 void LeaveDeviceQueue(devLatch)
246 struct deviceSyncNode *devLatch;
249 ReleaseWriteLock(&(devLatch->lock));
252 #define BELLTIME 60 /* 60 seconds before a bell rings */
253 #define BELLCHAR 7 /* ascii for bell */
256 #ifdef AFS_PTHREAD_ENV
258 /* WaitForKeystroke : Wait until a key has been struck or time (secconds)
259 * runs out and return to caller. The NT version of this function will return
260 * immediately after a key has been pressed (doesn't wait for cr).
262 * seconds: wait for <seconds> seconds before returning. If seconds < 0,
265 * 1: Keyboard input available
266 * 0: seconds elapsed. Timeout.
268 * STOLEN FROM LWP_WaitForKeystroke()
270 int WaitForKeystroke(int seconds)
272 time_t startTime, nowTime;
274 struct timeval twait;
283 /* check if we have a keystroke */
284 if (_kbhit()) return 1;
285 if (timeleft == 0) break;
287 /* sleep for LWP_KEYSTROKE_DELAY ms and let other
289 select(0, 0, 0, 0, &twait);
291 if (seconds > 0) { /* we only worry about elapsed time if
292 * not looping forever (seconds < 0) */
294 timeleft = seconds - difftime(nowTime, startTime);
296 } while(timeleft > 0);
299 #else /* AFS_NT40)ENV */
300 extern int WaitForKeystroke(int);
302 * STOLEN FROM LWP_WaitForKeystroke()
304 int WaitForKeystroke(int seconds)
308 struct timeval twait;
309 struct timeval *tp = NULL;
311 #ifdef AFS_LINUX20_ENV
312 if (stdin->_IO_read_ptr < stdin->_IO_read_end)
319 FD_SET(fileno(stdin), &rdfds);
322 twait.tv_sec = seconds;
326 code = select(1+fileno(stdin), &rdfds, NULL, NULL, tp);
327 return (code == 1) ? 1 : 0;
331 /* GetResponseKey() - Waits for a specified period of time and
332 * returns a char when one has been typed by the user.
334 * seconds - how long to wait for a key press.
335 * *key - char entered by user
337 * 0 - Time ran out before the user typed a key.
338 * 1 - Valid char is being returned.
340 * STOLEN FROM LWP_GetResponseKey();
342 int GetResponseKey(int seconds, char *key)
346 if (key == NULL) return 0; /* need space to store char */
347 fflush(stdin); /* flush all existing data and start anew */
349 rc = WaitForKeystroke(seconds);
350 if (rc == 0) { /* time ran out */
355 /* now read the char. */
357 *key = getche(); /* get char and echo it to screen */
363 #endif /* AFS_PTHREAD_ENV
368 * only external clients are in recoverDb.c. Was static. PA
377 #ifdef AFS_PTHREAD_ENV
378 w = WaitForKeystroke(0);
380 w = LWP_WaitForKeystroke(0);
381 #endif /* AFS_PTHREAD_ENV */
388 #endif /* AFS_NT40_ENV */
395 int callOutRoutine(taskId, tapePath, flag, name, dbDumpId, tapecount)
420 callOut = opencallout;
424 strcpy(Sopcode, "restore");
427 strcpy(Sopcode, "appenddump");
430 strcpy(Sopcode, "dump");
433 strcpy(Sopcode, "labeltape");
435 case READLABELOPCODE:
436 strcpy(Sopcode, "readlabel");
439 strcpy(Sopcode, "scantape");
441 case RESTOREDBOPCODE:
442 strcpy(Sopcode, "restoredb");
445 strcpy(Sopcode, "savedb");
448 strcpy(Sopcode, "unmount");
449 callOut = closecallout;
452 strcpy(Sopcode, "unknown");
456 if (!callOut) /* no script to call */
459 strcpy(ScallOut, callOut);
460 CO_argv[0] = ScallOut;
462 strcpy(StapePath, tapePath);
463 CO_argv[1] = StapePath;
465 CO_argv[2] = Sopcode;
467 if (flag == CLOSEOPCODE)
469 CO_argv[3] = (char *)0;
473 sprintf(Scount, "%d", tapecount);
476 /* The tape label name - special case labeltape */
477 if ( !name || (strcmp(name,"") == 0) ) /* no label */
478 strcpy(Stape, "none");
479 else { /* labeltape */
481 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
482 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
491 strcpy(Sdumpid, "none");
493 sprintf(Sdumpid, "%u", dbDumpId);
494 CO_argv[5] = Sdumpid;
496 CO_argv[6] = (char *)0;
499 CO_envp[0] = (char *)0;
501 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
503 ErrorLog(0, taskId, errno, 0, "Call to %s outside routine %s failed\n",
513 * Unmounts a tape and prints a warning if it can't unmount it.
514 * Regardless of error, the closecallout routine will be called
515 * (unless a tape is not mounted in the first place).
517 unmountTape(taskId, tapeInfoPtr)
519 struct butm_tapeInfo *tapeInfoPtr;
523 int cpid, status, rcpid;
525 code = butm_Dismount(tapeInfoPtr);
526 if (code && (code != BUTM_NOMOUNT))
527 ErrorLog(0, taskId, code, (tapeInfoPtr)->error, "Warning: Can't close tape\n");
529 if (tapemounted && closecallout)
531 setStatus(taskId, CALL_WAIT);
533 cpid = callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "", 0, 1);
534 while (cpid) /* Wait until return */
537 rcpid = waitpid(cpid, &status, WNOHANG);
543 if (rcpid == -1 && errno != EINTR) {
545 com_err(whoami, errno, "Error waiting for callout script to terminate.");
548 #ifdef AFS_PTHREAD_ENV
554 if ( checkAbortByTaskId(taskId) )
556 TLog(taskId, "Callout routine has been aborted\n");
557 if (kill(cpid, SIGKILL)) /* Cancel callout */
558 ErrorLog(0, taskId, errno, 0, "Kill of callout process %d failed\n", cpid);
563 clearStatus(taskId, CALL_WAIT);
567 * print out prompt to operator
569 * PromptForTape only.
573 PrintPrompt(flag, name, dumpid)
577 char tapename[BU_MAXTAPELEN+32];
580 TAPENAME(tapename, name, dumpid);
582 printf("******* OPERATOR ATTENTION *******\n");
583 printf("Device : %s \n",globalTapeConfig.device);
587 case READOPCODE: /* mount for restore */
588 printf("Please put in tape %s for reading", tapename);
591 case APPENDOPCODE: /* mount for dump (appends) */
593 dn = extractDumpName(name);
596 printf("Please put in last tape of dump set for appending dump");
598 printf("Please put in last tape of dump set for appending dump %s (DumpID %u)",
602 case WRITEOPCODE: /* mount for dump */
603 if (strcmp(name,"") == 0)
604 printf("Please put in tape for writing");
606 /* The name is what we are going to label the tape as */
608 printf("Please put in tape %s for writing", tapename);
611 case LABELOPCODE: /* mount for labeltape */
612 printf("Please put in tape to be labelled as %s", tapename);
615 case READLABELOPCODE: /* mount for readlabel */
616 printf("Please put in tape whose label is to be read");
619 case SCANOPCODE: /* mount for scantape */
620 if (strcmp(name,"") == 0)
621 printf("Please put in tape to be scanned");
623 printf("Please put in tape %s for scanning", tapename);
626 case RESTOREDBOPCODE: /* Mount for restoredb */
627 printf("Please insert a tape %s for the database restore", tapename);
630 case SAVEDBOPCODE: /* Mount for savedb */
631 printf("Please insert a writeable tape %s for the database dump", tapename);
637 printf(" and hit return when done\n");
641 * Prompt the operator to change the tape.
642 * Use to be a void routine but now returns an error. Some calls
643 * don't use the error code.
645 * only external clients are in recoverDb.c. Was static PA
647 afs_int32 PromptForTape(flag, name, dbDumpId, taskId, tapecount)
650 afs_uint32 dbDumpId; /* Specific dump ID - If non-zero */
654 register afs_int32 code = 0;
659 int cpid, status, rcpid;
661 if ( checkAbortByTaskId(taskId) )
662 ERROR_EXIT(TC_ABORTEDBYREQUEST);
665 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
667 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
669 CallOut = (opencallout ? 1 : 0);
672 setStatus(taskId, CALL_WAIT);
674 cpid = callOutRoutine(taskId, globalTapeConfig.device, flag, name, dbDumpId, tapecount);
675 if (cpid == 0) CallOut = 0; /* prompt at screen */
678 { /* Check if callout routine finished */
680 rcpid = waitpid(cpid, &status, WNOHANG);
685 else if (WIFEXITED(status))
686 wcode = WEXITSTATUS(status);
692 break; /* All done */
696 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
698 else if ( (flag == READOPCODE) && (wcode == 3) ) {
699 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
703 TLog(taskId, "Callout routine has exited with code %d: will prompt\n", wcode);
704 CallOut = 0; /* Switch to keyboard input */
708 /* if waitpid experienced an error, we prompt */
709 if (rcpid == -1 && errno != EINTR) {
710 com_err(whoami, errno, "Error waiting for callout script to terminate.");
711 TLog(taskId, "Can't get exit status from callout script. will prompt\n", wcode);
715 #ifdef AFS_PTHREAD_ENV
721 if ( checkAbortByTaskId(taskId) )
723 printf("This tape operation has been aborted by the coordinator.\n");
725 if (kill(cpid, SIGKILL)) /* Cancel callout */
726 ErrorLog(0, taskId, errno, 0, "Kill of callout process %d failed\n", cpid);
728 ERROR_EXIT(TC_ABORTEDBYREQUEST);
735 clearStatus(taskId, CALL_WAIT);
736 setStatus(taskId, OPR_WAIT);
738 PrintPrompt(flag, name, dbDumpId);
740 /* Loop until we get ok to go ahead (or abort) */
743 if ( time(0) > start+BELLTIME )
751 #ifdef AFS_PTHREAD_ENV
752 wcode = GetResponseKey(5, &inchr); /* inchr stores key read */
754 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
756 if (wcode == 1) { /* keyboard input is available */
758 if ( (inchr == 'a') || (inchr == 'A') ) {
759 printf("This tape operation has been aborted.\n");
760 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
761 } else if ( (flag == READOPCODE) && ((inchr == 's') || (inchr == 'S')) ) {
762 printf("This tape will be skipped.\n");
763 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
765 break; /* continue */
768 if ( checkAbortByTaskId(taskId) ) {
769 printf("This tape operation has been aborted by the coordinator.\n");
770 ERROR_EXIT(TC_ABORTEDBYREQUEST);
776 printf("Thanks, now proceeding with tape ");
779 case RESTOREDBOPCODE:
785 printf("append writing");
797 case READLABELOPCODE:
798 printf("label reading");
810 printf(" operation.\n");
812 printf("**********************************\n");
814 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
818 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
824 * convert the fields in the tapeVolHeader into host byte order,
825 * placing the converted copy of the structure into the hostVolHeader
827 * tapeVolHeader - points to volume header read from tape
828 * hostVolHeader - pointer to struct for result
830 * hostVolHeader - information in host byte order
834 VolHeaderToHost(hostVolHeader, tapeVolHeader)
835 struct volumeHeader *hostVolHeader, *tapeVolHeader;
837 switch ( ntohl(tapeVolHeader->versionflags) )
840 /* sizes in bytes and fields in host order */
841 bcopy(hostVolHeader, tapeVolHeader, sizeof(struct volumeHeader));
846 case TAPE_VERSION_3: /* for present */
848 /* sizes in K and fields in network order */
849 /* do the conversion field by field */
851 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
852 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
853 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
854 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
855 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
856 hostVolHeader->server = ntohl(tapeVolHeader->server);
857 hostVolHeader->part = ntohl(tapeVolHeader->part);
858 hostVolHeader->from = ntohl(tapeVolHeader->from);
859 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
860 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
861 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
862 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
863 hostVolHeader->level = ntohl(tapeVolHeader->level);
864 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
865 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
866 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
867 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
871 return(TC_BADVOLHEADER);
877 ReadVolHeader(taskId, tapeInfoPtr, volHeaderPtr)
879 struct butm_tapeInfo *tapeInfoPtr;
880 struct volumeHeader *volHeaderPtr;
884 struct volumeHeader volHead;
886 /* Read the volume header */
887 code = butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT), &nbytes);
889 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read volume header on tape\n");
893 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
896 ErrorLog(0, taskId, code, 0, "Can't find volume header on tape block\n");
900 code = VolHeaderToHost(volHeaderPtr, &volHead);
903 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
912 GetVolumeHead(taskId, tapeInfoPtr, position, volName, volId)
914 struct butm_tapeInfo *tapeInfoPtr;
920 struct volumeHeader tapeVolHeader;
922 /* Position directly to the volume and read the header */
924 code = butm_Seek (tapeInfoPtr, position);
926 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't seek to position %u on tape\n",
931 code = butm_ReadFileBegin(tapeInfoPtr);
933 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read FileBegin on tape\n");
937 /* Read the volume header */
938 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
939 if (code) ERROR_EXIT(code);
941 /* Check if volume header matches */
942 if (strcmp(tapeVolHeader.volumeName,volName)) ERROR_EXIT(TC_BADVOLHEADER);
943 if (volId && (tapeVolHeader.volumeID != volId)) ERROR_EXIT(TC_BADVOLHEADER);
944 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC) ERROR_EXIT(TC_BADVOLHEADER);
947 /* Do a sequential search for the volume */
950 code = butm_ReadFileBegin(tapeInfoPtr);
952 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read FileBegin on tape\n");
956 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
957 if (code) ERROR_EXIT(TC_VOLUMENOTONTAPE);
959 /* Test if we found the volume */
960 if ( ( strcmp(tapeVolHeader.volumeName,volName) == 0 ) &&
961 ( !volId || (volId == tapeVolHeader.volumeID) ) )
964 /* skip to the next HW EOF marker */
965 code = SeekFile(tapeInfoPtr, 1);
967 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't seek to next EOF on tape\n");
977 afs_int32 GetRestoreTape(taskId, tapeInfoPtr, tname, tapeID, prompt)
979 struct butm_tapeInfo *tapeInfoPtr;
984 struct butm_tapeLabel tapeLabel;
985 afs_int32 code = 0, rc;
987 struct budb_dumpEntry dumpEntry;
989 /* Make sure that the dump/tape is not a XBSA dump */
990 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
991 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
992 ErrorLog(0, taskId, 0, 0, "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
993 ERROR_EXIT(TC_SKIPTAPE);
1000 code = PromptForTape (READOPCODE, tname, tapeID, taskId, tapecount);
1001 if (code) ERROR_EXIT(code);
1006 code = butm_Mount (tapeInfoPtr, tname);
1009 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
1013 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
1016 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't read tape label\n");
1020 /* Now check the label to see if the tapename matches or tapeids match */
1021 if ( strcmp(TNAME(&tapeLabel),tname) ||
1022 ((tapeLabel.structVersion >= TAPE_VERSION_3) &&
1023 (tapeLabel.dumpid != tapeID)) )
1025 char expectedName[BU_MAXTAPELEN+32], gotName[BU_MAXTAPELEN+32];
1027 TAPENAME(expectedName, tname, tapeID);
1028 LABELNAME(gotName, &tapeLabel);
1030 TapeLog(0, taskId, 0, 0,
1031 "Tape label expected %s, label seen %s\n",
1032 expectedName, gotName);
1039 unmountTape(taskId, tapeInfoPtr);
1046 afs_int32 xbsaRestoreVolumeData(call, rparamsPtr)
1047 register struct rx_call *call;
1048 struct restoreParams *rparamsPtr;
1052 afs_int32 curChunk, rc;
1053 afs_uint32 totalWritten;
1054 afs_int32 headBytes, tailBytes, w;
1056 struct volumeHeader volTrailer;
1059 struct dumpNode *nodePtr;
1060 struct tc_restoreDesc *Restore;
1061 afs_int32 bytesRead, tbuffersize, endData=0;
1062 char *buffer = (char *)bufferBlock, tbuffer[256];
1064 nodePtr = rparamsPtr->nodePtr;
1065 Restore = nodePtr->restores;
1066 taskId = nodePtr->taskID;
1068 /* Read the volume fragment one block at a time until
1069 * find a volume trailer
1071 curChunk = BIGCHUNK+1;
1076 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead, &endData);
1077 if (restoretofile && (bytesRead > 0)) {
1078 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1080 if (rc != XBSA_SUCCESS) {
1081 ErrorLog(0, taskId, rc, 0, "Unable to read volume data from the server\n");
1085 /* Periodically update status structure and check if should abort */
1086 curChunk += bytesRead;
1087 if (curChunk > BIGCHUNK) {
1090 nodePtr->statusNodePtr->nKBytes = totalWritten/1024;
1093 if ( checkAbortByTaskId(taskId) )
1094 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1097 if (!endData && (bytesRead > 0)) {
1098 /* Fill tbuffer up with data from end of buffer and write
1099 * the remainder of buffer out.
1101 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1102 /* Write out contents of tbuffer */
1104 w = rx_Write(call, tbuffer, tbuffersize);
1105 if (w != tbuffersize) {
1106 ErrorLog (0, taskId, -1, 0, "Error in RX write: Wrote %d bytes\n", w);
1111 /* fill tbuffer with end of buffer */
1112 bytesRead -= sizeof(tbuffer);
1113 bcopy(buffer+bytesRead, tbuffer, sizeof(tbuffer));
1114 tbuffersize = sizeof(tbuffer);
1115 /* Write out whatever is left over in buffer */
1117 w = rx_Write(call, buffer, bytesRead);
1118 if (w != bytesRead) {
1119 ErrorLog (0, taskId, -1, 0, "Error in RX data write: Wrote %d bytes\n", w);
1126 else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1127 /* Copy all of buffer into tbuffer (it will fit) */
1128 bcopy(buffer, tbuffer+tbuffersize, bytesRead);
1129 tbuffersize += bytesRead;
1133 /* We need to write some of tbuffer out and fill it with buffer */
1134 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1135 w = rx_Write(call, tbuffer, towrite);
1137 ErrorLog (0, taskId, -1, 0, "Error in RX write: Wrote %d bytes\n", w);
1143 /* Move the data in tbuffer up */
1144 bcopy(tbuffer+towrite, tbuffer, tbuffersize);
1146 /* Now copy buffer in */
1147 bcopy(buffer, tbuffer+tbuffersize, bytesRead);
1148 tbuffersize += bytesRead;
1154 /* Pull the volume trailer from the last two buffers */
1155 found = FindVolTrailer2(tbuffer, tbuffersize, &headBytes,
1156 buffer, bytesRead, &tailBytes,
1160 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1161 ERROR_EXIT(TC_MISSINGTRAILER);
1164 /* Now rx_write the data in the last two blocks */
1166 w = rx_Write(call, tbuffer, headBytes);
1167 if (w != headBytes) {
1168 ErrorLog (0, taskId, -1, 0, "Error in RX trail1 write: Wrote %d bytes\n", w);
1174 w = rx_Write(call, buffer, tailBytes);
1175 if (w != tailBytes) {
1176 ErrorLog (0, taskId, -1, 0, "Error in RX trail2 write: Wrote %d bytes\n", w);
1188 * sends the contents of volume dump to Rx Stream associated
1192 afs_int32 restoreVolumeData (call, rparamsPtr)
1193 register struct rx_call *call;
1194 struct restoreParams *rparamsPtr;
1197 afs_uint32 totalWritten = 0;
1199 afs_int32 code, tcode;
1200 afs_int32 headBytes, tailBytes, w;
1202 afs_int32 nbytes; /* # bytes data in last tape block read */
1203 struct volumeHeader tapeVolTrailer;
1206 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1207 struct tc_restoreDesc *Restore;
1208 struct dumpNode *nodePtr;
1209 struct butm_tapeInfo *tapeInfoPtr;
1211 afs_int32 origVolID;
1213 nodePtr = rparamsPtr->nodePtr;
1214 taskId = nodePtr->taskID;
1215 Restore = nodePtr->restores;
1216 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1217 origVolName = Restore[rparamsPtr->frag].oldName;
1218 origVolID = Restore[rparamsPtr->frag].origVid;
1220 /* Read the volume one fragment at a time */
1221 while (rparamsPtr->frag < nodePtr->arraySize) {
1223 curChunk = BIGCHUNK+1; /* Check if should abort */
1225 /* Read the volume fragment one block at a time until
1226 * find a volume trailer
1232 while (moretoread) {
1233 /* Fill the circular buffer with tape blocks
1234 * Search for volume trailer in the process.
1238 code = butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1239 BUTM_BLKSIZE, &nbytes);
1241 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1242 "Can't read FileData on tape %s\n",
1243 rparamsPtr->mntTapeName);
1246 curChunk += BUTM_BLKSIZE;
1248 /* Periodically update status structure and check if should abort */
1249 if (curChunk > BIGCHUNK) {
1253 nodePtr->statusNodePtr->nKBytes = totalWritten/1024;
1256 if ( checkAbortByTaskId(taskId) )
1257 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1260 /* step to next block in buffer */
1262 buf = ((buf+1) == tapeblocks) ? 0 : (buf+1);
1264 /* If this is the end of the volume, the exit the loop */
1265 if ( (nbytes != BUTM_BLKSIZE) ||
1266 (FindVolTrailer(bufferBlock[pbuf].data,nbytes,&tailBytes, &tapeVolTrailer)) )
1269 } while (moretoread && (buf != endRbuf));
1271 /* Write the buffer upto (but not including) the last read block
1272 * If volume is completely read, then leave the last two blocks.
1274 lastbuf = endWbuf = pbuf;
1275 if (!moretoread && (endWbuf != startWbuf))
1276 endWbuf = (endWbuf==0) ? (tapeblocks-1) : (endWbuf-1);
1278 for (buf = startWbuf; buf != endWbuf; buf = (((buf+1)==tapeblocks)?0:(buf+1))){
1279 w = rx_Write(call,bufferBlock[buf].data,BUTM_BLKSIZE);
1280 if (w != BUTM_BLKSIZE) {
1281 ErrorLog (0, taskId, -1, 0, "Error in RX write\n");
1284 totalWritten += BUTM_BLKSIZE;
1287 /* Setup pointers to refill buffer */
1288 startRbuf = ((lastbuf+1) == tapeblocks) ? 0 : (lastbuf+1);
1290 startWbuf = endWbuf;
1293 /* lastbuf is last block read and it has nbytes of data
1294 * startWbuf is the 2nd to last block read
1295 * Seach for the volume trailer in these two blocks.
1297 if (lastbuf == startWbuf)
1298 found = FindVolTrailer2((char *)0 , 0 , &headBytes,
1299 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1302 found = FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE, &headBytes,
1303 bufferBlock[lastbuf].data , nbytes , &tailBytes,
1306 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1307 "Missing volume trailer on tape %s\n", rparamsPtr->mntTapeName);
1308 ERROR_EXIT(TC_MISSINGTRAILER);
1311 /* Now rx_write the data in the last two blocks */
1313 w = rx_Write(call,bufferBlock[startWbuf].data,headBytes);
1314 if (w != headBytes) {
1315 ErrorLog (0, taskId, -1, 0, "Error in RX write\n");
1318 totalWritten += headBytes;
1321 w = rx_Write(call,bufferBlock[lastbuf].data,tailBytes);
1322 if (w != tailBytes) {
1323 ErrorLog (0, taskId, -1, 0, "Error in RX write\n");
1326 totalWritten += tailBytes;
1329 /* Exit the loop if the volume is not continued on next tape */
1330 if ( !tapeVolTrailer.contd )
1331 break; /* We've read the entire volume */
1333 /* Volume is continued on next tape.
1334 * Step to the next volume fragment and prompt for its tape.
1335 * When a volume has multiple frags, those frags are on different
1336 * tapes. So we know that we need to prompt for a tape.
1339 if (rparamsPtr->frag >= nodePtr->arraySize)
1342 unmountTape(taskId, tapeInfoPtr);
1343 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1344 rparamsPtr->tapeID = (Restore[rparamsPtr->frag].initialDumpId ?
1345 Restore[rparamsPtr->frag].initialDumpId :
1346 Restore[rparamsPtr->frag].dbDumpId);
1347 code = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1348 rparamsPtr->tapeID, 1);
1349 if (code) ERROR_EXIT(code);
1351 /* Position to the frag and read the volume header */
1352 code = GetVolumeHead(taskId, tapeInfoPtr,
1353 Restore[rparamsPtr->frag].position,
1354 origVolName, origVolID);
1356 ErrorLog(0, taskId, code, 0, "Can't find volume %s (%u) on tape %s\n",
1357 origVolName, origVolID,
1358 rparamsPtr->mntTapeName);
1359 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1368 * Find all the volumes on a specific tape and mark them to skip.
1370 SkipTape(Restore, size, index, tapename, tapeid, taskid)
1371 struct tc_restoreDesc *Restore;
1372 afs_int32 size, index, tapeid, taskid;
1377 for (i=index; i<size; i++) {
1378 if (Restore[i].flags & RDFLAG_SKIP) continue;
1379 tid = (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].dbDumpId);
1380 if ( (strcmp(Restore[i].tapeName,tapename) == 0) && (tid == tapeid) ) {
1381 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1387 * Find all the entries for a volume and mark them to skip.
1389 SkipVolume(Restore, size, index, volid, taskid)
1390 struct tc_restoreDesc *Restore;
1391 afs_int32 size, index, volid, taskid;
1396 for (i=index; i<size; i++) {
1397 if (Restore[i].flags & RDFLAG_SKIP) continue;
1398 if (Restore[i].origVid == volid) {
1399 Restore[i].flags |= RDFLAG_SKIP;
1401 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1402 ((Restore[i].dumpLevel == 0)?"":"remainder of "),
1403 Restore[i].oldName, volid);
1410 xbsaRestoreVolume(taskId, restoreInfo, rparamsPtr)
1412 struct tc_restoreDesc *restoreInfo;
1413 struct restoreParams *rparamsPtr;
1415 afs_int32 code=0, rc;
1417 afs_int32 newServer, newPart, newVolId;
1419 int restoreflags, havetrans=0, startread=0;
1420 afs_int32 bytesRead, endData=0;
1422 struct budb_dumpEntry dumpEntry;
1423 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1424 struct volumeHeader volHeader, hostVolHeader;
1426 if (restoretofile) {
1427 restoretofilefd = fopen(restoretofile, "w+");
1430 dumpID = restoreInfo->dbDumpId;
1432 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1434 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n", dumpID);
1438 /* ADSM servers restore ADSM and BUTA dumps */
1439 if ( (xbsaType == XBSA_SERVER_TYPE_ADSM) &&
1440 !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA)) ) {
1441 ELog(taskId, "The dump requested by this restore operation for the "
1442 "volumeset is incompatible with this instance of butc\n");
1443 /* Skip the entire dump (one dump per tape) */
1444 ERROR_EXIT(TC_SKIPTAPE);
1447 /* make sure we are connected to the correct server. */
1448 if ( (strlen((char *)dumpEntry.tapes.tapeServer) != 0) &&
1449 (strcmp((char *)dumpEntry.tapes.tapeServer,butxInfo.serverName) != 0) ) {
1450 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA)) && !forcemultiple) {
1451 TLog(taskId, "Dump %d is on server %s but butc is connected "
1452 "to server %s (attempting to restore)\n",
1453 dumpID, (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1455 TLog(taskId, "Dump %d is on server %s but butc is connected "
1456 "to server %s (switching servers)\n",
1457 dumpID, (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1459 rc = InitToServer(taskId, &butxInfo, (char *)dumpEntry.tapes.tapeServer);
1460 if (rc != XBSA_SUCCESS) ERROR_EXIT(TC_SKIPTAPE);
1464 /* Start a transaction and query the server for the correct fileset dump */
1465 rc = xbsa_BeginTrans(&butxInfo);
1466 if (rc != XBSA_SUCCESS) {
1467 ELog(taskId, "Unable to create a new transaction\n");
1468 ERROR_EXIT(TC_SKIPTAPE);
1472 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1473 sprintf(dumpIdStr, "/%d", dumpID);
1474 strcpy(volumeNameStr, "/");
1475 strcat(volumeNameStr, restoreInfo->oldName);
1476 } else { /* new butc names */
1477 extern char *butcdumpIdStr;
1478 strcpy(dumpIdStr, butcdumpIdStr);
1479 sprintf(volumeNameStr, "/%d", dumpID);
1480 strcat(volumeNameStr, "/");
1481 strcat(volumeNameStr, restoreInfo->oldName);
1484 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1485 if (rc != XBSA_SUCCESS) {
1486 ELog(taskId, "Unable to locate object (%s) of dump (%s) on the server\n",
1487 volumeNameStr, dumpIdStr);
1491 rc = xbsa_EndTrans(&butxInfo);
1493 if (rc != XBSA_SUCCESS) {
1494 ELog(taskId, "Unable to terminate the current transaction\n");
1498 if ( checkAbortByTaskId(taskId) )
1499 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1501 /* Now start a transaction on the volume to restore and read the
1502 * volumeheader. We do this before starting a transaction on
1503 * volserver to restore the volume because the XBSA server may take
1504 * a while to mount and seek to the volume causing the volserver to
1507 rc = xbsa_BeginTrans(&butxInfo);
1508 if (rc != XBSA_SUCCESS) {
1509 ELog(taskId, "Unable to create a new transaction\n");
1510 ERROR_EXIT(TC_SKIPTAPE);
1514 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1515 sizeof(volHeader), &bytesRead, &endData);
1516 if (restoretofile && (bytesRead > 0)) {
1517 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1519 if (rc != XBSA_SUCCESS) {
1520 ELog(taskId, "Unable to begin reading of the volume from the server\n");
1525 if ((bytesRead != sizeof(volHeader)) || endData) {
1526 ELog(taskId,"The size of data read (%d) does not equal the size of data requested (%d)\n",
1527 bytesRead, sizeof(volHeader));
1528 ERROR_EXIT(TC_BADVOLHEADER);
1531 /* convert and check the volume header */
1532 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1534 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1538 if ( (strcmp(hostVolHeader.volumeName,restoreInfo->oldName) != 0) ||
1539 (restoreInfo->origVid && (hostVolHeader.volumeID != restoreInfo->origVid)) ||
1540 (hostVolHeader.magic != TC_VOLBEGINMAGIC) )
1541 ERROR_EXIT(TC_BADVOLHEADER);
1543 /* Set up prior restoring volume data */
1544 newVolName = restoreInfo->newName;
1545 newVolId = restoreInfo->vid;
1546 newServer = restoreInfo->hostAddr;
1547 newPart = restoreInfo->partition;
1549 if ( (restoreInfo->dumpLevel == 0) || (restoreInfo->flags & RDFLAG_FIRSTDUMP) )
1550 restoreflags |= RV_FULLRST;
1551 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1552 restoreflags |= RV_OFFLINE;
1554 if ( checkAbortByTaskId(taskId) )
1555 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1557 /* Start the restore of the volume data. This is the code we want to return */
1558 code = UV_RestoreVolume(htonl(newServer), newPart,
1559 newVolId, newVolName,
1561 xbsaRestoreVolumeData,
1562 (char *)rparamsPtr);
1565 rc = xbsa_ReadObjectEnd(&butxInfo);
1566 if (rc != XBSA_SUCCESS) {
1567 ELog(taskId, "Unable to terminate reading of the volume from the server\n");
1573 rc = xbsa_EndTrans(&butxInfo);
1574 if (rc != XBSA_SUCCESS) {
1575 ELog(taskId, "Unable to terminate the current transaction\n");
1576 if (!code) code = rc;
1580 if (restoretofile && restoretofilefd) {
1581 fclose(restoretofilefd);
1587 restoreVolume(taskId, restoreInfo, rparamsPtr)
1589 struct tc_restoreDesc *restoreInfo;
1590 struct restoreParams *rparamsPtr;
1592 afs_int32 code=0, rc;
1593 afs_int32 newServer, newPart, newVolId;
1597 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1598 struct budb_dumpEntry dumpEntry;
1600 /* Check if we need a tape and prompt for one if so */
1601 tapeID = (restoreInfo->initialDumpId ? restoreInfo->initialDumpId : restoreInfo->dbDumpId);
1602 if ( (rparamsPtr->frag == 0) ||
1603 (strcmp(restoreInfo->tapeName,rparamsPtr->mntTapeName) != 0) ||
1604 (tapeID != rparamsPtr->tapeID) ) {
1605 /* Unmount the previous tape */
1606 unmountTape(taskId, tapeInfoPtr);
1608 /* Remember this new tape */
1609 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1610 rparamsPtr->tapeID = tapeID;
1612 /* Mount a new tape */
1613 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1614 rparamsPtr->tapeID, ((rparamsPtr->frag==0)?autoQuery:1));
1615 if (rc) ERROR_EXIT(rc);
1618 /* Seek to the correct spot and read the header information */
1619 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1620 restoreInfo->oldName, restoreInfo->origVid);
1621 if (rc) ERROR_EXIT(rc);
1623 /* Set up prior restoring volume data */
1624 newVolName = restoreInfo->newName;
1625 newVolId = restoreInfo->vid;
1626 newServer = restoreInfo->hostAddr;
1627 newPart = restoreInfo->partition;
1629 if ( (restoreInfo->dumpLevel == 0) || (restoreInfo->flags & RDFLAG_FIRSTDUMP) )
1630 restoreflags |= RV_FULLRST;
1631 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1632 restoreflags |= RV_OFFLINE;
1634 if ( checkAbortByTaskId(taskId) )
1635 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1637 /* Start the restore of the volume data. This is the code we
1640 code = UV_RestoreVolume(htonl(newServer), newPart,
1641 newVolId, newVolName,
1644 (char *)rparamsPtr);
1646 /* Read the FileEnd marker for the volume and step to next FM */
1647 rc = butm_ReadFileEnd(tapeInfoPtr);
1649 ErrorLog(0, taskId, rc, tapeInfoPtr->error, "Can't read EOF on tape\n");
1657 * created as a LWP by the server stub, <newNode> is a pointer to all
1658 * the parameters Restorer needs
1661 struct dumpNode *newNode;
1663 afs_int32 code = 0, tcode, rc;
1667 struct butm_tapeInfo tapeInfo;
1668 struct tc_restoreDesc *Restore;
1669 struct tc_restoreDesc *RestoreDesc;
1670 struct restoreParams rparams;
1672 afs_int32 allocbufferSize;
1673 time_t startTime, endTime;
1674 afs_int32 goodrestore=0;
1676 taskId = newNode->taskID;
1677 setStatus(taskId, DRIVE_WAIT);
1678 EnterDeviceQueue(deviceLatch);
1679 clearStatus(taskId, DRIVE_WAIT);
1682 TLog (taskId, "Restore\n");
1684 bzero(&tapeInfo, sizeof(tapeInfo));
1686 tapeInfo.structVersion = BUTM_MAJORVERSION;
1687 tcode = butm_file_Instantiate (&tapeInfo, &globalTapeConfig);
1689 ErrorLog(0, taskId, tcode, tapeInfo.error,
1690 "Can't initialize the tape module\n");
1695 if ( checkAbortByTaskId(taskId) ) ERROR_EXIT(TC_ABORTEDBYREQUEST);
1697 bzero(&rparams, sizeof(rparams));
1698 rparams.nodePtr = newNode;
1699 rparams.tapeInfoPtr = &tapeInfo;
1700 Restore = newNode->restores; /* Array of vol fragments to restore */
1702 /* Allocate memory in which to restore the volumes data into */
1704 allocbufferSize = dataSize = BufferSize;
1706 /* Must have at least two tape blocks */
1707 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1708 if (tapeblocks < 2) tapeblocks = 2;
1709 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1711 bufferBlock = (struct TapeBlock *)0;
1712 bufferBlock = (struct TapeBlock *) malloc(allocbufferSize);
1713 if (!bufferBlock) ERROR_EXIT(TC_NOMEMORY);
1714 bzero(bufferBlock, allocbufferSize);
1716 startTime = time(0);
1717 for (rparams.frag=0; (rparams.frag < newNode->arraySize); rparams.frag++) {
1718 RestoreDesc = &Restore[rparams.frag];
1720 /* Skip the volume if it was requested to */
1721 if (RestoreDesc->flags & RDFLAG_SKIP) {
1722 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1723 /* If the volume was restored, should bring it online */
1728 newVolName = RestoreDesc->newName;
1730 /* Make sure the server to restore to is good */
1731 if (!RestoreDesc->hostAddr) {
1732 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n", newVolName);
1733 ERROR_EXIT(TC_INTERNALERROR);
1736 if ( checkAbortByTaskId(taskId) )
1737 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1739 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1741 strncpy(newNode->statusNodePtr->volumeName, newVolName, BU_MAXNAMELEN);
1744 /* restoreVolume function takes care of all the related fragments
1745 * spanning various tapes. On return the complete volume has been
1749 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1751 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1754 if (tcode == TC_ABORTEDBYREQUEST) {
1756 } else if (tcode == TC_SKIPTAPE) {
1758 tapeID = (RestoreDesc->initialDumpId ? RestoreDesc->initialDumpId :
1759 RestoreDesc->dbDumpId);
1760 SkipTape(Restore, newNode->arraySize, rparams.frag,
1761 RestoreDesc->tapeName, tapeID, taskId);
1763 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n", newVolName);
1764 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1765 RestoreDesc->origVid, taskId);
1777 unmountTape(taskId, &tapeInfo);
1780 rc = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1784 if (bufferBlock) free(bufferBlock);
1786 if (code == TC_ABORTEDBYREQUEST)
1788 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1789 clearStatus(taskId, ABORT_REQUEST);
1790 setStatus (taskId, ABORT_DONE);
1794 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1795 setStatus(taskId, TASK_ERROR);
1799 TLog(taskId, "Restore: Finished\n");
1802 if (centralLogIO && startTime) {
1804 afs_int32 hrs, min, sec, tmp;
1806 struct tm tmstart, tmend;
1808 localtime_r(&startTime, &tmstart);
1809 localtime_r(&endTime, &tmend);
1810 timediff = (int)endTime - (int)startTime;
1811 hrs = timediff / 3600;
1812 tmp = timediff % 3600;
1816 sprintf(line, "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1817 "%02d/%02d/%04d %02d:%02d:%02d "
1819 "%d of %d volume%s restored\n",
1820 taskId, tmstart.tm_mon+1, tmstart.tm_mday, tmstart.tm_year+1900,
1821 tmstart.tm_hour, tmstart.tm_min, tmstart.tm_sec,
1822 tmend.tm_mon+1, tmend.tm_mday, tmend.tm_year+1900,
1823 tmend.tm_hour, tmend.tm_min, tmend.tm_sec,
1825 goodrestore, newNode->arraySize, ((newNode->arraySize>1)?"s":""));
1827 fwrite(line, strlen(line), 1, centralLogIO);
1828 fflush(centralLogIO);
1831 setStatus(taskId, TASK_DONE);
1834 LeaveDeviceQueue(deviceLatch);
1838 /* this is just scaffolding, creates new tape label with name <tapeName> */
1840 GetNewLabel(tapeInfoPtr, pName, AFSName, tapeLabel)
1841 struct butm_tapeInfo *tapeInfoPtr;
1842 char *pName, *AFSName;
1843 struct butm_tapeLabel *tapeLabel;
1846 struct timezone tzp;
1849 bzero(tapeLabel,sizeof(struct butm_tapeLabel));
1852 butm_GetSize(tapeInfoPtr, &size);
1853 if ( !size ) size = globalTapeConfig.capacity;
1855 size = 0; /* no tape size */
1857 gettimeofday(&tp,&tzp);
1859 tapeLabel->structVersion = CUR_TAPE_VERSION;
1860 tapeLabel->creationTime = tp.tv_sec;
1861 tapeLabel->size = size;
1862 tapeLabel->expirationDate = 0; /* 1970 sometime */
1863 tapeLabel->dumpPath[0] = 0; /* no path name */
1864 tapeLabel->useCount = 0;
1865 strcpy(tapeLabel->AFSName, AFSName);
1866 strcpy(tapeLabel->pName, pName);
1867 strcpy(tapeLabel->cell, globalCellName);
1868 strcpy(tapeLabel->comment, "AFS Backup Software");
1869 strcpy(tapeLabel->creator.name, "AFS 3.6");
1870 strcpy(tapeLabel->creator.instance, "");
1871 strcpy(tapeLabel->creator.cell, globalCellName);
1874 /* extracts trailer out of buffer, nbytes is set to total data in buffer - trailer size */
1876 ExtractTrailer(buffer, size, nbytes, volTrailerPtr)
1880 struct volumeHeader *volTrailerPtr;
1884 struct volumeHeader tempTrailer;
1887 startPos <= (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1890 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1893 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1896 if (nbytes) *nbytes = startPos;
1897 return 1; /* saw the trailer */
1901 if (nbytes) *nbytes = size/2;
1902 return 0; /* did not see the trailer */
1906 FindVolTrailer(buffer, size, dSize, volTrailerPtr)
1909 struct volumeHeader *volTrailerPtr;
1910 afs_int32 *dSize; /* dataSize */
1912 afs_int32 offset, s;
1917 if (!buffer) return 0;
1919 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1920 if (s > size) s = size;
1922 found = ExtractTrailer((buffer+size-s),s,&offset,volTrailerPtr);
1923 if (found) *dSize -= (s - offset);
1928 FindVolTrailer2(buffera, sizea, dataSizea, bufferb, sizeb, dataSizeb, volTrailerPtr)
1931 afs_int32 *dataSizea;
1934 afs_int32 *dataSizeb;
1935 struct volumeHeader *volTrailerPtr;
1937 afs_int32 offset, s;
1938 afs_int32 headB, tailB;
1941 if ( !buffera ) sizea = 0;
1942 if ( !bufferb ) sizeb = 0;
1946 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1948 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
1951 headB = (s - sizeb); /*(s > sizeb)*/
1952 if (headB > sizea) {
1958 bzero(tapeVolumeHT, sizeof(tapeVolumeHT));
1959 if (headB) bcopy (buffera + sizea - headB, tapeVolumeHT , headB);
1960 if (tailB) bcopy (bufferb , tapeVolumeHT + headB, tailB);
1961 if (ExtractTrailer (tapeVolumeHT, s, &offset, volTrailerPtr)) {
1963 if (offset > headB) {
1964 /* *dataSizea remains unchanged */
1965 *dataSizeb = offset - headB;
1967 *dataSizea -= (headB - offset); /*(headB >= offset)*/
1975 /* Returns true or false depending on whether the tape is expired or not */
1977 Date ExpirationDate (dumpid)
1981 Date expiration = 0;
1982 struct budb_dumpEntry dumpEntry;
1983 struct budb_tapeEntry tapeEntry;
1984 struct budb_volumeEntry volEntry;
1989 * Get the expiration date from DB if its there. The expiration of any tape
1990 * will be the most future expiration of any dump in the set. Can't use
1991 * bcdb_FindTape because dumpid here pertains to the initial dump id.
1993 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
1994 if (!code) expiration = tapeEntry.expires;
2000 tapeExpired (tapeLabelPtr)
2001 struct butm_tapeLabel *tapeLabelPtr;
2005 struct timezone tzp;
2007 expiration = ExpirationDate(tapeLabelPtr->dumpid);
2008 if (!expiration) expiration = tapeLabelPtr->expirationDate;
2010 gettimeofday (&tp, &tzp);
2011 return ((expiration < tp.tv_sec) ? 1 : 0);
2015 * given the label on the tape, delete any old information from the
2018 * Deletes all entries that match the volset.dumpnode
2019 * and the dump path.
2022 updateTapeLabel(labelIfPtr, tapeInfoPtr, newLabelPtr)
2023 struct labelTapeIf *labelIfPtr;
2024 struct butm_tapeInfo *tapeInfoPtr;
2025 struct butm_tapeLabel *newLabelPtr;
2027 struct butm_tapeLabel oldLabel;
2028 afs_int32 i, code = 0;
2030 int tapeIsLabeled = 0;
2031 int interactiveFlag;
2032 extern afs_int32 BUDB_DeleteDump();
2035 interactiveFlag = autoQuery;
2036 taskId = labelIfPtr->taskId;
2040 if ( interactiveFlag )
2042 code = PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2043 labelIfPtr->taskId, tapecount);
2044 if (code) ERROR_EXIT(code);
2046 interactiveFlag = 1;
2049 /* mount the tape */
2050 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2053 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2057 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2062 if ( (strcmp(newLabelPtr->AFSName,"") != 0) &&
2063 (strcmp(oldLabel.pName,"") != 0) ) {
2064 /* We are setting the AFS name, yet tape
2065 * has a permanent name (not allowed).
2067 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2072 if ( !tapeExpired(&oldLabel) )
2076 TLog(taskId, "This tape has not expired\n");
2079 if ( Ask("This tape has not expired - proceed") == 0 ) goto newtape;
2082 /* Keep the permanent name */
2083 if (strcmp(newLabelPtr->pName,"") == 0)
2085 strcpy(newLabelPtr->pName, oldLabel.pName);
2087 else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0)
2089 strcpy(newLabelPtr->pName, "");
2093 /* extract useful information from the old label */
2094 if ( tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3 )
2096 newLabelPtr->dumpid = 0;
2097 newLabelPtr->useCount = oldLabel.useCount + 1;
2100 /* now write the new label */
2101 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2104 ErrorLog(0, taskId, code, tapeInfoPtr->error, "Can't label tape\n");
2111 unmountTape(taskId, tapeInfoPtr);
2114 /* delete obsolete information from the database */
2115 if ( tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3 )
2117 /* delete based on dump id */
2118 if ( oldLabel.dumpid )
2120 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2121 if ( i && (i != BUDB_NOENT) )
2122 ErrorLog(0, taskId, i, 0,
2123 "Warning: Can't delete old dump %u from database\n", oldLabel.dumpid);
2128 unmountTape(taskId, tapeInfoPtr);
2133 * LWP created by the server stub. Labels the tape with name and size
2134 * specified by <label>
2137 Labeller (labelIfPtr)
2138 struct labelTapeIf *labelIfPtr;
2140 struct tc_tapeLabel *label = &labelIfPtr->label;
2142 struct butm_tapeLabel newTapeLabel;
2143 struct butm_tapeInfo tapeInfo;
2147 taskId = labelIfPtr->taskId;
2148 setStatus(taskId, DRIVE_WAIT);
2149 EnterDeviceQueue(deviceLatch);
2150 clearStatus(taskId, DRIVE_WAIT);
2153 TLog (taskId, "Labeltape\n");
2155 bzero(&tapeInfo, sizeof(tapeInfo));
2156 tapeInfo.structVersion = BUTM_MAJORVERSION;
2157 code = butm_file_Instantiate (&tapeInfo, &globalTapeConfig);
2160 ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize the tape module\n");
2164 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2165 if (label->size) newTapeLabel.size = label->size;
2166 else newTapeLabel.size = globalTapeConfig.capacity;
2168 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2169 if (code) ERROR_EXIT(code);
2172 if (code == TC_ABORTEDBYREQUEST)
2174 ErrorLog (0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2175 clearStatus(taskId, ABORT_REQUEST);
2176 setStatus (taskId, ABORT_DONE);
2180 ErrorLog (0, taskId, code, 0, "Labeltape: Finished with errors\n");
2181 setStatus(taskId, TASK_ERROR);
2185 TLog (taskId, "Labelled tape %s size %u Kbytes\n",
2186 TNAME(&newTapeLabel), newTapeLabel.size);
2188 setStatus(labelIfPtr->taskId, TASK_DONE);
2191 LeaveDeviceQueue(deviceLatch);
2196 * print out the tape label.
2199 PrintTapeLabel(labelptr)
2200 struct butm_tapeLabel *labelptr;
2202 char tapeName[BU_MAXTAPELEN+32];
2204 printf("Tape label\n");
2205 printf("----------\n");
2206 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2207 printf("permanent tape name = %s\n", tapeName);
2208 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2209 printf("AFS tape name = %s\n", tapeName);
2210 printf("creationTime = %s", ctime(&labelptr->creationTime));
2211 if ( labelptr->expirationDate )
2212 printf("expirationDate = %s", cTIME(&labelptr->expirationDate));
2213 printf("cell = %s\n", labelptr->cell);
2214 printf("size = %u Kbytes\n", labelptr->size);
2215 printf("dump path = %s\n", labelptr->dumpPath);
2217 if ( labelptr->structVersion >= TAPE_VERSION_3 )
2219 printf("dump id = %u\n", labelptr->dumpid);
2220 printf("useCount = %d\n", labelptr->useCount);
2222 printf("-- End of tape label --\n\n");
2226 * Read the label from a tape.
2227 * Currently prints out a "detailed" summary of the label but passes
2228 * back only selected fields.
2232 struct tc_tapeLabel *label;
2234 struct butm_tapeLabel newTapeLabel;
2235 struct butm_tapeInfo tapeInfo;
2239 int interactiveFlag;
2242 EnterDeviceQueue(deviceLatch);
2243 taskId = allocTaskId(); /* reqd for lower level rtns */
2246 TLog (taskId, "Readlabel\n");
2248 bzero(&tapeInfo,sizeof(tapeInfo));
2249 tapeInfo.structVersion = BUTM_MAJORVERSION;
2250 code = butm_file_Instantiate (&tapeInfo, &globalTapeConfig);
2253 ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize the tape module\n");
2256 bzero(&newTapeLabel,sizeof(newTapeLabel));
2258 interactiveFlag = autoQuery;
2262 if ( interactiveFlag )
2264 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2265 if (code) ERROR_EXIT(code);
2267 interactiveFlag = 1;
2270 code = butm_Mount(&tapeInfo, "");
2273 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2279 unmountTape(taskId, &tapeInfo);
2282 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2285 if (code == BUTM_NOLABEL)
2287 printf("Tape is unlabelled\n");
2290 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2294 /* copy the fields to be passed to the caller */
2295 label->size = newTapeLabel.size;
2296 label->tapeId = newTapeLabel.dumpid;
2297 strcpy(label->afsname, newTapeLabel.AFSName);
2298 strcpy(label->pname, newTapeLabel.pName);
2301 expir = ExpirationDate(newTapeLabel.dumpid);
2302 if (expir) newTapeLabel.expirationDate = expir;
2304 PrintTapeLabel(&newTapeLabel);
2307 unmountTape(taskId, &tapeInfo);
2309 if (code == TC_ABORTEDBYREQUEST)
2310 ErrorLog (0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2311 else if (code && (code != BUTM_NOLABEL))
2312 ErrorLog (0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2314 TLog (taskId, "ReadLabel: Finished\n");
2316 LeaveDeviceQueue(deviceLatch);
2320 /* Function to read volume header and trailer structure from tape, taking
2321 into consideration, different word alignment rules.
2324 readVolumeHeader (buffer, bufloc, header)
2325 /*in*/ char *buffer; /* buffer to read header from */
2326 /*in*/ afs_int32 bufloc; /* header's location in buffer */
2327 /*out*/ struct volumeHeader *header; /* header structure */
2330 struct volumeHeader vhptr, *tempvhptr;
2331 afs_int32 firstSplice = (afs_int32)&vhptr.pad - (afs_int32)&vhptr;
2332 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2333 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2335 /* Four cases are to be handled
2337 Volume Header (byte alignment)
2338 -----------------------
2345 -----------------------
2347 Case 2 and Case 3 are identical cases and handled the same way.
2348 Case 1 and Case 4 are separate cases. In one case the pad needs
2349 to be removed and in the other, it needs to be spliced in. The
2350 four cases are handled as follows
2352 tempvhptr = (struct volumeHeader *)(buffer+bufloc);
2353 if ( (strncmp(tempvhptr->preamble, "H++NAME#",8) == 0) &&
2354 (strncmp(tempvhptr->postamble, "T--NAME#",8) == 0) )
2356 /* Handle Cases 2 & 3 */
2357 bcopy (buffer+bufloc, &vhptr, sizeof(struct volumeHeader));
2358 HEADER_CHECKS(vhptr, header);
2361 bzero (&vhptr, sizeof(struct volumeHeader));
2362 bcopy (buffer+bufloc, &vhptr, firstSplice);
2363 bzero (&vhptr.pad, padLen);
2364 bcopy (buffer+bufloc+firstSplice, &vhptr.volumeID, nextSplice);
2365 HEADER_CHECKS(vhptr, header);
2368 bzero (&vhptr, sizeof(struct volumeHeader));
2369 bcopy (buffer+bufloc, &vhptr, firstSplice);
2370 bcopy (buffer+bufloc+firstSplice+padLen, &vhptr+firstSplice, nextSplice);
2371 HEADER_CHECKS(vhptr, header);
2374 return (TC_BADVOLHEADER);