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>
16 #include <sys/types.h>
23 #include <netinet/in.h>
27 #include <afs/procmgmt.h>
33 #include <afs/tcdata.h>
34 #include <afs/bubasics.h> /* PA */
35 #include <afs/budb_client.h>
36 #include <afs/volser.h>
37 #include <afs/com_err.h>
38 #include "error_macros.h"
39 #include <afs/afsutil.h>
41 #include "butc_xbsa.h"
43 /* GLOBAL CONFIGURATION PARAMETERS */
44 extern int queryoperator;
45 extern int tapemounted;
46 extern char *opencallout;
47 extern char *closecallout;
49 extern char *extractDumpName();
50 extern int BufferSize; /* Size in B stored for header info */
51 FILE *restoretofilefd;
53 extern char *restoretofile;
54 extern int forcemultiple;
57 /* XBSA Global Parameters */
60 struct butx_transactionInfo butxInfo;
63 static struct TapeBlock { /* A 16KB tapeblock */
64 char mark[BUTM_HDRSIZE]; /* Header info */
65 char data[BUTM_BLKSIZE]; /* data */
68 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
69 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
72 * Need to re-write to:
73 * 1) non-interactive tape handling (optional)
74 * 2) compute tape and volume sizes for the database
75 * 3) compute and use tape id's for tape tracking (put on tape label)
76 * 4) status management
79 /* All the relevant info shared between Restorer and restoreVolume */
80 struct restoreParams {
81 struct dumpNode *nodePtr;
83 char mntTapeName[BU_MAXTAPELEN];
85 struct butm_tapeInfo *tapeInfoPtr;
88 /* Abort checks are done after each BIGCHUNK of data transfer */
89 #define BIGCHUNK 102400
91 #define HEADER_CHECKS(vhptr, header) \
93 afs_int32 magic, versionflags; \
95 versionflags = ntohl(vhptr.versionflags); \
96 if ( versionflags == TAPE_VERSION_0 || \
97 versionflags == TAPE_VERSION_1 || \
98 versionflags == TAPE_VERSION_2 || \
99 versionflags == TAPE_VERSION_3 || \
100 versionflags == TAPE_VERSION_4 ) { \
102 magic = ntohl(vhptr.magic); /* another sanity check */ \
103 if (magic == TC_VOLBEGINMAGIC || \
104 magic == TC_VOLENDMAGIC || \
105 magic == TC_VOLCONTD ) { \
107 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
110 } /* versionflags */ \
114 extern FILE *ErrorlogIO;
115 extern FILE *centralLogIO;
116 extern FILE *lastLogIO;
117 extern afs_int32 lastPass; /* Set true during last pass of dump */
118 extern int debugLevel;
119 extern int autoQuery;
120 extern struct tapeConfig globalTapeConfig;
121 extern struct deviceSyncNode *deviceLatch;
122 extern char globalCellName[];
126 /* forward declaration */
127 afs_int32 readVolumeHeader( /*char *buffer,afs_int32 bufloc,(struct volumeHeader *)vhptr */ );
129 /* The on-disk volume header or trailer can differ in size from platform to platform */
130 static struct TapeBlock tapeBlock;
131 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
134 PrintLog(log, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
136 afs_int32 error1, error2;
137 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
141 fprintf(log, str, a, b, c, d, e, f, g, h, i, j);
146 err1 = "Volume needs to be salvaged";
149 err1 = "Bad vnode number quoted";
152 err1 = "Volume not attached, does not exist, or not on line";
155 err1 = "Volume already exists";
158 err1 = "Volume is not in service";
161 err1 = "Volume is off line";
164 err1 = "Volume is already on line";
167 err1 = "Partition is full";
170 err1 = "Volume max quota exceeded";
173 err1 = "Volume temporarily unavailable";
176 err1 = "Volume has moved to another server";
179 err1 = (char *)afs_error_message(error1);
180 err2 = (char *)afs_error_table_name(error1);
184 fprintf(log, " Possible communication failure");
186 fprintf(log, " %s: %s", err2, err1);
188 fprintf(log, ": %s", afs_error_message(error2));
195 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
197 afs_int32 task, error1, error2;
198 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
201 char tbuffer[32], *timestr;
204 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
207 fprintf(logIO, "%s: ", timestr);
209 fprintf(logIO, "Task %u: ", task);
210 PrintLog(logIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
212 if (lastPass && lastLogIO) {
213 fprintf(lastLogIO, "%s: ", timestr);
215 fprintf(lastLogIO, "Task %u: ", task);
216 PrintLog(lastLogIO, error1, error2, str, a, b, c, d, e, f, g, h, i,
220 /* Now print to the screen if debug level requires */
221 if (debug <= debugLevel)
222 PrintLog(stdout, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
226 TLog(task, str, a, b, c, d, e, f, g, h, i, j)
228 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
230 /* Sends message to TapeLog and stdout */
231 TapeLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
235 ErrorLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
237 afs_int32 task, error1, error2;
238 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
241 char tbuffer[32], *timestr;
244 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
246 fprintf(ErrorlogIO, "%s: ", timestr);
248 /* Print the time and task number */
250 fprintf(ErrorlogIO, "Task %u: ", task);
251 PrintLog(ErrorlogIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
253 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
257 ELog(task, str, a, b, c, d, e, f, g, h, i, j)
259 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
261 /* Sends message to ErrorLog, TapeLog and stdout */
262 ErrorLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
265 /* first proc called by anybody who intends to use the device */
267 EnterDeviceQueue(devLatch)
268 struct deviceSyncNode *devLatch;
270 ObtainWriteLock(&(devLatch->lock));
271 devLatch->flags = TC_DEVICEINUSE;
274 /* last proc called by anybody finishing using the device */
276 LeaveDeviceQueue(devLatch)
277 struct deviceSyncNode *devLatch;
280 ReleaseWriteLock(&(devLatch->lock));
283 #define BELLTIME 60 /* 60 seconds before a bell rings */
284 #define BELLCHAR 7 /* ascii for bell */
287 #ifdef AFS_PTHREAD_ENV
289 /* WaitForKeystroke : Wait until a key has been struck or time (secconds)
290 * runs out and return to caller. The NT version of this function will return
291 * immediately after a key has been pressed (doesn't wait for cr).
293 * seconds: wait for <seconds> seconds before returning. If seconds < 0,
296 * 1: Keyboard input available
297 * 0: seconds elapsed. Timeout.
299 * STOLEN FROM LWP_WaitForKeystroke()
302 WaitForKeystroke(int seconds)
304 time_t startTime, nowTime;
306 struct timeval twait;
315 /* check if we have a keystroke */
321 /* sleep for LWP_KEYSTROKE_DELAY ms and let other
323 select(0, 0, 0, 0, &twait);
325 if (seconds > 0) { /* we only worry about elapsed time if
326 * not looping forever (seconds < 0) */
328 timeleft = seconds - difftime(nowTime, startTime);
330 } while (timeleft > 0);
333 #else /* AFS_NT40)ENV */
334 extern int WaitForKeystroke(int);
336 * STOLEN FROM LWP_WaitForKeystroke()
339 WaitForKeystroke(int seconds)
343 struct timeval twait;
344 struct timeval *tp = NULL;
346 #ifdef AFS_LINUX20_ENV
347 if (stdin->_IO_read_ptr < stdin->_IO_read_end)
354 FD_SET(fileno(stdin), &rdfds);
357 twait.tv_sec = seconds;
361 code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
362 return (code == 1) ? 1 : 0;
366 /* GetResponseKey() - Waits for a specified period of time and
367 * returns a char when one has been typed by the user.
369 * seconds - how long to wait for a key press.
370 * *key - char entered by user
372 * 0 - Time ran out before the user typed a key.
373 * 1 - Valid char is being returned.
375 * STOLEN FROM LWP_GetResponseKey();
378 GetResponseKey(int seconds, char *key)
383 return 0; /* need space to store char */
384 fflush(stdin); /* flush all existing data and start anew */
386 rc = WaitForKeystroke(seconds);
387 if (rc == 0) { /* time ran out */
392 /* now read the char. */
394 *key = getche(); /* get char and echo it to screen */
400 #endif /* AFS_PTHREAD_ENV
405 * * only external clients are in recoverDb.c. Was static. PA
415 #ifdef AFS_PTHREAD_ENV
416 w = WaitForKeystroke(0);
418 w = LWP_WaitForKeystroke(0);
419 #endif /* AFS_PTHREAD_ENV */
426 #endif /* AFS_NT40_ENV */
434 callOutRoutine(taskId, tapePath, flag, name, dbDumpId, tapecount)
457 callOut = opencallout;
460 strcpy(Sopcode, "restore");
463 strcpy(Sopcode, "appenddump");
466 strcpy(Sopcode, "dump");
469 strcpy(Sopcode, "labeltape");
471 case READLABELOPCODE:
472 strcpy(Sopcode, "readlabel");
475 strcpy(Sopcode, "scantape");
477 case RESTOREDBOPCODE:
478 strcpy(Sopcode, "restoredb");
481 strcpy(Sopcode, "savedb");
484 strcpy(Sopcode, "unmount");
485 callOut = closecallout;
488 strcpy(Sopcode, "unknown");
492 if (!callOut) /* no script to call */
495 strcpy(ScallOut, callOut);
496 CO_argv[0] = ScallOut;
498 strcpy(StapePath, tapePath);
499 CO_argv[1] = StapePath;
501 CO_argv[2] = Sopcode;
503 if (flag == CLOSEOPCODE) {
506 sprintf(Scount, "%d", tapecount);
509 /* The tape label name - special case labeltape */
510 if (!name || (strcmp(name, "") == 0)) /* no label */
511 strcpy(Stape, "none");
512 else { /* labeltape */
514 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
515 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
524 strcpy(Sdumpid, "none");
526 sprintf(Sdumpid, "%u", dbDumpId);
527 CO_argv[5] = Sdumpid;
534 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
536 ErrorLog(0, taskId, errno, 0,
537 "Call to %s outside routine %s failed\n", Sopcode, callOut);
546 * Unmounts a tape and prints a warning if it can't unmount it.
547 * Regardless of error, the closecallout routine will be called
548 * (unless a tape is not mounted in the first place).
551 unmountTape(taskId, tapeInfoPtr)
553 struct butm_tapeInfo *tapeInfoPtr;
556 int cpid, status, rcpid;
558 code = butm_Dismount(tapeInfoPtr);
559 if (code && (code != BUTM_NOMOUNT))
560 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
561 "Warning: Can't close tape\n");
563 if (tapemounted && closecallout) {
564 setStatus(taskId, CALL_WAIT);
567 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
569 while (cpid) { /* Wait until return */
571 rcpid = waitpid(cpid, &status, WNOHANG);
576 if (rcpid == -1 && errno != EINTR) {
578 afs_com_err(whoami, errno,
579 "Error waiting for callout script to terminate.");
582 #ifdef AFS_PTHREAD_ENV
588 if (checkAbortByTaskId(taskId)) {
589 TLog(taskId, "Callout routine has been aborted\n");
590 if (kill(cpid, SIGKILL)) /* Cancel callout */
591 ErrorLog(0, taskId, errno, 0,
592 "Kill of callout process %d failed\n", cpid);
597 clearStatus(taskId, CALL_WAIT);
601 * print out prompt to operator
603 * PromptForTape only.
607 PrintPrompt(flag, name, dumpid)
611 char tapename[BU_MAXTAPELEN + 32];
614 TAPENAME(tapename, name, dumpid);
616 printf("******* OPERATOR ATTENTION *******\n");
617 printf("Device : %s \n", globalTapeConfig.device);
620 case READOPCODE: /* mount for restore */
621 printf("Please put in tape %s for reading", tapename);
624 case APPENDOPCODE: /* mount for dump (appends) */
626 dn = extractDumpName(name);
629 printf("Please put in last tape of dump set for appending dump");
632 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
636 case WRITEOPCODE: /* mount for dump */
637 if (strcmp(name, "") == 0)
638 printf("Please put in tape for writing");
640 /* The name is what we are going to label the tape as */
642 printf("Please put in tape %s for writing", tapename);
645 case LABELOPCODE: /* mount for labeltape */
646 printf("Please put in tape to be labelled as %s", tapename);
649 case READLABELOPCODE: /* mount for readlabel */
650 printf("Please put in tape whose label is to be read");
653 case SCANOPCODE: /* mount for scantape */
654 if (strcmp(name, "") == 0)
655 printf("Please put in tape to be scanned");
657 printf("Please put in tape %s for scanning", tapename);
660 case RESTOREDBOPCODE: /* Mount for restoredb */
661 printf("Please insert a tape %s for the database restore", tapename);
664 case SAVEDBOPCODE: /* Mount for savedb */
665 printf("Please insert a writeable tape %s for the database dump",
672 printf(" and hit return when done\n");
676 * Prompt the operator to change the tape.
677 * Use to be a void routine but now returns an error. Some calls
678 * don't use the error code.
680 * only external clients are in recoverDb.c. Was static PA
683 PromptForTape(flag, name, dbDumpId, taskId, tapecount)
686 afs_uint32 dbDumpId; /* Specific dump ID - If non-zero */
690 register afs_int32 code = 0;
695 int cpid, status, rcpid;
697 if (checkAbortByTaskId(taskId))
698 ERROR_EXIT(TC_ABORTEDBYREQUEST);
701 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
703 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
705 CallOut = (opencallout ? 1 : 0);
707 setStatus(taskId, CALL_WAIT);
710 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
711 dbDumpId, tapecount);
713 CallOut = 0; /* prompt at screen */
715 while (CallOut) { /* Check if callout routine finished */
717 rcpid = waitpid(cpid, &status, WNOHANG);
721 else if (WIFEXITED(status))
722 wcode = WEXITSTATUS(status);
727 break; /* All done */
728 } else if (wcode == 1) {
729 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
730 } else if ((flag == READOPCODE) && (wcode == 3)) {
731 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
734 "Callout routine has exited with code %d: will prompt\n",
736 CallOut = 0; /* Switch to keyboard input */
740 /* if waitpid experienced an error, we prompt */
741 if (rcpid == -1 && errno != EINTR) {
742 afs_com_err(whoami, errno,
743 "Error waiting for callout script to terminate.");
745 "Can't get exit status from callout script. will prompt\n");
749 #ifdef AFS_PTHREAD_ENV
755 if (checkAbortByTaskId(taskId)) {
757 ("This tape operation has been aborted by the coordinator.\n");
759 if (kill(cpid, SIGKILL)) /* Cancel callout */
760 ErrorLog(0, taskId, errno, 0,
761 "Kill of callout process %d failed\n", cpid);
763 ERROR_EXIT(TC_ABORTEDBYREQUEST);
769 clearStatus(taskId, CALL_WAIT);
770 setStatus(taskId, OPR_WAIT);
772 PrintPrompt(flag, name, dbDumpId);
774 /* Loop until we get ok to go ahead (or abort) */
776 if (time(0) > start + BELLTIME) {
782 #ifdef AFS_PTHREAD_ENV
783 wcode = GetResponseKey(5, &inchr); /* inchr stores key read */
785 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
787 if (wcode == 1) { /* keyboard input is available */
789 if ((inchr == 'a') || (inchr == 'A')) {
790 printf("This tape operation has been aborted.\n");
791 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
792 } else if ((flag == READOPCODE)
793 && ((inchr == 's') || (inchr == 'S'))) {
794 printf("This tape will be skipped.\n");
795 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
797 break; /* continue */
800 if (checkAbortByTaskId(taskId)) {
802 ("This tape operation has been aborted by the coordinator.\n");
803 ERROR_EXIT(TC_ABORTEDBYREQUEST);
809 printf("Thanks, now proceeding with tape ");
811 case RESTOREDBOPCODE:
817 printf("append writing");
829 case READLABELOPCODE:
830 printf("label reading");
842 printf(" operation.\n");
844 printf("**********************************\n");
846 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
850 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
856 * convert the fields in the tapeVolHeader into host byte order,
857 * placing the converted copy of the structure into the hostVolHeader
859 * tapeVolHeader - points to volume header read from tape
860 * hostVolHeader - pointer to struct for result
862 * hostVolHeader - information in host byte order
866 VolHeaderToHost(hostVolHeader, tapeVolHeader)
867 struct volumeHeader *hostVolHeader, *tapeVolHeader;
869 switch (ntohl(tapeVolHeader->versionflags)) {
871 /* sizes in bytes and fields in host order */
872 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
877 case TAPE_VERSION_3: /* for present */
879 /* sizes in K and fields in network order */
880 /* do the conversion field by field */
882 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
883 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
884 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
885 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
886 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
887 hostVolHeader->server = ntohl(tapeVolHeader->server);
888 hostVolHeader->part = ntohl(tapeVolHeader->part);
889 hostVolHeader->from = ntohl(tapeVolHeader->from);
890 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
891 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
892 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
893 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
894 hostVolHeader->level = ntohl(tapeVolHeader->level);
895 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
896 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
897 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
898 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
902 return (TC_BADVOLHEADER);
908 ReadVolHeader(taskId, tapeInfoPtr, volHeaderPtr)
910 struct butm_tapeInfo *tapeInfoPtr;
911 struct volumeHeader *volHeaderPtr;
915 struct volumeHeader volHead;
917 /* Read the volume header */
919 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
922 ErrorLog(0, taskId, code, tapeInfoPtr->error,
923 "Can't read volume header on tape\n");
927 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
929 ErrorLog(0, taskId, code, 0,
930 "Can't find volume header on tape block\n");
934 code = VolHeaderToHost(volHeaderPtr, &volHead);
936 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
945 GetVolumeHead(taskId, tapeInfoPtr, position, volName, volId)
947 struct butm_tapeInfo *tapeInfoPtr;
953 struct volumeHeader tapeVolHeader;
955 /* Position directly to the volume and read the header */
957 code = butm_Seek(tapeInfoPtr, position);
959 ErrorLog(0, taskId, code, tapeInfoPtr->error,
960 "Can't seek to position %u on tape\n", position);
964 code = butm_ReadFileBegin(tapeInfoPtr);
966 ErrorLog(0, taskId, code, tapeInfoPtr->error,
967 "Can't read FileBegin on tape\n");
971 /* Read the volume header */
972 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
976 /* Check if volume header matches */
977 if (strcmp(tapeVolHeader.volumeName, volName))
978 ERROR_EXIT(TC_BADVOLHEADER);
979 if (volId && (tapeVolHeader.volumeID != volId))
980 ERROR_EXIT(TC_BADVOLHEADER);
981 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
982 ERROR_EXIT(TC_BADVOLHEADER);
985 /* Do a sequential search for the volume */
988 code = butm_ReadFileBegin(tapeInfoPtr);
990 ErrorLog(0, taskId, code, tapeInfoPtr->error,
991 "Can't read FileBegin on tape\n");
995 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
997 ERROR_EXIT(TC_VOLUMENOTONTAPE);
999 /* Test if we found the volume */
1000 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
1001 && (!volId || (volId == tapeVolHeader.volumeID)))
1004 /* skip to the next HW EOF marker */
1005 code = SeekFile(tapeInfoPtr, 1);
1007 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1008 "Can't seek to next EOF on tape\n");
1019 GetRestoreTape(taskId, tapeInfoPtr, tname, tapeID, prompt)
1021 struct butm_tapeInfo *tapeInfoPtr;
1026 struct butm_tapeLabel tapeLabel;
1027 afs_int32 code = 0, rc;
1029 struct budb_dumpEntry dumpEntry;
1031 /* Make sure that the dump/tape is not a XBSA dump */
1032 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
1033 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1034 ErrorLog(0, taskId, 0, 0,
1035 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
1036 ERROR_EXIT(TC_SKIPTAPE);
1042 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
1049 code = butm_Mount(tapeInfoPtr, tname);
1051 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
1055 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
1057 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1058 "Can't read tape label\n");
1062 /* Now check the label to see if the tapename matches or tapeids match */
1063 if (strcmp(TNAME(&tapeLabel), tname)
1064 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
1065 && (tapeLabel.dumpid != tapeID))) {
1066 char expectedName[BU_MAXTAPELEN + 32],
1067 gotName[BU_MAXTAPELEN + 32];
1069 TAPENAME(expectedName, tname, tapeID);
1070 LABELNAME(gotName, &tapeLabel);
1072 TapeLog(0, taskId, 0, 0,
1073 "Tape label expected %s, label seen %s\n", expectedName,
1081 unmountTape(taskId, tapeInfoPtr);
1089 xbsaRestoreVolumeData(call, rparamsPtr)
1090 register struct rx_call *call;
1091 struct restoreParams *rparamsPtr;
1095 afs_int32 curChunk, rc;
1096 afs_uint32 totalWritten;
1097 afs_int32 headBytes, tailBytes, w;
1099 struct volumeHeader volTrailer;
1100 afs_int32 vtsize = 0;
1102 struct dumpNode *nodePtr;
1103 struct tc_restoreDesc *Restore;
1104 afs_int32 bytesRead, tbuffersize, endData = 0;
1105 char *buffer = (char *)bufferBlock, tbuffer[256];
1107 nodePtr = rparamsPtr->nodePtr;
1108 Restore = nodePtr->restores;
1109 taskId = nodePtr->taskID;
1111 /* Read the volume fragment one block at a time until
1112 * find a volume trailer
1114 curChunk = BIGCHUNK + 1;
1119 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1121 if (restoretofile && (bytesRead > 0)) {
1122 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1124 if (rc != XBSA_SUCCESS) {
1125 ErrorLog(0, taskId, rc, 0,
1126 "Unable to read volume data from the server\n");
1130 /* Periodically update status structure and check if should abort */
1131 curChunk += bytesRead;
1132 if (curChunk > BIGCHUNK) {
1135 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1138 if (checkAbortByTaskId(taskId))
1139 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1142 if (!endData && (bytesRead > 0)) {
1143 /* Fill tbuffer up with data from end of buffer and write
1144 * the remainder of buffer out.
1146 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1147 /* Write out contents of tbuffer */
1149 w = rx_Write(call, tbuffer, tbuffersize);
1150 if (w != tbuffersize) {
1151 ErrorLog(0, taskId, -1, 0,
1152 "Error in RX write: Wrote %d bytes\n", w);
1157 /* fill tbuffer with end of buffer */
1158 bytesRead -= sizeof(tbuffer);
1159 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1160 tbuffersize = sizeof(tbuffer);
1161 /* Write out whatever is left over in buffer */
1163 w = rx_Write(call, buffer, bytesRead);
1164 if (w != bytesRead) {
1165 ErrorLog(0, taskId, -1, 0,
1166 "Error in RX data write: Wrote %d bytes\n",
1173 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1174 /* Copy all of buffer into tbuffer (it will fit) */
1175 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1176 tbuffersize += bytesRead;
1179 /* We need to write some of tbuffer out and fill it with buffer */
1180 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1181 w = rx_Write(call, tbuffer, towrite);
1183 ErrorLog(0, taskId, -1, 0,
1184 "Error in RX write: Wrote %d bytes\n", w);
1190 /* Move the data in tbuffer up */
1191 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1193 /* Now copy buffer in */
1194 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1195 tbuffersize += bytesRead;
1201 /* Pull the volume trailer from the last two buffers */
1203 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1204 &tailBytes, &volTrailer);
1207 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1208 ERROR_EXIT(TC_MISSINGTRAILER);
1211 /* Now rx_write the data in the last two blocks */
1213 w = rx_Write(call, tbuffer, headBytes);
1214 if (w != headBytes) {
1215 ErrorLog(0, taskId, -1, 0,
1216 "Error in RX trail1 write: Wrote %d bytes\n", w);
1222 w = rx_Write(call, buffer, tailBytes);
1223 if (w != tailBytes) {
1224 ErrorLog(0, taskId, -1, 0,
1225 "Error in RX trail2 write: Wrote %d bytes\n", w);
1237 * sends the contents of volume dump to Rx Stream associated
1242 restoreVolumeData(call, rparamsPtr)
1243 register struct rx_call *call;
1244 struct restoreParams *rparamsPtr;
1247 afs_uint32 totalWritten = 0;
1249 afs_int32 headBytes, tailBytes, w;
1251 afs_int32 nbytes; /* # bytes data in last tape block read */
1252 struct volumeHeader tapeVolTrailer;
1255 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1256 struct tc_restoreDesc *Restore;
1257 struct dumpNode *nodePtr;
1258 struct butm_tapeInfo *tapeInfoPtr;
1260 afs_int32 origVolID;
1262 nodePtr = rparamsPtr->nodePtr;
1263 taskId = nodePtr->taskID;
1264 Restore = nodePtr->restores;
1265 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1266 origVolName = Restore[rparamsPtr->frag].oldName;
1267 origVolID = Restore[rparamsPtr->frag].origVid;
1269 /* Read the volume one fragment at a time */
1270 while (rparamsPtr->frag < nodePtr->arraySize) {
1272 curChunk = BIGCHUNK + 1; /* Check if should abort */
1274 /* Read the volume fragment one block at a time until
1275 * find a volume trailer
1281 while (moretoread) {
1282 /* Fill the circular buffer with tape blocks
1283 * Search for volume trailer in the process.
1288 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1289 BUTM_BLKSIZE, &nbytes);
1291 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1292 "Can't read FileData on tape %s\n",
1293 rparamsPtr->mntTapeName);
1296 curChunk += BUTM_BLKSIZE;
1298 /* Periodically update status structure and check if should abort */
1299 if (curChunk > BIGCHUNK) {
1303 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1306 if (checkAbortByTaskId(taskId))
1307 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1310 /* step to next block in buffer */
1312 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1314 /* If this is the end of the volume, the exit the loop */
1315 if ((nbytes != BUTM_BLKSIZE)
1318 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1322 } while (moretoread && (buf != endRbuf));
1324 /* Write the buffer upto (but not including) the last read block
1325 * If volume is completely read, then leave the last two blocks.
1327 lastbuf = endWbuf = pbuf;
1328 if (!moretoread && (endWbuf != startWbuf))
1329 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1331 for (buf = startWbuf; buf != endWbuf;
1332 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1333 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1334 if (w != BUTM_BLKSIZE) {
1335 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1338 totalWritten += BUTM_BLKSIZE;
1341 /* Setup pointers to refill buffer */
1342 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1344 startWbuf = endWbuf;
1347 /* lastbuf is last block read and it has nbytes of data
1348 * startWbuf is the 2nd to last block read
1349 * Seach for the volume trailer in these two blocks.
1351 if (lastbuf == startWbuf)
1353 FindVolTrailer2(NULL, 0, &headBytes,
1354 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1358 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1359 &headBytes, bufferBlock[lastbuf].data, nbytes,
1360 &tailBytes, &tapeVolTrailer);
1362 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1363 "Missing volume trailer on tape %s\n",
1364 rparamsPtr->mntTapeName);
1365 ERROR_EXIT(TC_MISSINGTRAILER);
1368 /* Now rx_write the data in the last two blocks */
1370 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1371 if (w != headBytes) {
1372 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1375 totalWritten += headBytes;
1378 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1379 if (w != tailBytes) {
1380 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1383 totalWritten += tailBytes;
1386 /* Exit the loop if the volume is not continued on next tape */
1387 if (!tapeVolTrailer.contd)
1388 break; /* We've read the entire volume */
1390 /* Volume is continued on next tape.
1391 * Step to the next volume fragment and prompt for its tape.
1392 * When a volume has multiple frags, those frags are on different
1393 * tapes. So we know that we need to prompt for a tape.
1396 if (rparamsPtr->frag >= nodePtr->arraySize)
1399 unmountTape(taskId, tapeInfoPtr);
1400 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1401 rparamsPtr->tapeID =
1402 (Restore[rparamsPtr->frag].
1403 initialDumpId ? Restore[rparamsPtr->frag].
1404 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1406 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1407 rparamsPtr->tapeID, 1);
1411 /* Position to the frag and read the volume header */
1413 GetVolumeHead(taskId, tapeInfoPtr,
1414 Restore[rparamsPtr->frag].position, origVolName,
1417 ErrorLog(0, taskId, code, 0,
1418 "Can't find volume %s (%u) on tape %s\n", origVolName,
1419 origVolID, rparamsPtr->mntTapeName);
1420 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1429 * Find all the volumes on a specific tape and mark them to skip.
1431 SkipTape(Restore, size, index, tapename, tapeid, taskid)
1432 struct tc_restoreDesc *Restore;
1433 afs_int32 size, index, tapeid, taskid;
1438 for (i = index; i < size; i++) {
1439 if (Restore[i].flags & RDFLAG_SKIP)
1442 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1444 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1445 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1452 * Find all the entries for a volume and mark them to skip.
1454 SkipVolume(Restore, size, index, volid, taskid)
1455 struct tc_restoreDesc *Restore;
1456 afs_int32 size, index, volid, taskid;
1461 for (i = index; i < size; i++) {
1462 if (Restore[i].flags & RDFLAG_SKIP)
1464 if (Restore[i].origVid == volid) {
1465 Restore[i].flags |= RDFLAG_SKIP;
1467 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1468 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1469 Restore[i].oldName, volid);
1477 xbsaRestoreVolume(taskId, restoreInfo, rparamsPtr)
1479 struct tc_restoreDesc *restoreInfo;
1480 struct restoreParams *rparamsPtr;
1485 afs_int32 newServer, newPart, newVolId;
1487 int restoreflags, havetrans = 0, startread = 0;
1488 afs_int32 bytesRead, endData = 0;
1490 struct budb_dumpEntry dumpEntry;
1491 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1492 struct volumeHeader volHeader, hostVolHeader;
1494 if (restoretofile) {
1495 restoretofilefd = fopen(restoretofile, "w+");
1498 dumpID = restoreInfo->dbDumpId;
1500 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1502 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1507 /* ADSM servers restore ADSM and BUTA dumps */
1508 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1509 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1511 "The dump requested by this restore operation for the "
1512 "volumeset is incompatible with this instance of butc\n");
1513 /* Skip the entire dump (one dump per tape) */
1514 ERROR_EXIT(TC_SKIPTAPE);
1517 /* make sure we are connected to the correct server. */
1518 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1519 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1521 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1522 && !forcemultiple) {
1524 "Dump %d is on server %s but butc is connected "
1525 "to server %s (attempting to restore)\n", dumpID,
1526 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1529 "Dump %d is on server %s but butc is connected "
1530 "to server %s (switching servers)\n", dumpID,
1531 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1533 rc = InitToServer(taskId, &butxInfo,
1534 (char *)dumpEntry.tapes.tapeServer);
1535 if (rc != XBSA_SUCCESS)
1536 ERROR_EXIT(TC_SKIPTAPE);
1540 /* Start a transaction and query the server for the correct fileset dump */
1541 rc = xbsa_BeginTrans(&butxInfo);
1542 if (rc != XBSA_SUCCESS) {
1543 ELog(taskId, "Unable to create a new transaction\n");
1544 ERROR_EXIT(TC_SKIPTAPE);
1548 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1549 sprintf(dumpIdStr, "/%d", dumpID);
1550 strcpy(volumeNameStr, "/");
1551 strcat(volumeNameStr, restoreInfo->oldName);
1552 } else { /* new butc names */
1553 extern char *butcdumpIdStr;
1554 strcpy(dumpIdStr, butcdumpIdStr);
1555 sprintf(volumeNameStr, "/%d", dumpID);
1556 strcat(volumeNameStr, "/");
1557 strcat(volumeNameStr, restoreInfo->oldName);
1560 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1561 if (rc != XBSA_SUCCESS) {
1563 "Unable to locate object (%s) of dump (%s) on the server\n",
1564 volumeNameStr, dumpIdStr);
1568 rc = xbsa_EndTrans(&butxInfo);
1570 if (rc != XBSA_SUCCESS) {
1571 ELog(taskId, "Unable to terminate the current transaction\n");
1575 if (checkAbortByTaskId(taskId))
1576 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1578 /* Now start a transaction on the volume to restore and read the
1579 * volumeheader. We do this before starting a transaction on
1580 * volserver to restore the volume because the XBSA server may take
1581 * a while to mount and seek to the volume causing the volserver to
1584 rc = xbsa_BeginTrans(&butxInfo);
1585 if (rc != XBSA_SUCCESS) {
1586 ELog(taskId, "Unable to create a new transaction\n");
1587 ERROR_EXIT(TC_SKIPTAPE);
1591 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1592 sizeof(volHeader), &bytesRead, &endData);
1593 if (restoretofile && (bytesRead > 0)) {
1594 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1596 if (rc != XBSA_SUCCESS) {
1598 "Unable to begin reading of the volume from the server\n");
1603 if ((bytesRead != sizeof(volHeader)) || endData) {
1605 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1606 bytesRead, sizeof(volHeader));
1607 ERROR_EXIT(TC_BADVOLHEADER);
1610 /* convert and check the volume header */
1611 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1613 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1617 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1618 || (restoreInfo->origVid
1619 && (hostVolHeader.volumeID != restoreInfo->origVid))
1620 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1621 ERROR_EXIT(TC_BADVOLHEADER);
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)
1630 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1631 restoreflags |= RV_FULLRST;
1632 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1633 restoreflags |= RV_OFFLINE;
1635 if (checkAbortByTaskId(taskId))
1636 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1638 /* Start the restore of the volume data. This is the code we want to return */
1640 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1641 restoreflags, xbsaRestoreVolumeData,
1642 (char *)rparamsPtr);
1645 rc = xbsa_ReadObjectEnd(&butxInfo);
1646 if (rc != XBSA_SUCCESS) {
1648 "Unable to terminate reading of the volume from the server\n");
1654 rc = xbsa_EndTrans(&butxInfo);
1655 if (rc != XBSA_SUCCESS) {
1656 ELog(taskId, "Unable to terminate the current transaction\n");
1662 if (restoretofile && restoretofilefd) {
1663 fclose(restoretofilefd);
1669 restoreVolume(taskId, restoreInfo, rparamsPtr)
1671 struct tc_restoreDesc *restoreInfo;
1672 struct restoreParams *rparamsPtr;
1674 afs_int32 code = 0, rc;
1675 afs_int32 newServer, newPart, newVolId;
1679 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1681 /* Check if we need a tape and prompt for one if so */
1683 (restoreInfo->initialDumpId ? restoreInfo->
1684 initialDumpId : restoreInfo->dbDumpId);
1685 if ((rparamsPtr->frag == 0)
1686 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1687 || (tapeID != rparamsPtr->tapeID)) {
1688 /* Unmount the previous tape */
1689 unmountTape(taskId, tapeInfoPtr);
1691 /* Remember this new tape */
1692 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1693 rparamsPtr->tapeID = tapeID;
1695 /* Mount a new tape */
1696 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1698 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1703 /* Seek to the correct spot and read the header information */
1704 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1705 restoreInfo->oldName, restoreInfo->origVid);
1709 /* Set up prior restoring volume data */
1710 newVolName = restoreInfo->newName;
1711 newVolId = restoreInfo->vid;
1712 newServer = restoreInfo->hostAddr;
1713 newPart = restoreInfo->partition;
1715 if ((restoreInfo->dumpLevel == 0)
1716 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1717 restoreflags |= RV_FULLRST;
1718 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1719 restoreflags |= RV_OFFLINE;
1721 if (checkAbortByTaskId(taskId))
1722 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1724 /* Start the restore of the volume data. This is the code we
1728 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1729 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1731 /* Read the FileEnd marker for the volume and step to next FM */
1732 rc = butm_ReadFileEnd(tapeInfoPtr);
1734 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1735 "Can't read EOF on tape\n");
1743 * created as a LWP by the server stub, <newNode> is a pointer to all
1744 * the parameters Restorer needs
1747 Restorer(void *param) {
1748 struct dumpNode *newNode = (struct dumpNode *) param;
1750 afs_int32 code = 0, tcode;
1753 struct butm_tapeInfo tapeInfo;
1754 struct tc_restoreDesc *Restore;
1755 struct tc_restoreDesc *RestoreDesc;
1756 struct restoreParams rparams;
1757 afs_int32 allocbufferSize;
1758 time_t startTime, endTime;
1759 afs_int32 goodrestore = 0;
1761 taskId = newNode->taskID;
1762 setStatus(taskId, DRIVE_WAIT);
1763 EnterDeviceQueue(deviceLatch);
1764 clearStatus(taskId, DRIVE_WAIT);
1767 TLog(taskId, "Restore\n");
1769 memset(&tapeInfo, 0, sizeof(tapeInfo));
1771 tapeInfo.structVersion = BUTM_MAJORVERSION;
1772 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1774 ErrorLog(0, taskId, tcode, tapeInfo.error,
1775 "Can't initialize the tape module\n");
1780 if (checkAbortByTaskId(taskId))
1781 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1783 memset(&rparams, 0, sizeof(rparams));
1784 rparams.nodePtr = newNode;
1785 rparams.tapeInfoPtr = &tapeInfo;
1786 Restore = newNode->restores; /* Array of vol fragments to restore */
1788 /* Allocate memory in which to restore the volumes data into */
1790 allocbufferSize = dataSize = BufferSize;
1792 /* Must have at least two tape blocks */
1793 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1796 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1799 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1801 ERROR_EXIT(TC_NOMEMORY);
1802 memset(bufferBlock, 0, allocbufferSize);
1804 startTime = time(0);
1805 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1807 RestoreDesc = &Restore[rparams.frag];
1809 /* Skip the volume if it was requested to */
1810 if (RestoreDesc->flags & RDFLAG_SKIP) {
1811 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1812 /* If the volume was restored, should bring it online */
1817 newVolName = RestoreDesc->newName;
1819 /* Make sure the server to restore to is good */
1820 if (!RestoreDesc->hostAddr) {
1821 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1823 ERROR_EXIT(TC_INTERNALERROR);
1826 if (checkAbortByTaskId(taskId))
1827 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1829 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1831 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1835 /* restoreVolume function takes care of all the related fragments
1836 * spanning various tapes. On return the complete volume has been
1840 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1842 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1845 if (tcode == TC_ABORTEDBYREQUEST) {
1847 } else if (tcode == TC_SKIPTAPE) {
1850 (RestoreDesc->initialDumpId ? RestoreDesc->
1851 initialDumpId : RestoreDesc->dbDumpId);
1852 SkipTape(Restore, newNode->arraySize, rparams.frag,
1853 RestoreDesc->tapeName, tapeID, taskId);
1855 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1857 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1858 RestoreDesc->origVid, taskId);
1870 unmountTape(taskId, &tapeInfo);
1873 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1880 if (code == TC_ABORTEDBYREQUEST) {
1881 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1882 clearStatus(taskId, ABORT_REQUEST);
1883 setStatus(taskId, ABORT_DONE);
1885 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1886 setStatus(taskId, TASK_ERROR);
1888 TLog(taskId, "Restore: Finished\n");
1891 if (centralLogIO && startTime) {
1893 afs_int32 hrs, min, sec, tmp;
1895 struct tm tmstart, tmend;
1897 localtime_r(&startTime, &tmstart);
1898 localtime_r(&endTime, &tmend);
1899 timediff = (int)endTime - (int)startTime;
1900 hrs = timediff / 3600;
1901 tmp = timediff % 3600;
1906 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1907 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1908 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1909 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1910 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1911 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1912 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1913 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1915 fwrite(line, strlen(line), 1, centralLogIO);
1916 fflush(centralLogIO);
1919 setStatus(taskId, TASK_DONE);
1922 LeaveDeviceQueue(deviceLatch);
1923 return (void *)(code);
1926 /* this is just scaffolding, creates new tape label with name <tapeName> */
1929 GetNewLabel(tapeInfoPtr, pName, AFSName, tapeLabel)
1930 struct butm_tapeInfo *tapeInfoPtr;
1931 char *pName, *AFSName;
1932 struct butm_tapeLabel *tapeLabel;
1935 struct timezone tzp;
1938 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1941 butm_GetSize(tapeInfoPtr, &size);
1943 size = globalTapeConfig.capacity;
1945 size = 0; /* no tape size */
1947 gettimeofday(&tp, &tzp);
1949 tapeLabel->structVersion = CUR_TAPE_VERSION;
1950 tapeLabel->creationTime = tp.tv_sec;
1951 tapeLabel->size = size;
1952 tapeLabel->expirationDate = 0; /* 1970 sometime */
1953 tapeLabel->dumpPath[0] = 0; /* no path name */
1954 tapeLabel->useCount = 0;
1955 strcpy(tapeLabel->AFSName, AFSName);
1956 strcpy(tapeLabel->pName, pName);
1957 strcpy(tapeLabel->cell, globalCellName);
1958 strcpy(tapeLabel->comment, "AFS Backup Software");
1959 strcpy(tapeLabel->creator.name, "AFS 3.6");
1960 strcpy(tapeLabel->creator.instance, "");
1961 strcpy(tapeLabel->creator.cell, globalCellName);
1964 /* extracts trailer out of buffer, nbytes is set to total data in buffer - trailer size */
1966 ExtractTrailer(buffer, size, nbytes, volTrailerPtr)
1970 struct volumeHeader *volTrailerPtr;
1974 struct volumeHeader tempTrailer;
1978 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1980 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1982 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1988 return 1; /* saw the trailer */
1994 return 0; /* did not see the trailer */
1998 FindVolTrailer(buffer, size, dSize, volTrailerPtr)
2001 struct volumeHeader *volTrailerPtr;
2002 afs_int32 *dSize; /* dataSize */
2004 afs_int32 offset, s;
2011 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2015 found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
2017 *dSize -= (s - offset);
2022 FindVolTrailer2(buffera, sizea, dataSizea, bufferb, sizeb, dataSizeb,
2026 afs_int32 *dataSizea;
2029 afs_int32 *dataSizeb;
2030 struct volumeHeader *volTrailerPtr;
2032 afs_int32 offset, s;
2033 afs_int32 headB, tailB;
2043 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2045 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
2048 headB = (s - sizeb); /*(s > sizeb) */
2049 if (headB > sizea) {
2056 memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
2058 memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
2060 memcpy(tapeVolumeHT + headB, bufferb, tailB);
2061 if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
2063 if (offset > headB) {
2064 /* *dataSizea remains unchanged */
2065 *dataSizeb = offset - headB;
2067 *dataSizea -= (headB - offset); /*(headB >= offset) */
2075 /* Returns true or false depending on whether the tape is expired or not */
2078 ExpirationDate(dumpid)
2082 Date expiration = 0;
2083 struct budb_dumpEntry dumpEntry;
2084 struct budb_tapeEntry tapeEntry;
2085 struct budb_volumeEntry volEntry;
2089 * Get the expiration date from DB if its there. The expiration of any tape
2090 * will be the most future expiration of any dump in the set. Can't use
2091 * bcdb_FindTape because dumpid here pertains to the initial dump id.
2093 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
2095 expiration = tapeEntry.expires;
2097 return (expiration);
2101 tapeExpired(tapeLabelPtr)
2102 struct butm_tapeLabel *tapeLabelPtr;
2106 struct timezone tzp;
2108 expiration = ExpirationDate(tapeLabelPtr->dumpid);
2110 expiration = tapeLabelPtr->expirationDate;
2112 gettimeofday(&tp, &tzp);
2113 return ((expiration < tp.tv_sec) ? 1 : 0);
2117 * given the label on the tape, delete any old information from the
2120 * Deletes all entries that match the volset.dumpnode
2121 * and the dump path.
2124 updateTapeLabel(labelIfPtr, tapeInfoPtr, newLabelPtr)
2125 struct labelTapeIf *labelIfPtr;
2126 struct butm_tapeInfo *tapeInfoPtr;
2127 struct butm_tapeLabel *newLabelPtr;
2129 struct butm_tapeLabel oldLabel;
2130 afs_int32 i, code = 0;
2132 int tapeIsLabeled = 0;
2133 int interactiveFlag;
2136 interactiveFlag = autoQuery;
2137 taskId = labelIfPtr->taskId;
2140 if (interactiveFlag) {
2142 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2143 labelIfPtr->taskId, tapecount);
2147 interactiveFlag = 1;
2150 /* mount the tape */
2151 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2153 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2157 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2161 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2162 && (strcmp(oldLabel.pName, "") != 0)) {
2163 /* We are setting the AFS name, yet tape
2164 * has a permanent name (not allowed).
2166 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2171 if (!tapeExpired(&oldLabel)) {
2172 if (!queryoperator) {
2173 TLog(taskId, "This tape has not expired\n");
2176 if (Ask("This tape has not expired - proceed") == 0)
2180 /* Keep the permanent name */
2181 if (strcmp(newLabelPtr->pName, "") == 0) {
2182 strcpy(newLabelPtr->pName, oldLabel.pName);
2183 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2184 strcpy(newLabelPtr->pName, "");
2188 /* extract useful information from the old label */
2189 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2190 newLabelPtr->dumpid = 0;
2191 newLabelPtr->useCount = oldLabel.useCount + 1;
2194 /* now write the new label */
2195 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2197 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2198 "Can't label tape\n");
2205 unmountTape(taskId, tapeInfoPtr);
2208 /* delete obsolete information from the database */
2209 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2210 /* delete based on dump id */
2211 if (oldLabel.dumpid) {
2212 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2213 if (i && (i != BUDB_NOENT))
2214 ErrorLog(0, taskId, i, 0,
2215 "Warning: Can't delete old dump %u from database\n",
2221 unmountTape(taskId, tapeInfoPtr);
2226 * LWP created by the server stub. Labels the tape with name and size
2227 * specified by <label>
2231 Labeller(void *param)
2233 struct labelTapeIf *labelIfPtr = (struct labelTapeIf *)param;
2235 struct tc_tapeLabel *label = &labelIfPtr->label;
2237 struct butm_tapeLabel newTapeLabel;
2238 struct butm_tapeInfo tapeInfo;
2242 taskId = labelIfPtr->taskId;
2243 setStatus(taskId, DRIVE_WAIT);
2244 EnterDeviceQueue(deviceLatch);
2245 clearStatus(taskId, DRIVE_WAIT);
2248 TLog(taskId, "Labeltape\n");
2250 memset(&tapeInfo, 0, sizeof(tapeInfo));
2251 tapeInfo.structVersion = BUTM_MAJORVERSION;
2252 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2254 ErrorLog(0, taskId, code, tapeInfo.error,
2255 "Can't initialize the tape module\n");
2259 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2261 newTapeLabel.size = label->size;
2263 newTapeLabel.size = globalTapeConfig.capacity;
2265 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2270 if (code == TC_ABORTEDBYREQUEST) {
2271 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2272 clearStatus(taskId, ABORT_REQUEST);
2273 setStatus(taskId, ABORT_DONE);
2275 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2276 setStatus(taskId, TASK_ERROR);
2278 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2279 TNAME(&newTapeLabel), newTapeLabel.size);
2281 setStatus(labelIfPtr->taskId, TASK_DONE);
2284 LeaveDeviceQueue(deviceLatch);
2285 return (void *)(code);
2289 * print out the tape label.
2293 PrintTapeLabel(labelptr)
2294 struct butm_tapeLabel *labelptr;
2296 char tapeName[BU_MAXTAPELEN + 32];
2299 printf("Tape label\n");
2300 printf("----------\n");
2301 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2302 printf("permanent tape name = %s\n", tapeName);
2303 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2304 printf("AFS tape name = %s\n", tapeName);
2305 t = labelptr->creationTime;
2306 printf("creationTime = %s", ctime(&t));
2307 if (labelptr->expirationDate) {
2308 t = labelptr->expirationDate;
2309 printf("expirationDate = %s", cTIME(&t));
2311 printf("cell = %s\n", labelptr->cell);
2312 printf("size = %u Kbytes\n", labelptr->size);
2313 printf("dump path = %s\n", labelptr->dumpPath);
2315 if (labelptr->structVersion >= TAPE_VERSION_3) {
2316 printf("dump id = %u\n", labelptr->dumpid);
2317 printf("useCount = %d\n", labelptr->useCount);
2319 printf("-- End of tape label --\n\n");
2323 * Read the label from a tape.
2324 * Currently prints out a "detailed" summary of the label but passes
2325 * back only selected fields.
2329 struct tc_tapeLabel *label;
2331 struct butm_tapeLabel newTapeLabel;
2332 struct butm_tapeInfo tapeInfo;
2336 int interactiveFlag;
2339 EnterDeviceQueue(deviceLatch);
2340 taskId = allocTaskId(); /* reqd for lower level rtns */
2343 TLog(taskId, "Readlabel\n");
2345 memset(&tapeInfo, 0, sizeof(tapeInfo));
2346 tapeInfo.structVersion = BUTM_MAJORVERSION;
2347 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2349 ErrorLog(0, taskId, code, tapeInfo.error,
2350 "Can't initialize the tape module\n");
2353 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2355 interactiveFlag = autoQuery;
2358 if (interactiveFlag) {
2359 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2363 interactiveFlag = 1;
2366 code = butm_Mount(&tapeInfo, "");
2368 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2374 unmountTape(taskId, &tapeInfo);
2377 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2379 if (code == BUTM_NOLABEL) {
2380 printf("Tape is unlabelled\n");
2383 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2387 /* copy the fields to be passed to the caller */
2388 label->size = newTapeLabel.size;
2389 label->tapeId = newTapeLabel.dumpid;
2390 strcpy(label->afsname, newTapeLabel.AFSName);
2391 strcpy(label->pname, newTapeLabel.pName);
2394 expir = ExpirationDate(newTapeLabel.dumpid);
2396 newTapeLabel.expirationDate = expir;
2398 PrintTapeLabel(&newTapeLabel);
2401 unmountTape(taskId, &tapeInfo);
2403 if (code == TC_ABORTEDBYREQUEST)
2404 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2405 else if (code && (code != BUTM_NOLABEL))
2406 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2408 TLog(taskId, "ReadLabel: Finished\n");
2410 LeaveDeviceQueue(deviceLatch);
2414 /* Function to read volume header and trailer structure from tape, taking
2415 into consideration, different word alignment rules.
2418 readVolumeHeader(buffer, bufloc, header)
2420 char *buffer; /* buffer to read header from */
2421 /*in */ afs_int32 bufloc;
2422 /* header's location in buffer */
2423 /*out */ struct volumeHeader *header;
2424 /* header structure */
2427 struct volumeHeader vhptr, *tempvhptr;
2428 afs_int32 firstSplice = (afs_int32) ((char*)& vhptr.pad - (char*) & vhptr);
2429 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2430 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2432 /* Four cases are to be handled
2434 * Volume Header (byte alignment)
2435 * -----------------------
2442 * -----------------------
2444 * Case 2 and Case 3 are identical cases and handled the same way.
2445 * Case 1 and Case 4 are separate cases. In one case the pad needs
2446 * to be removed and in the other, it needs to be spliced in. The
2447 * four cases are handled as follows
2449 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2450 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2451 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2452 /* Handle Cases 2 & 3 */
2453 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2454 HEADER_CHECKS(vhptr, header);
2457 memset(&vhptr, 0, sizeof(struct volumeHeader));
2458 memcpy(&vhptr, buffer + bufloc, firstSplice);
2459 memset(&vhptr.pad, 0, padLen);
2460 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2461 HEADER_CHECKS(vhptr, header);
2464 memset(&vhptr, 0, sizeof(struct volumeHeader));
2465 memcpy(&vhptr, buffer + bufloc, firstSplice);
2466 memcpy(&vhptr + firstSplice, buffer + bufloc + firstSplice + padLen,
2468 HEADER_CHECKS(vhptr, header);
2471 return (TC_BADVOLHEADER);