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>
22 #include <netinet/in.h>
26 #include <afs/procmgmt.h>
32 #include <afs/tcdata.h>
33 #include <afs/bubasics.h> /* PA */
34 #include <afs/budb_client.h>
35 #include <afs/volser.h>
36 #include <afs/com_err.h>
37 #include "error_macros.h"
38 #include <afs/afsutil.h>
40 #include "butc_xbsa.h"
42 /* GLOBAL CONFIGURATION PARAMETERS */
43 extern int dump_namecheck;
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 extern char *restoretofile;
52 FILE *restoretofilefd;
53 extern int forcemultiple;
55 /* XBSA Global Parameters */
58 struct butx_transactionInfo butxInfo;
61 struct TapeBlock { /* A 16KB tapeblock */
62 char mark[BUTM_HDRSIZE]; /* Header info */
63 char data[BUTM_BLKSIZE]; /* data */
66 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
67 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
70 * Need to re-write to:
71 * 1) non-interactive tape handling (optional)
72 * 2) compute tape and volume sizes for the database
73 * 3) compute and use tape id's for tape tracking (put on tape label)
74 * 4) status management
77 /* All the relevant info shared between Restorer and restoreVolume */
78 struct restoreParams {
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 memcpy(header, &vhptr, 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);
144 err1 = "Volume needs to be salvaged";
147 err1 = "Bad vnode number quoted";
150 err1 = "Volume not attached, does not exist, or not on line";
153 err1 = "Volume already exists";
156 err1 = "Volume is not in service";
159 err1 = "Volume is off line";
162 err1 = "Volume is already on line";
165 err1 = "Partition is full";
168 err1 = "Volume max quota exceeded";
171 err1 = "Volume temporarily unavailable";
174 err1 = "Volume has moved to another server";
177 err1 = (char *)error_message(error1);
178 err2 = (char *)error_table_name(error1);
182 fprintf(log, " Possible communication failure");
184 fprintf(log, " %s: %s", err2, err1);
186 fprintf(log, ": %s", error_message(error2));
193 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
195 afs_int32 task, error1, error2;
196 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
199 char tbuffer[32], *timestr;
202 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
205 fprintf(logIO, "%s: ", timestr);
207 fprintf(logIO, "Task %u: ", task);
208 PrintLog(logIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
210 if (lastPass && lastLogIO) {
211 fprintf(lastLogIO, "%s: ", timestr);
213 fprintf(lastLogIO, "Task %u: ", task);
214 PrintLog(lastLogIO, error1, error2, str, a, b, c, d, e, f, g, h, i,
218 /* Now print to the screen if debug level requires */
219 if (debug <= debugLevel)
220 PrintLog(stdout, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
224 TLog(task, str, a, b, c, d, e, f, g, h, i, j)
226 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
228 /* Sends message to TapeLog and stdout */
229 TapeLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
233 ErrorLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
235 afs_int32 task, error1, error2;
236 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
239 char tbuffer[32], *timestr;
242 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
244 fprintf(ErrorlogIO, "%s: ", timestr);
246 /* Print the time and task number */
248 fprintf(ErrorlogIO, "Task %u: ", task);
249 PrintLog(ErrorlogIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
251 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
255 ELog(task, str, a, b, c, d, e, f, g, h, i, j)
257 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
259 /* Sends message to ErrorLog, TapeLog and stdout */
260 ErrorLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
263 /* first proc called by anybody who intends to use the device */
265 EnterDeviceQueue(devLatch)
266 struct deviceSyncNode *devLatch;
268 ObtainWriteLock(&(devLatch->lock));
269 devLatch->flags = TC_DEVICEINUSE;
272 /* last proc called by anybody finishing using the device */
274 LeaveDeviceQueue(devLatch)
275 struct deviceSyncNode *devLatch;
278 ReleaseWriteLock(&(devLatch->lock));
281 #define BELLTIME 60 /* 60 seconds before a bell rings */
282 #define BELLCHAR 7 /* ascii for bell */
285 #ifdef AFS_PTHREAD_ENV
287 /* WaitForKeystroke : Wait until a key has been struck or time (secconds)
288 * runs out and return to caller. The NT version of this function will return
289 * immediately after a key has been pressed (doesn't wait for cr).
291 * seconds: wait for <seconds> seconds before returning. If seconds < 0,
294 * 1: Keyboard input available
295 * 0: seconds elapsed. Timeout.
297 * STOLEN FROM LWP_WaitForKeystroke()
300 WaitForKeystroke(int seconds)
302 time_t startTime, nowTime;
304 struct timeval twait;
313 /* check if we have a keystroke */
319 /* sleep for LWP_KEYSTROKE_DELAY ms and let other
321 select(0, 0, 0, 0, &twait);
323 if (seconds > 0) { /* we only worry about elapsed time if
324 * not looping forever (seconds < 0) */
326 timeleft = seconds - difftime(nowTime, startTime);
328 } while (timeleft > 0);
331 #else /* AFS_NT40)ENV */
332 extern int WaitForKeystroke(int);
334 * STOLEN FROM LWP_WaitForKeystroke()
337 WaitForKeystroke(int seconds)
341 struct timeval twait;
342 struct timeval *tp = NULL;
344 #ifdef AFS_LINUX20_ENV
345 if (stdin->_IO_read_ptr < stdin->_IO_read_end)
352 FD_SET(fileno(stdin), &rdfds);
355 twait.tv_sec = seconds;
359 code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
360 return (code == 1) ? 1 : 0;
364 /* GetResponseKey() - Waits for a specified period of time and
365 * returns a char when one has been typed by the user.
367 * seconds - how long to wait for a key press.
368 * *key - char entered by user
370 * 0 - Time ran out before the user typed a key.
371 * 1 - Valid char is being returned.
373 * STOLEN FROM LWP_GetResponseKey();
376 GetResponseKey(int seconds, char *key)
381 return 0; /* need space to store char */
382 fflush(stdin); /* flush all existing data and start anew */
384 rc = WaitForKeystroke(seconds);
385 if (rc == 0) { /* time ran out */
390 /* now read the char. */
392 *key = getche(); /* get char and echo it to screen */
398 #endif /* AFS_PTHREAD_ENV
403 * * only external clients are in recoverDb.c. Was static. PA
412 #ifdef AFS_PTHREAD_ENV
413 w = WaitForKeystroke(0);
415 w = LWP_WaitForKeystroke(0);
416 #endif /* AFS_PTHREAD_ENV */
423 #endif /* AFS_NT40_ENV */
431 callOutRoutine(taskId, tapePath, flag, name, dbDumpId, tapecount)
456 callOut = opencallout;
459 strcpy(Sopcode, "restore");
462 strcpy(Sopcode, "appenddump");
465 strcpy(Sopcode, "dump");
468 strcpy(Sopcode, "labeltape");
470 case READLABELOPCODE:
471 strcpy(Sopcode, "readlabel");
474 strcpy(Sopcode, "scantape");
476 case RESTOREDBOPCODE:
477 strcpy(Sopcode, "restoredb");
480 strcpy(Sopcode, "savedb");
483 strcpy(Sopcode, "unmount");
484 callOut = closecallout;
487 strcpy(Sopcode, "unknown");
491 if (!callOut) /* no script to call */
494 strcpy(ScallOut, callOut);
495 CO_argv[0] = ScallOut;
497 strcpy(StapePath, tapePath);
498 CO_argv[1] = StapePath;
500 CO_argv[2] = Sopcode;
502 if (flag == CLOSEOPCODE) {
505 sprintf(Scount, "%d", tapecount);
508 /* The tape label name - special case labeltape */
509 if (!name || (strcmp(name, "") == 0)) /* no label */
510 strcpy(Stape, "none");
511 else { /* labeltape */
513 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
514 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
523 strcpy(Sdumpid, "none");
525 sprintf(Sdumpid, "%u", dbDumpId);
526 CO_argv[5] = Sdumpid;
533 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
535 ErrorLog(0, taskId, errno, 0,
536 "Call to %s outside routine %s failed\n", Sopcode, callOut);
545 * Unmounts a tape and prints a warning if it can't unmount it.
546 * Regardless of error, the closecallout routine will be called
547 * (unless a tape is not mounted in the first place).
549 unmountTape(taskId, tapeInfoPtr)
551 struct butm_tapeInfo *tapeInfoPtr;
555 int cpid, status, rcpid;
557 code = butm_Dismount(tapeInfoPtr);
558 if (code && (code != BUTM_NOMOUNT))
559 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
560 "Warning: Can't close tape\n");
562 if (tapemounted && closecallout) {
563 setStatus(taskId, CALL_WAIT);
566 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
568 while (cpid) { /* Wait until return */
570 rcpid = waitpid(cpid, &status, WNOHANG);
575 if (rcpid == -1 && errno != EINTR) {
577 com_err(whoami, errno,
578 "Error waiting for callout script to terminate.");
581 #ifdef AFS_PTHREAD_ENV
587 if (checkAbortByTaskId(taskId)) {
588 TLog(taskId, "Callout routine has been aborted\n");
589 if (kill(cpid, SIGKILL)) /* Cancel callout */
590 ErrorLog(0, taskId, errno, 0,
591 "Kill of callout process %d failed\n", cpid);
596 clearStatus(taskId, CALL_WAIT);
600 * print out prompt to operator
602 * PromptForTape only.
606 PrintPrompt(flag, name, dumpid)
610 char tapename[BU_MAXTAPELEN + 32];
613 TAPENAME(tapename, name, dumpid);
615 printf("******* OPERATOR ATTENTION *******\n");
616 printf("Device : %s \n", globalTapeConfig.device);
619 case READOPCODE: /* mount for restore */
620 printf("Please put in tape %s for reading", tapename);
623 case APPENDOPCODE: /* mount for dump (appends) */
625 dn = extractDumpName(name);
628 printf("Please put in last tape of dump set for appending dump");
631 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
635 case WRITEOPCODE: /* mount for dump */
636 if (strcmp(name, "") == 0)
637 printf("Please put in tape for writing");
639 /* The name is what we are going to label the tape as */
641 printf("Please put in tape %s for writing", tapename);
644 case LABELOPCODE: /* mount for labeltape */
645 printf("Please put in tape to be labelled as %s", tapename);
648 case READLABELOPCODE: /* mount for readlabel */
649 printf("Please put in tape whose label is to be read");
652 case SCANOPCODE: /* mount for scantape */
653 if (strcmp(name, "") == 0)
654 printf("Please put in tape to be scanned");
656 printf("Please put in tape %s for scanning", tapename);
659 case RESTOREDBOPCODE: /* Mount for restoredb */
660 printf("Please insert a tape %s for the database restore", tapename);
663 case SAVEDBOPCODE: /* Mount for savedb */
664 printf("Please insert a writeable tape %s for the database dump",
671 printf(" and hit return when done\n");
675 * Prompt the operator to change the tape.
676 * Use to be a void routine but now returns an error. Some calls
677 * don't use the error code.
679 * only external clients are in recoverDb.c. Was static PA
682 PromptForTape(flag, name, dbDumpId, taskId, tapecount)
685 afs_uint32 dbDumpId; /* Specific dump ID - If non-zero */
689 register afs_int32 code = 0;
694 int cpid, status, rcpid;
696 if (checkAbortByTaskId(taskId))
697 ERROR_EXIT(TC_ABORTEDBYREQUEST);
700 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
702 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
704 CallOut = (opencallout ? 1 : 0);
706 setStatus(taskId, CALL_WAIT);
709 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
710 dbDumpId, tapecount);
712 CallOut = 0; /* prompt at screen */
714 while (CallOut) { /* Check if callout routine finished */
716 rcpid = waitpid(cpid, &status, WNOHANG);
720 else if (WIFEXITED(status))
721 wcode = WEXITSTATUS(status);
726 break; /* All done */
727 } else if (wcode == 1) {
728 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
729 } else if ((flag == READOPCODE) && (wcode == 3)) {
730 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
733 "Callout routine has exited with code %d: will prompt\n",
735 CallOut = 0; /* Switch to keyboard input */
739 /* if waitpid experienced an error, we prompt */
740 if (rcpid == -1 && errno != EINTR) {
741 com_err(whoami, errno,
742 "Error waiting for callout script to terminate.");
744 "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 code, tcode;
1250 afs_int32 headBytes, tailBytes, w;
1252 afs_int32 nbytes; /* # bytes data in last tape block read */
1253 struct volumeHeader tapeVolTrailer;
1256 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1257 struct tc_restoreDesc *Restore;
1258 struct dumpNode *nodePtr;
1259 struct butm_tapeInfo *tapeInfoPtr;
1261 afs_int32 origVolID;
1263 nodePtr = rparamsPtr->nodePtr;
1264 taskId = nodePtr->taskID;
1265 Restore = nodePtr->restores;
1266 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1267 origVolName = Restore[rparamsPtr->frag].oldName;
1268 origVolID = Restore[rparamsPtr->frag].origVid;
1270 /* Read the volume one fragment at a time */
1271 while (rparamsPtr->frag < nodePtr->arraySize) {
1273 curChunk = BIGCHUNK + 1; /* Check if should abort */
1275 /* Read the volume fragment one block at a time until
1276 * find a volume trailer
1282 while (moretoread) {
1283 /* Fill the circular buffer with tape blocks
1284 * Search for volume trailer in the process.
1289 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1290 BUTM_BLKSIZE, &nbytes);
1292 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1293 "Can't read FileData on tape %s\n",
1294 rparamsPtr->mntTapeName);
1297 curChunk += BUTM_BLKSIZE;
1299 /* Periodically update status structure and check if should abort */
1300 if (curChunk > BIGCHUNK) {
1304 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1307 if (checkAbortByTaskId(taskId))
1308 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1311 /* step to next block in buffer */
1313 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1315 /* If this is the end of the volume, the exit the loop */
1316 if ((nbytes != BUTM_BLKSIZE)
1319 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1323 } while (moretoread && (buf != endRbuf));
1325 /* Write the buffer upto (but not including) the last read block
1326 * If volume is completely read, then leave the last two blocks.
1328 lastbuf = endWbuf = pbuf;
1329 if (!moretoread && (endWbuf != startWbuf))
1330 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1332 for (buf = startWbuf; buf != endWbuf;
1333 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1334 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1335 if (w != BUTM_BLKSIZE) {
1336 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1339 totalWritten += BUTM_BLKSIZE;
1342 /* Setup pointers to refill buffer */
1343 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1345 startWbuf = endWbuf;
1348 /* lastbuf is last block read and it has nbytes of data
1349 * startWbuf is the 2nd to last block read
1350 * Seach for the volume trailer in these two blocks.
1352 if (lastbuf == startWbuf)
1354 FindVolTrailer2(NULL, 0, &headBytes,
1355 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1359 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1360 &headBytes, bufferBlock[lastbuf].data, nbytes,
1361 &tailBytes, &tapeVolTrailer);
1363 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1364 "Missing volume trailer on tape %s\n",
1365 rparamsPtr->mntTapeName);
1366 ERROR_EXIT(TC_MISSINGTRAILER);
1369 /* Now rx_write the data in the last two blocks */
1371 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1372 if (w != headBytes) {
1373 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1376 totalWritten += headBytes;
1379 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1380 if (w != tailBytes) {
1381 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1384 totalWritten += tailBytes;
1387 /* Exit the loop if the volume is not continued on next tape */
1388 if (!tapeVolTrailer.contd)
1389 break; /* We've read the entire volume */
1391 /* Volume is continued on next tape.
1392 * Step to the next volume fragment and prompt for its tape.
1393 * When a volume has multiple frags, those frags are on different
1394 * tapes. So we know that we need to prompt for a tape.
1397 if (rparamsPtr->frag >= nodePtr->arraySize)
1400 unmountTape(taskId, tapeInfoPtr);
1401 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1402 rparamsPtr->tapeID =
1403 (Restore[rparamsPtr->frag].
1404 initialDumpId ? Restore[rparamsPtr->frag].
1405 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1407 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1408 rparamsPtr->tapeID, 1);
1412 /* Position to the frag and read the volume header */
1414 GetVolumeHead(taskId, tapeInfoPtr,
1415 Restore[rparamsPtr->frag].position, origVolName,
1418 ErrorLog(0, taskId, code, 0,
1419 "Can't find volume %s (%u) on tape %s\n", origVolName,
1420 origVolID, rparamsPtr->mntTapeName);
1421 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1430 * Find all the volumes on a specific tape and mark them to skip.
1432 SkipTape(Restore, size, index, tapename, tapeid, taskid)
1433 struct tc_restoreDesc *Restore;
1434 afs_int32 size, index, tapeid, taskid;
1439 for (i = index; i < size; i++) {
1440 if (Restore[i].flags & RDFLAG_SKIP)
1443 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1445 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1446 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);
1476 xbsaRestoreVolume(taskId, restoreInfo, rparamsPtr)
1478 struct tc_restoreDesc *restoreInfo;
1479 struct restoreParams *rparamsPtr;
1481 afs_int32 code = 0, rc;
1483 afs_int32 newServer, newPart, newVolId;
1485 int restoreflags, havetrans = 0, startread = 0;
1486 afs_int32 bytesRead, endData = 0;
1488 struct budb_dumpEntry dumpEntry;
1489 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1490 struct volumeHeader volHeader, hostVolHeader;
1492 if (restoretofile) {
1493 restoretofilefd = fopen(restoretofile, "w+");
1496 dumpID = restoreInfo->dbDumpId;
1498 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1500 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1505 /* ADSM servers restore ADSM and BUTA dumps */
1506 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1507 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1509 "The dump requested by this restore operation for the "
1510 "volumeset is incompatible with this instance of butc\n");
1511 /* Skip the entire dump (one dump per tape) */
1512 ERROR_EXIT(TC_SKIPTAPE);
1515 /* make sure we are connected to the correct server. */
1516 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1517 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1519 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1520 && !forcemultiple) {
1522 "Dump %d is on server %s but butc is connected "
1523 "to server %s (attempting to restore)\n", dumpID,
1524 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1527 "Dump %d is on server %s but butc is connected "
1528 "to server %s (switching servers)\n", dumpID,
1529 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1531 rc = InitToServer(taskId, &butxInfo,
1532 (char *)dumpEntry.tapes.tapeServer);
1533 if (rc != XBSA_SUCCESS)
1534 ERROR_EXIT(TC_SKIPTAPE);
1538 /* Start a transaction and query the server for the correct fileset dump */
1539 rc = xbsa_BeginTrans(&butxInfo);
1540 if (rc != XBSA_SUCCESS) {
1541 ELog(taskId, "Unable to create a new transaction\n");
1542 ERROR_EXIT(TC_SKIPTAPE);
1546 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1547 sprintf(dumpIdStr, "/%d", dumpID);
1548 strcpy(volumeNameStr, "/");
1549 strcat(volumeNameStr, restoreInfo->oldName);
1550 } else { /* new butc names */
1551 extern char *butcdumpIdStr;
1552 strcpy(dumpIdStr, butcdumpIdStr);
1553 sprintf(volumeNameStr, "/%d", dumpID);
1554 strcat(volumeNameStr, "/");
1555 strcat(volumeNameStr, restoreInfo->oldName);
1558 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1559 if (rc != XBSA_SUCCESS) {
1561 "Unable to locate object (%s) of dump (%s) on the server\n",
1562 volumeNameStr, dumpIdStr);
1566 rc = xbsa_EndTrans(&butxInfo);
1568 if (rc != XBSA_SUCCESS) {
1569 ELog(taskId, "Unable to terminate the current transaction\n");
1573 if (checkAbortByTaskId(taskId))
1574 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1576 /* Now start a transaction on the volume to restore and read the
1577 * volumeheader. We do this before starting a transaction on
1578 * volserver to restore the volume because the XBSA server may take
1579 * a while to mount and seek to the volume causing the volserver to
1582 rc = xbsa_BeginTrans(&butxInfo);
1583 if (rc != XBSA_SUCCESS) {
1584 ELog(taskId, "Unable to create a new transaction\n");
1585 ERROR_EXIT(TC_SKIPTAPE);
1589 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1590 sizeof(volHeader), &bytesRead, &endData);
1591 if (restoretofile && (bytesRead > 0)) {
1592 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1594 if (rc != XBSA_SUCCESS) {
1596 "Unable to begin reading of the volume from the server\n");
1601 if ((bytesRead != sizeof(volHeader)) || endData) {
1603 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1604 bytesRead, sizeof(volHeader));
1605 ERROR_EXIT(TC_BADVOLHEADER);
1608 /* convert and check the volume header */
1609 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1611 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1615 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1616 || (restoreInfo->origVid
1617 && (hostVolHeader.volumeID != restoreInfo->origVid))
1618 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1619 ERROR_EXIT(TC_BADVOLHEADER);
1621 /* Set up prior restoring volume data */
1622 newVolName = restoreInfo->newName;
1623 newVolId = restoreInfo->vid;
1624 newServer = restoreInfo->hostAddr;
1625 newPart = restoreInfo->partition;
1627 if ((restoreInfo->dumpLevel == 0)
1628 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1629 restoreflags |= RV_FULLRST;
1630 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1631 restoreflags |= RV_OFFLINE;
1633 if (checkAbortByTaskId(taskId))
1634 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1636 /* Start the restore of the volume data. This is the code we want to return */
1638 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1639 restoreflags, xbsaRestoreVolumeData,
1640 (char *)rparamsPtr);
1643 rc = xbsa_ReadObjectEnd(&butxInfo);
1644 if (rc != XBSA_SUCCESS) {
1646 "Unable to terminate reading of the volume from the server\n");
1652 rc = xbsa_EndTrans(&butxInfo);
1653 if (rc != XBSA_SUCCESS) {
1654 ELog(taskId, "Unable to terminate the current transaction\n");
1660 if (restoretofile && restoretofilefd) {
1661 fclose(restoretofilefd);
1667 restoreVolume(taskId, restoreInfo, rparamsPtr)
1669 struct tc_restoreDesc *restoreInfo;
1670 struct restoreParams *rparamsPtr;
1672 afs_int32 code = 0, rc;
1673 afs_int32 newServer, newPart, newVolId;
1677 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1678 struct budb_dumpEntry dumpEntry;
1680 /* Check if we need a tape and prompt for one if so */
1682 (restoreInfo->initialDumpId ? restoreInfo->
1683 initialDumpId : restoreInfo->dbDumpId);
1684 if ((rparamsPtr->frag == 0)
1685 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1686 || (tapeID != rparamsPtr->tapeID)) {
1687 /* Unmount the previous tape */
1688 unmountTape(taskId, tapeInfoPtr);
1690 /* Remember this new tape */
1691 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1692 rparamsPtr->tapeID = tapeID;
1694 /* Mount a new tape */
1695 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1697 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1702 /* Seek to the correct spot and read the header information */
1703 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1704 restoreInfo->oldName, restoreInfo->origVid);
1708 /* Set up prior restoring volume data */
1709 newVolName = restoreInfo->newName;
1710 newVolId = restoreInfo->vid;
1711 newServer = restoreInfo->hostAddr;
1712 newPart = restoreInfo->partition;
1714 if ((restoreInfo->dumpLevel == 0)
1715 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1716 restoreflags |= RV_FULLRST;
1717 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1718 restoreflags |= RV_OFFLINE;
1720 if (checkAbortByTaskId(taskId))
1721 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1723 /* Start the restore of the volume data. This is the code we
1727 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1728 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1730 /* Read the FileEnd marker for the volume and step to next FM */
1731 rc = butm_ReadFileEnd(tapeInfoPtr);
1733 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1734 "Can't read EOF on tape\n");
1742 * created as a LWP by the server stub, <newNode> is a pointer to all
1743 * the parameters Restorer needs
1746 struct dumpNode *newNode;
1748 afs_int32 code = 0, tcode, rc;
1752 struct butm_tapeInfo tapeInfo;
1753 struct tc_restoreDesc *Restore;
1754 struct tc_restoreDesc *RestoreDesc;
1755 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 rc = 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);
1926 /* this is just scaffolding, creates new tape label with name <tapeName> */
1928 GetNewLabel(tapeInfoPtr, pName, AFSName, tapeLabel)
1929 struct butm_tapeInfo *tapeInfoPtr;
1930 char *pName, *AFSName;
1931 struct butm_tapeLabel *tapeLabel;
1934 struct timezone tzp;
1937 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1940 butm_GetSize(tapeInfoPtr, &size);
1942 size = globalTapeConfig.capacity;
1944 size = 0; /* no tape size */
1946 gettimeofday(&tp, &tzp);
1948 tapeLabel->structVersion = CUR_TAPE_VERSION;
1949 tapeLabel->creationTime = tp.tv_sec;
1950 tapeLabel->size = size;
1951 tapeLabel->expirationDate = 0; /* 1970 sometime */
1952 tapeLabel->dumpPath[0] = 0; /* no path name */
1953 tapeLabel->useCount = 0;
1954 strcpy(tapeLabel->AFSName, AFSName);
1955 strcpy(tapeLabel->pName, pName);
1956 strcpy(tapeLabel->cell, globalCellName);
1957 strcpy(tapeLabel->comment, "AFS Backup Software");
1958 strcpy(tapeLabel->creator.name, "AFS 3.6");
1959 strcpy(tapeLabel->creator.instance, "");
1960 strcpy(tapeLabel->creator.cell, globalCellName);
1963 /* extracts trailer out of buffer, nbytes is set to total data in buffer - trailer size */
1965 ExtractTrailer(buffer, size, nbytes, volTrailerPtr)
1969 struct volumeHeader *volTrailerPtr;
1973 struct volumeHeader tempTrailer;
1977 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1979 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1981 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1987 return 1; /* saw the trailer */
1993 return 0; /* did not see the trailer */
1997 FindVolTrailer(buffer, size, dSize, volTrailerPtr)
2000 struct volumeHeader *volTrailerPtr;
2001 afs_int32 *dSize; /* dataSize */
2003 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>
2230 Labeller(labelIfPtr)
2231 struct labelTapeIf *labelIfPtr;
2233 struct tc_tapeLabel *label = &labelIfPtr->label;
2235 struct butm_tapeLabel newTapeLabel;
2236 struct butm_tapeInfo tapeInfo;
2240 taskId = labelIfPtr->taskId;
2241 setStatus(taskId, DRIVE_WAIT);
2242 EnterDeviceQueue(deviceLatch);
2243 clearStatus(taskId, DRIVE_WAIT);
2246 TLog(taskId, "Labeltape\n");
2248 memset(&tapeInfo, 0, sizeof(tapeInfo));
2249 tapeInfo.structVersion = BUTM_MAJORVERSION;
2250 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2252 ErrorLog(0, taskId, code, tapeInfo.error,
2253 "Can't initialize the tape module\n");
2257 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2259 newTapeLabel.size = label->size;
2261 newTapeLabel.size = globalTapeConfig.capacity;
2263 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2268 if (code == TC_ABORTEDBYREQUEST) {
2269 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2270 clearStatus(taskId, ABORT_REQUEST);
2271 setStatus(taskId, ABORT_DONE);
2273 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2274 setStatus(taskId, TASK_ERROR);
2276 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2277 TNAME(&newTapeLabel), newTapeLabel.size);
2279 setStatus(labelIfPtr->taskId, TASK_DONE);
2282 LeaveDeviceQueue(deviceLatch);
2287 * print out the tape label.
2290 PrintTapeLabel(labelptr)
2291 struct butm_tapeLabel *labelptr;
2293 char tapeName[BU_MAXTAPELEN + 32];
2295 printf("Tape label\n");
2296 printf("----------\n");
2297 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2298 printf("permanent tape name = %s\n", tapeName);
2299 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2300 printf("AFS tape name = %s\n", tapeName);
2301 printf("creationTime = %s", ctime(&labelptr->creationTime));
2302 if (labelptr->expirationDate)
2303 printf("expirationDate = %s", cTIME(&labelptr->expirationDate));
2304 printf("cell = %s\n", labelptr->cell);
2305 printf("size = %u Kbytes\n", labelptr->size);
2306 printf("dump path = %s\n", labelptr->dumpPath);
2308 if (labelptr->structVersion >= TAPE_VERSION_3) {
2309 printf("dump id = %u\n", labelptr->dumpid);
2310 printf("useCount = %d\n", labelptr->useCount);
2312 printf("-- End of tape label --\n\n");
2316 * Read the label from a tape.
2317 * Currently prints out a "detailed" summary of the label but passes
2318 * back only selected fields.
2322 struct tc_tapeLabel *label;
2324 struct butm_tapeLabel newTapeLabel;
2325 struct butm_tapeInfo tapeInfo;
2329 int interactiveFlag;
2332 EnterDeviceQueue(deviceLatch);
2333 taskId = allocTaskId(); /* reqd for lower level rtns */
2336 TLog(taskId, "Readlabel\n");
2338 memset(&tapeInfo, 0, sizeof(tapeInfo));
2339 tapeInfo.structVersion = BUTM_MAJORVERSION;
2340 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2342 ErrorLog(0, taskId, code, tapeInfo.error,
2343 "Can't initialize the tape module\n");
2346 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2348 interactiveFlag = autoQuery;
2351 if (interactiveFlag) {
2352 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2356 interactiveFlag = 1;
2359 code = butm_Mount(&tapeInfo, "");
2361 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2367 unmountTape(taskId, &tapeInfo);
2370 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2372 if (code == BUTM_NOLABEL) {
2373 printf("Tape is unlabelled\n");
2376 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2380 /* copy the fields to be passed to the caller */
2381 label->size = newTapeLabel.size;
2382 label->tapeId = newTapeLabel.dumpid;
2383 strcpy(label->afsname, newTapeLabel.AFSName);
2384 strcpy(label->pname, newTapeLabel.pName);
2387 expir = ExpirationDate(newTapeLabel.dumpid);
2389 newTapeLabel.expirationDate = expir;
2391 PrintTapeLabel(&newTapeLabel);
2394 unmountTape(taskId, &tapeInfo);
2396 if (code == TC_ABORTEDBYREQUEST)
2397 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2398 else if (code && (code != BUTM_NOLABEL))
2399 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2401 TLog(taskId, "ReadLabel: Finished\n");
2403 LeaveDeviceQueue(deviceLatch);
2407 /* Function to read volume header and trailer structure from tape, taking
2408 into consideration, different word alignment rules.
2411 readVolumeHeader(buffer, bufloc, header)
2413 char *buffer; /* buffer to read header from */
2414 /*in */ afs_int32 bufloc;
2415 /* header's location in buffer */
2416 /*out */ struct volumeHeader *header;
2417 /* header structure */
2420 struct volumeHeader vhptr, *tempvhptr;
2421 afs_int32 firstSplice = (afs_int32) & vhptr.pad - (afs_int32) & vhptr;
2422 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2423 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2425 /* Four cases are to be handled
2427 * Volume Header (byte alignment)
2428 * -----------------------
2435 * -----------------------
2437 * Case 2 and Case 3 are identical cases and handled the same way.
2438 * Case 1 and Case 4 are separate cases. In one case the pad needs
2439 * to be removed and in the other, it needs to be spliced in. The
2440 * four cases are handled as follows
2442 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2443 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2444 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2445 /* Handle Cases 2 & 3 */
2446 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2447 HEADER_CHECKS(vhptr, header);
2450 memset(&vhptr, 0, sizeof(struct volumeHeader));
2451 memcpy(&vhptr, buffer + bufloc, firstSplice);
2452 memset(&vhptr.pad, 0, padLen);
2453 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2454 HEADER_CHECKS(vhptr, header);
2457 memset(&vhptr, 0, sizeof(struct volumeHeader));
2458 memcpy(&vhptr, buffer + bufloc, firstSplice);
2459 memcpy(&vhptr + firstSplice, buffer + bufloc + firstSplice + padLen,
2461 HEADER_CHECKS(vhptr, header);
2464 return (TC_BADVOLHEADER);