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>
14 #include <sys/types.h>
21 #include <netinet/in.h>
25 #include <afs/procmgmt.h>
31 #include <afs/tcdata.h>
32 #include <afs/bubasics.h> /* PA */
33 #include <afs/budb_client.h>
34 #include <afs/bucoord_prototypes.h>
35 #include <afs/butm_prototypes.h>
36 #include <afs/volser.h>
37 #include <afs/volser_prototypes.h>
38 #include <afs/com_err.h>
39 #include "error_macros.h"
40 #include <afs/afsutil.h>
42 #include "butc_xbsa.h"
43 #include "butc_internal.h"
45 /* GLOBAL CONFIGURATION PARAMETERS */
46 extern int queryoperator;
47 extern int tapemounted;
48 extern char *opencallout;
49 extern char *closecallout;
51 extern char *extractDumpName(char *);
52 extern int BufferSize; /* Size in B stored for header info */
53 FILE *restoretofilefd;
55 extern char *restoretofile;
56 extern int forcemultiple;
59 /* XBSA Global Parameters */
62 struct butx_transactionInfo butxInfo;
65 static struct TapeBlock { /* A 16KB tapeblock */
66 char mark[BUTM_HDRSIZE]; /* Header info */
67 char data[BUTM_BLKSIZE]; /* data */
70 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
71 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
74 * Need to re-write to:
75 * 1) non-interactive tape handling (optional)
76 * 2) compute tape and volume sizes for the database
77 * 3) compute and use tape id's for tape tracking (put on tape label)
78 * 4) status management
81 /* All the relevant info shared between Restorer and restoreVolume */
82 struct restoreParams {
83 struct dumpNode *nodePtr;
85 char mntTapeName[BU_MAXTAPELEN];
87 struct butm_tapeInfo *tapeInfoPtr;
90 /* Abort checks are done after each BIGCHUNK of data transfer */
91 #define BIGCHUNK 102400
93 #define HEADER_CHECKS(vhptr, header) \
95 afs_int32 magic, versionflags; \
97 versionflags = ntohl(vhptr.versionflags); \
98 if ( versionflags == TAPE_VERSION_0 || \
99 versionflags == TAPE_VERSION_1 || \
100 versionflags == TAPE_VERSION_2 || \
101 versionflags == TAPE_VERSION_3 || \
102 versionflags == TAPE_VERSION_4 ) { \
104 magic = ntohl(vhptr.magic); /* another sanity check */ \
105 if (magic == TC_VOLBEGINMAGIC || \
106 magic == TC_VOLENDMAGIC || \
107 magic == TC_VOLCONTD ) { \
109 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
112 } /* versionflags */ \
116 extern FILE *ErrorlogIO;
117 extern FILE *centralLogIO;
118 extern FILE *lastLogIO;
119 extern afs_int32 lastPass; /* Set true during last pass of dump */
120 extern int debugLevel;
121 extern int autoQuery;
122 extern struct tapeConfig globalTapeConfig;
123 extern struct deviceSyncNode *deviceLatch;
124 extern char globalCellName[];
128 /* forward declaration */
129 afs_int32 readVolumeHeader(char *, afs_int32, struct volumeHeader *);
130 int FindVolTrailer(char *, afs_int32, afs_int32 *, struct volumeHeader *);
131 int FindVolTrailer2(char *, afs_int32, afs_int32 *, char *, afs_int32,
132 afs_int32 *, struct volumeHeader *);
133 int SkipVolume(struct tc_restoreDesc *, afs_int32, afs_int32, afs_int32,
138 /* The on-disk volume header or trailer can differ in size from platform to platform */
139 static struct TapeBlock tapeBlock;
140 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
143 PrintLogStr(FILE *log, afs_int32 error1, afs_int32 error2, char *str)
147 fprintf(log, "%s", str);
152 err1 = "Volume needs to be salvaged";
155 err1 = "Bad vnode number quoted";
158 err1 = "Volume not attached, does not exist, or not on line";
161 err1 = "Volume already exists";
164 err1 = "Volume is not in service";
167 err1 = "Volume is off line";
170 err1 = "Volume is already on line";
173 err1 = "Partition is full";
176 err1 = "Volume max quota exceeded";
179 err1 = "Volume temporarily unavailable";
182 err1 = "Volume has moved to another server";
185 err1 = (char *)afs_error_message(error1);
186 err2 = (char *)afs_error_table_name(error1);
190 fprintf(log, " Possible communication failure");
192 fprintf(log, " %s: %s", err2, err1);
194 fprintf(log, ": %s", afs_error_message(error2));
201 TapeLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
205 char tbuffer[32], *timestr;
208 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
211 fprintf(logIO, "%s: ", timestr);
213 fprintf(logIO, "Task %u: ", task);
214 PrintLogStr(logIO, error1, error2, str);
216 if (lastPass && lastLogIO) {
217 fprintf(lastLogIO, "%s: ", timestr);
219 fprintf(lastLogIO, "Task %u: ", task);
220 PrintLogStr(lastLogIO, error1, error2, str);
223 /* Now print to the screen if debug level requires */
224 if (debug <= debugLevel)
225 PrintLogStr(stdout, error1, error2, str);
229 TapeLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
236 afs_vsnprintf(tmp, sizeof(tmp), fmt, ap);
239 TapeLogStr(debug, task, error1, error2, tmp);
243 TLog(afs_int32 task, char *fmt, ...)
249 afs_vsnprintf(tmp, sizeof(tmp), fmt, ap);
252 /* Sends message to TapeLog and stdout */
253 TapeLogStr(0, task, 0, 0, tmp);
257 ErrorLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
261 char tbuffer[32], *timestr;
264 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
266 fprintf(ErrorlogIO, "%s: ", timestr);
268 /* Print the time and task number */
270 fprintf(ErrorlogIO, "Task %u: ", task);
272 PrintLogStr(ErrorlogIO, error1, error2, errStr);
273 TapeLogStr(debug, task, error1, error2, errStr);
277 ErrorLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
284 afs_vsnprintf(tmp, sizeof(tmp), fmt, ap);
287 ErrorLogStr(debug, task, error1, error2, tmp);
292 ELog(afs_int32 task, char *fmt, ...)
298 afs_vsnprintf(tmp, sizeof(tmp), fmt, ap);
301 /* Sends message to ErrorLog, TapeLog and stdout */
302 ErrorLog(0, task, 0, 0, tmp);
305 /* first proc called by anybody who intends to use the device */
307 EnterDeviceQueue(struct deviceSyncNode *devLatch)
309 ObtainWriteLock(&(devLatch->lock));
310 devLatch->flags = TC_DEVICEINUSE;
313 /* last proc called by anybody finishing using the device */
315 LeaveDeviceQueue(struct deviceSyncNode *devLatch)
318 ReleaseWriteLock(&(devLatch->lock));
321 #define BELLTIME 60 /* 60 seconds before a bell rings */
322 #define BELLCHAR 7 /* ascii for bell */
325 #ifdef AFS_PTHREAD_ENV
327 /* WaitForKeystroke : Wait until a key has been struck or time (secconds)
328 * runs out and return to caller. The NT version of this function will return
329 * immediately after a key has been pressed (doesn't wait for cr).
331 * seconds: wait for <seconds> seconds before returning. If seconds < 0,
334 * 1: Keyboard input available
335 * 0: seconds elapsed. Timeout.
337 * STOLEN FROM LWP_WaitForKeystroke()
340 WaitForKeystroke(int seconds)
342 time_t startTime, nowTime;
344 struct timeval twait;
353 /* check if we have a keystroke */
359 /* sleep for LWP_KEYSTROKE_DELAY ms and let other
361 select(0, 0, 0, 0, &twait);
363 if (seconds > 0) { /* we only worry about elapsed time if
364 * not looping forever (seconds < 0) */
366 timeleft = seconds - difftime(nowTime, startTime);
368 } while (timeleft > 0);
371 #else /* AFS_NT40)ENV */
372 extern int WaitForKeystroke(int);
374 * STOLEN FROM LWP_WaitForKeystroke()
377 WaitForKeystroke(int seconds)
381 struct timeval twait;
382 struct timeval *tp = NULL;
384 #ifdef AFS_LINUX20_ENV
385 if (stdin->_IO_read_ptr < stdin->_IO_read_end)
392 FD_SET(fileno(stdin), &rdfds);
395 twait.tv_sec = seconds;
399 code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
400 return (code == 1) ? 1 : 0;
404 /* GetResponseKey() - Waits for a specified period of time and
405 * returns a char when one has been typed by the user.
407 * seconds - how long to wait for a key press.
408 * *key - char entered by user
410 * 0 - Time ran out before the user typed a key.
411 * 1 - Valid char is being returned.
413 * STOLEN FROM LWP_GetResponseKey();
416 GetResponseKey(int seconds, char *key)
421 return 0; /* need space to store char */
422 fflush(stdin); /* flush all existing data and start anew */
424 rc = WaitForKeystroke(seconds);
425 if (rc == 0) { /* time ran out */
430 /* now read the char. */
432 *key = getche(); /* get char and echo it to screen */
438 #endif /* AFS_PTHREAD_ENV */
444 * only external clients are in recoverDb.c. Was static. PA
454 #ifdef AFS_PTHREAD_ENV
455 w = WaitForKeystroke(0);
457 w = LWP_WaitForKeystroke(0);
458 #endif /* AFS_PTHREAD_ENV */
465 #endif /* AFS_NT40_ENV */
473 callOutRoutine(afs_int32 taskId, char *tapePath, int flag, char *name,
474 afs_uint32 dbDumpId, int tapecount)
490 callOut = opencallout;
493 strcpy(Sopcode, "restore");
496 strcpy(Sopcode, "appenddump");
499 strcpy(Sopcode, "dump");
502 strcpy(Sopcode, "labeltape");
504 case READLABELOPCODE:
505 strcpy(Sopcode, "readlabel");
508 strcpy(Sopcode, "scantape");
510 case RESTOREDBOPCODE:
511 strcpy(Sopcode, "restoredb");
514 strcpy(Sopcode, "savedb");
517 strcpy(Sopcode, "unmount");
518 callOut = closecallout;
521 strcpy(Sopcode, "unknown");
525 if (!callOut) /* no script to call */
528 strcpy(ScallOut, callOut);
529 CO_argv[0] = ScallOut;
531 strcpy(StapePath, tapePath);
532 CO_argv[1] = StapePath;
534 CO_argv[2] = Sopcode;
536 if (flag == CLOSEOPCODE) {
539 sprintf(Scount, "%d", tapecount);
542 /* The tape label name - special case labeltape */
543 if (!name || (strcmp(name, "") == 0)) /* no label */
544 strcpy(Stape, "none");
545 else { /* labeltape */
547 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
548 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
557 strcpy(Sdumpid, "none");
559 sprintf(Sdumpid, "%u", dbDumpId);
560 CO_argv[5] = Sdumpid;
567 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
569 ErrorLog(0, taskId, errno, 0,
570 "Call to %s outside routine %s failed\n", Sopcode, callOut);
579 * Unmounts a tape and prints a warning if it can't unmount it.
580 * Regardless of error, the closecallout routine will be called
581 * (unless a tape is not mounted in the first place).
584 unmountTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr)
587 int cpid, status, rcpid;
589 code = butm_Dismount(tapeInfoPtr);
590 if (code && (code != BUTM_NOMOUNT))
591 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
592 "Warning: Can't close tape\n");
594 if (tapemounted && closecallout) {
595 setStatus(taskId, CALL_WAIT);
598 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
600 while (cpid) { /* Wait until return */
602 rcpid = waitpid(cpid, &status, WNOHANG);
607 if (rcpid == -1 && errno != EINTR) {
609 afs_com_err(whoami, errno,
610 "Error waiting for callout script to terminate.");
613 #ifdef AFS_PTHREAD_ENV
619 if (checkAbortByTaskId(taskId)) {
620 TLog(taskId, "Callout routine has been aborted\n");
621 if (kill(cpid, SIGKILL)) /* Cancel callout */
622 ErrorLog(0, taskId, errno, 0,
623 "Kill of callout process %d failed\n", cpid);
628 clearStatus(taskId, CALL_WAIT);
632 * print out prompt to operator
634 * PromptForTape only.
638 PrintPrompt(int flag, char *name, int dumpid)
640 char tapename[BU_MAXTAPELEN + 32];
643 TAPENAME(tapename, name, dumpid);
645 printf("******* OPERATOR ATTENTION *******\n");
646 printf("Device : %s \n", globalTapeConfig.device);
649 case READOPCODE: /* mount for restore */
650 printf("Please put in tape %s for reading", tapename);
653 case APPENDOPCODE: /* mount for dump (appends) */
655 dn = extractDumpName(name);
658 printf("Please put in last tape of dump set for appending dump");
661 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
665 case WRITEOPCODE: /* mount for dump */
666 if (strcmp(name, "") == 0)
667 printf("Please put in tape for writing");
669 /* The name is what we are going to label the tape as */
671 printf("Please put in tape %s for writing", tapename);
674 case LABELOPCODE: /* mount for labeltape */
675 printf("Please put in tape to be labelled as %s", tapename);
678 case READLABELOPCODE: /* mount for readlabel */
679 printf("Please put in tape whose label is to be read");
682 case SCANOPCODE: /* mount for scantape */
683 if (strcmp(name, "") == 0)
684 printf("Please put in tape to be scanned");
686 printf("Please put in tape %s for scanning", tapename);
689 case RESTOREDBOPCODE: /* Mount for restoredb */
690 printf("Please insert a tape %s for the database restore", tapename);
693 case SAVEDBOPCODE: /* Mount for savedb */
694 printf("Please insert a writeable tape %s for the database dump",
701 printf(" and hit return when done\n");
705 * Prompt the operator to change the tape.
706 * Use to be a void routine but now returns an error. Some calls
707 * don't use the error code.
709 * only external clients are in recoverDb.c. Was static PA
712 PromptForTape(int flag, char *name, afs_uint32 dbDumpId, afs_uint32 taskId,
715 register afs_int32 code = 0;
720 int cpid, status, rcpid;
722 if (checkAbortByTaskId(taskId))
723 ERROR_EXIT(TC_ABORTEDBYREQUEST);
726 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
728 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
730 CallOut = (opencallout ? 1 : 0);
732 setStatus(taskId, CALL_WAIT);
735 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
736 dbDumpId, tapecount);
738 CallOut = 0; /* prompt at screen */
740 while (CallOut) { /* Check if callout routine finished */
742 rcpid = waitpid(cpid, &status, WNOHANG);
746 else if (WIFEXITED(status))
747 wcode = WEXITSTATUS(status);
752 break; /* All done */
753 } else if (wcode == 1) {
754 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
755 } else if ((flag == READOPCODE) && (wcode == 3)) {
756 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
759 "Callout routine has exited with code %d: will prompt\n",
761 CallOut = 0; /* Switch to keyboard input */
765 /* if waitpid experienced an error, we prompt */
766 if (rcpid == -1 && errno != EINTR) {
767 afs_com_err(whoami, errno,
768 "Error waiting for callout script to terminate.");
770 "Can't get exit status from callout script. will prompt\n");
774 #ifdef AFS_PTHREAD_ENV
780 if (checkAbortByTaskId(taskId)) {
782 ("This tape operation has been aborted by the coordinator.\n");
784 if (kill(cpid, SIGKILL)) /* Cancel callout */
785 ErrorLog(0, taskId, errno, 0,
786 "Kill of callout process %d failed\n", cpid);
788 ERROR_EXIT(TC_ABORTEDBYREQUEST);
794 clearStatus(taskId, CALL_WAIT);
795 setStatus(taskId, OPR_WAIT);
797 PrintPrompt(flag, name, dbDumpId);
799 /* Loop until we get ok to go ahead (or abort) */
801 if (time(0) > start + BELLTIME) {
807 #ifdef AFS_PTHREAD_ENV
808 wcode = GetResponseKey(5, &inchr); /* inchr stores key read */
810 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
812 if (wcode == 1) { /* keyboard input is available */
814 if ((inchr == 'a') || (inchr == 'A')) {
815 printf("This tape operation has been aborted.\n");
816 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
817 } else if ((flag == READOPCODE)
818 && ((inchr == 's') || (inchr == 'S'))) {
819 printf("This tape will be skipped.\n");
820 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
822 break; /* continue */
825 if (checkAbortByTaskId(taskId)) {
827 ("This tape operation has been aborted by the coordinator.\n");
828 ERROR_EXIT(TC_ABORTEDBYREQUEST);
834 printf("Thanks, now proceeding with tape ");
836 case RESTOREDBOPCODE:
842 printf("append writing");
854 case READLABELOPCODE:
855 printf("label reading");
867 printf(" operation.\n");
869 printf("**********************************\n");
871 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
875 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
881 * convert the fields in the tapeVolHeader into host byte order,
882 * placing the converted copy of the structure into the hostVolHeader
884 * tapeVolHeader - points to volume header read from tape
885 * hostVolHeader - pointer to struct for result
887 * hostVolHeader - information in host byte order
891 VolHeaderToHost(struct volumeHeader *hostVolHeader,
892 struct volumeHeader *tapeVolHeader)
894 switch (ntohl(tapeVolHeader->versionflags)) {
896 /* sizes in bytes and fields in host order */
897 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
902 case TAPE_VERSION_3: /* for present */
904 /* sizes in K and fields in network order */
905 /* do the conversion field by field */
907 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
908 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
909 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
910 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
911 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
912 hostVolHeader->server = ntohl(tapeVolHeader->server);
913 hostVolHeader->part = ntohl(tapeVolHeader->part);
914 hostVolHeader->from = ntohl(tapeVolHeader->from);
915 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
916 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
917 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
918 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
919 hostVolHeader->level = ntohl(tapeVolHeader->level);
920 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
921 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
922 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
923 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
927 return (TC_BADVOLHEADER);
933 ReadVolHeader(afs_int32 taskId,
934 struct butm_tapeInfo *tapeInfoPtr,
935 struct volumeHeader *volHeaderPtr)
939 struct volumeHeader volHead;
941 /* Read the volume header */
943 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
946 ErrorLog(0, taskId, code, tapeInfoPtr->error,
947 "Can't read volume header on tape\n");
951 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
953 ErrorLog(0, taskId, code, 0,
954 "Can't find volume header on tape block\n");
958 code = VolHeaderToHost(volHeaderPtr, &volHead);
960 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
969 GetVolumeHead(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
970 afs_int32 position, char *volName, afs_int32 volId)
973 struct volumeHeader tapeVolHeader;
975 /* Position directly to the volume and read the header */
977 code = butm_Seek(tapeInfoPtr, position);
979 ErrorLog(0, taskId, code, tapeInfoPtr->error,
980 "Can't seek to position %u on tape\n", position);
984 code = butm_ReadFileBegin(tapeInfoPtr);
986 ErrorLog(0, taskId, code, tapeInfoPtr->error,
987 "Can't read FileBegin on tape\n");
991 /* Read the volume header */
992 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
996 /* Check if volume header matches */
997 if (strcmp(tapeVolHeader.volumeName, volName))
998 ERROR_EXIT(TC_BADVOLHEADER);
999 if (volId && (tapeVolHeader.volumeID != volId))
1000 ERROR_EXIT(TC_BADVOLHEADER);
1001 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
1002 ERROR_EXIT(TC_BADVOLHEADER);
1005 /* Do a sequential search for the volume */
1008 code = butm_ReadFileBegin(tapeInfoPtr);
1010 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1011 "Can't read FileBegin on tape\n");
1015 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
1017 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1019 /* Test if we found the volume */
1020 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
1021 && (!volId || (volId == tapeVolHeader.volumeID)))
1024 /* skip to the next HW EOF marker */
1025 code = SeekFile(tapeInfoPtr, 1);
1027 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1028 "Can't seek to next EOF on tape\n");
1039 GetRestoreTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
1040 char *tname, afs_int32 tapeID, int prompt)
1042 struct butm_tapeLabel tapeLabel;
1043 afs_int32 code = 0, rc;
1045 struct budb_dumpEntry dumpEntry;
1047 /* Make sure that the dump/tape is not a XBSA dump */
1048 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
1049 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1050 ErrorLog(0, taskId, 0, 0,
1051 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
1052 ERROR_EXIT(TC_SKIPTAPE);
1058 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
1065 code = butm_Mount(tapeInfoPtr, tname);
1067 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
1071 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
1073 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1074 "Can't read tape label\n");
1078 /* Now check the label to see if the tapename matches or tapeids match */
1079 if (strcmp(TNAME(&tapeLabel), tname)
1080 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
1081 && (tapeLabel.dumpid != tapeID))) {
1082 char expectedName[BU_MAXTAPELEN + 32],
1083 gotName[BU_MAXTAPELEN + 32];
1085 TAPENAME(expectedName, tname, tapeID);
1086 LABELNAME(gotName, &tapeLabel);
1088 TapeLog(0, taskId, 0, 0,
1089 "Tape label expected %s, label seen %s\n", expectedName,
1097 unmountTape(taskId, tapeInfoPtr);
1105 xbsaRestoreVolumeData(struct rx_call *call, void *rock)
1109 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
1110 afs_int32 curChunk, rc;
1111 afs_uint32 totalWritten;
1112 afs_int32 headBytes, tailBytes, w;
1114 struct volumeHeader volTrailer;
1115 afs_int32 vtsize = 0;
1117 struct dumpNode *nodePtr;
1118 struct tc_restoreDesc *Restore;
1119 afs_int32 bytesRead, tbuffersize, endData = 0;
1120 char *buffer = (char *)bufferBlock, tbuffer[256];
1122 nodePtr = rparamsPtr->nodePtr;
1123 Restore = nodePtr->restores;
1124 taskId = nodePtr->taskID;
1126 /* Read the volume fragment one block at a time until
1127 * find a volume trailer
1129 curChunk = BIGCHUNK + 1;
1134 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1136 if (restoretofile && (bytesRead > 0)) {
1137 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1139 if (rc != XBSA_SUCCESS) {
1140 ErrorLog(0, taskId, rc, 0,
1141 "Unable to read volume data from the server\n");
1145 /* Periodically update status structure and check if should abort */
1146 curChunk += bytesRead;
1147 if (curChunk > BIGCHUNK) {
1150 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1153 if (checkAbortByTaskId(taskId))
1154 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1157 if (!endData && (bytesRead > 0)) {
1158 /* Fill tbuffer up with data from end of buffer and write
1159 * the remainder of buffer out.
1161 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1162 /* Write out contents of tbuffer */
1164 w = rx_Write(call, tbuffer, tbuffersize);
1165 if (w != tbuffersize) {
1166 ErrorLog(0, taskId, -1, 0,
1167 "Error in RX write: Wrote %d bytes\n", w);
1172 /* fill tbuffer with end of buffer */
1173 bytesRead -= sizeof(tbuffer);
1174 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1175 tbuffersize = sizeof(tbuffer);
1176 /* Write out whatever is left over in buffer */
1178 w = rx_Write(call, buffer, bytesRead);
1179 if (w != bytesRead) {
1180 ErrorLog(0, taskId, -1, 0,
1181 "Error in RX data write: Wrote %d bytes\n",
1188 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1189 /* Copy all of buffer into tbuffer (it will fit) */
1190 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1191 tbuffersize += bytesRead;
1194 /* We need to write some of tbuffer out and fill it with buffer */
1195 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1196 w = rx_Write(call, tbuffer, towrite);
1198 ErrorLog(0, taskId, -1, 0,
1199 "Error in RX write: Wrote %d bytes\n", w);
1205 /* Move the data in tbuffer up */
1206 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1208 /* Now copy buffer in */
1209 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1210 tbuffersize += bytesRead;
1216 /* Pull the volume trailer from the last two buffers */
1218 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1219 &tailBytes, &volTrailer);
1222 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1223 ERROR_EXIT(TC_MISSINGTRAILER);
1226 /* Now rx_write the data in the last two blocks */
1228 w = rx_Write(call, tbuffer, headBytes);
1229 if (w != headBytes) {
1230 ErrorLog(0, taskId, -1, 0,
1231 "Error in RX trail1 write: Wrote %d bytes\n", w);
1237 w = rx_Write(call, buffer, tailBytes);
1238 if (w != tailBytes) {
1239 ErrorLog(0, taskId, -1, 0,
1240 "Error in RX trail2 write: Wrote %d bytes\n", w);
1252 * sends the contents of volume dump to Rx Stream associated
1257 restoreVolumeData(struct rx_call *call, void *rock)
1259 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
1261 afs_uint32 totalWritten = 0;
1263 afs_int32 headBytes, tailBytes, w;
1265 afs_int32 nbytes; /* # bytes data in last tape block read */
1266 struct volumeHeader tapeVolTrailer;
1269 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1270 struct tc_restoreDesc *Restore;
1271 struct dumpNode *nodePtr;
1272 struct butm_tapeInfo *tapeInfoPtr;
1274 afs_int32 origVolID;
1276 nodePtr = rparamsPtr->nodePtr;
1277 taskId = nodePtr->taskID;
1278 Restore = nodePtr->restores;
1279 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1280 origVolName = Restore[rparamsPtr->frag].oldName;
1281 origVolID = Restore[rparamsPtr->frag].origVid;
1283 /* Read the volume one fragment at a time */
1284 while (rparamsPtr->frag < nodePtr->arraySize) {
1286 curChunk = BIGCHUNK + 1; /* Check if should abort */
1288 /* Read the volume fragment one block at a time until
1289 * find a volume trailer
1295 while (moretoread) {
1296 /* Fill the circular buffer with tape blocks
1297 * Search for volume trailer in the process.
1302 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1303 BUTM_BLKSIZE, &nbytes);
1305 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1306 "Can't read FileData on tape %s\n",
1307 rparamsPtr->mntTapeName);
1310 curChunk += BUTM_BLKSIZE;
1312 /* Periodically update status structure and check if should abort */
1313 if (curChunk > BIGCHUNK) {
1317 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1320 if (checkAbortByTaskId(taskId))
1321 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1324 /* step to next block in buffer */
1326 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1328 /* If this is the end of the volume, the exit the loop */
1329 if ((nbytes != BUTM_BLKSIZE)
1332 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1336 } while (moretoread && (buf != endRbuf));
1338 /* Write the buffer upto (but not including) the last read block
1339 * If volume is completely read, then leave the last two blocks.
1341 lastbuf = endWbuf = pbuf;
1342 if (!moretoread && (endWbuf != startWbuf))
1343 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1345 for (buf = startWbuf; buf != endWbuf;
1346 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1347 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1348 if (w != BUTM_BLKSIZE) {
1349 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1352 totalWritten += BUTM_BLKSIZE;
1355 /* Setup pointers to refill buffer */
1356 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1358 startWbuf = endWbuf;
1361 /* lastbuf is last block read and it has nbytes of data
1362 * startWbuf is the 2nd to last block read
1363 * Seach for the volume trailer in these two blocks.
1365 if (lastbuf == startWbuf)
1367 FindVolTrailer2(NULL, 0, &headBytes,
1368 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1372 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1373 &headBytes, bufferBlock[lastbuf].data, nbytes,
1374 &tailBytes, &tapeVolTrailer);
1376 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1377 "Missing volume trailer on tape %s\n",
1378 rparamsPtr->mntTapeName);
1379 ERROR_EXIT(TC_MISSINGTRAILER);
1382 /* Now rx_write the data in the last two blocks */
1384 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1385 if (w != headBytes) {
1386 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1389 totalWritten += headBytes;
1392 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1393 if (w != tailBytes) {
1394 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1397 totalWritten += tailBytes;
1400 /* Exit the loop if the volume is not continued on next tape */
1401 if (!tapeVolTrailer.contd)
1402 break; /* We've read the entire volume */
1404 /* Volume is continued on next tape.
1405 * Step to the next volume fragment and prompt for its tape.
1406 * When a volume has multiple frags, those frags are on different
1407 * tapes. So we know that we need to prompt for a tape.
1410 if (rparamsPtr->frag >= nodePtr->arraySize)
1413 unmountTape(taskId, tapeInfoPtr);
1414 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1415 rparamsPtr->tapeID =
1416 (Restore[rparamsPtr->frag].
1417 initialDumpId ? Restore[rparamsPtr->frag].
1418 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1420 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1421 rparamsPtr->tapeID, 1);
1425 /* Position to the frag and read the volume header */
1427 GetVolumeHead(taskId, tapeInfoPtr,
1428 Restore[rparamsPtr->frag].position, origVolName,
1431 ErrorLog(0, taskId, code, 0,
1432 "Can't find volume %s (%u) on tape %s\n", origVolName,
1433 origVolID, rparamsPtr->mntTapeName);
1434 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1443 * Find all the volumes on a specific tape and mark them to skip.
1446 SkipTape(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1447 char *tapename, afs_int32 tapeid, afs_int32 taskid)
1451 for (i = index; i < size; i++) {
1452 if (Restore[i].flags & RDFLAG_SKIP)
1455 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1457 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1458 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1465 * Find all the entries for a volume and mark them to skip.
1468 SkipVolume(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1469 afs_int32 volid, afs_int32 taskid)
1474 for (i = index; i < size; i++) {
1475 if (Restore[i].flags & RDFLAG_SKIP)
1477 if (Restore[i].origVid == volid) {
1478 Restore[i].flags |= RDFLAG_SKIP;
1480 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1481 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1482 Restore[i].oldName, volid);
1491 xbsaRestoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1492 struct restoreParams *rparamsPtr)
1497 afs_int32 newServer, newPart, newVolId;
1499 int restoreflags, havetrans = 0, startread = 0;
1500 afs_int32 bytesRead, endData = 0;
1502 struct budb_dumpEntry dumpEntry;
1503 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1504 struct volumeHeader volHeader, hostVolHeader;
1506 if (restoretofile) {
1507 restoretofilefd = fopen(restoretofile, "w+");
1510 dumpID = restoreInfo->dbDumpId;
1512 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1514 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1519 /* ADSM servers restore ADSM and BUTA dumps */
1520 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1521 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1523 "The dump requested by this restore operation for the "
1524 "volumeset is incompatible with this instance of butc\n");
1525 /* Skip the entire dump (one dump per tape) */
1526 ERROR_EXIT(TC_SKIPTAPE);
1529 /* make sure we are connected to the correct server. */
1530 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1531 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1533 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1534 && !forcemultiple) {
1536 "Dump %d is on server %s but butc is connected "
1537 "to server %s (attempting to restore)\n", dumpID,
1538 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1541 "Dump %d is on server %s but butc is connected "
1542 "to server %s (switching servers)\n", dumpID,
1543 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1545 rc = InitToServer(taskId, &butxInfo,
1546 (char *)dumpEntry.tapes.tapeServer);
1547 if (rc != XBSA_SUCCESS)
1548 ERROR_EXIT(TC_SKIPTAPE);
1552 /* Start a transaction and query the server for the correct fileset dump */
1553 rc = xbsa_BeginTrans(&butxInfo);
1554 if (rc != XBSA_SUCCESS) {
1555 ELog(taskId, "Unable to create a new transaction\n");
1556 ERROR_EXIT(TC_SKIPTAPE);
1560 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1561 sprintf(dumpIdStr, "/%d", dumpID);
1562 strcpy(volumeNameStr, "/");
1563 strcat(volumeNameStr, restoreInfo->oldName);
1564 } else { /* new butc names */
1565 extern char *butcdumpIdStr;
1566 strcpy(dumpIdStr, butcdumpIdStr);
1567 sprintf(volumeNameStr, "/%d", dumpID);
1568 strcat(volumeNameStr, "/");
1569 strcat(volumeNameStr, restoreInfo->oldName);
1572 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1573 if (rc != XBSA_SUCCESS) {
1575 "Unable to locate object (%s) of dump (%s) on the server\n",
1576 volumeNameStr, dumpIdStr);
1580 rc = xbsa_EndTrans(&butxInfo);
1582 if (rc != XBSA_SUCCESS) {
1583 ELog(taskId, "Unable to terminate the current transaction\n");
1587 if (checkAbortByTaskId(taskId))
1588 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1590 /* Now start a transaction on the volume to restore and read the
1591 * volumeheader. We do this before starting a transaction on
1592 * volserver to restore the volume because the XBSA server may take
1593 * a while to mount and seek to the volume causing the volserver to
1596 rc = xbsa_BeginTrans(&butxInfo);
1597 if (rc != XBSA_SUCCESS) {
1598 ELog(taskId, "Unable to create a new transaction\n");
1599 ERROR_EXIT(TC_SKIPTAPE);
1603 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1604 sizeof(volHeader), &bytesRead, &endData);
1605 if (restoretofile && (bytesRead > 0)) {
1606 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1608 if (rc != XBSA_SUCCESS) {
1610 "Unable to begin reading of the volume from the server\n");
1615 if ((bytesRead != sizeof(volHeader)) || endData) {
1617 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1618 bytesRead, sizeof(volHeader));
1619 ERROR_EXIT(TC_BADVOLHEADER);
1622 /* convert and check the volume header */
1623 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1625 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1629 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1630 || (restoreInfo->origVid
1631 && (hostVolHeader.volumeID != restoreInfo->origVid))
1632 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1633 ERROR_EXIT(TC_BADVOLHEADER);
1635 /* Set up prior restoring volume data */
1636 newVolName = restoreInfo->newName;
1637 newVolId = restoreInfo->vid;
1638 newServer = restoreInfo->hostAddr;
1639 newPart = restoreInfo->partition;
1641 if ((restoreInfo->dumpLevel == 0)
1642 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1643 restoreflags |= RV_FULLRST;
1644 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1645 restoreflags |= RV_OFFLINE;
1647 if (checkAbortByTaskId(taskId))
1648 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1650 /* Start the restore of the volume data. This is the code we want to return */
1652 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1653 restoreflags, xbsaRestoreVolumeData,
1654 (char *)rparamsPtr);
1657 rc = xbsa_ReadObjectEnd(&butxInfo);
1658 if (rc != XBSA_SUCCESS) {
1660 "Unable to terminate reading of the volume from the server\n");
1666 rc = xbsa_EndTrans(&butxInfo);
1667 if (rc != XBSA_SUCCESS) {
1668 ELog(taskId, "Unable to terminate the current transaction\n");
1674 if (restoretofile && restoretofilefd) {
1675 fclose(restoretofilefd);
1682 restoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1683 struct restoreParams *rparamsPtr)
1685 afs_int32 code = 0, rc;
1686 afs_int32 newServer, newPart, newVolId;
1690 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1692 /* Check if we need a tape and prompt for one if so */
1694 (restoreInfo->initialDumpId ? restoreInfo->
1695 initialDumpId : restoreInfo->dbDumpId);
1696 if ((rparamsPtr->frag == 0)
1697 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1698 || (tapeID != rparamsPtr->tapeID)) {
1699 /* Unmount the previous tape */
1700 unmountTape(taskId, tapeInfoPtr);
1702 /* Remember this new tape */
1703 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1704 rparamsPtr->tapeID = tapeID;
1706 /* Mount a new tape */
1707 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1709 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1714 /* Seek to the correct spot and read the header information */
1715 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1716 restoreInfo->oldName, restoreInfo->origVid);
1720 /* Set up prior restoring volume data */
1721 newVolName = restoreInfo->newName;
1722 newVolId = restoreInfo->vid;
1723 newServer = restoreInfo->hostAddr;
1724 newPart = restoreInfo->partition;
1726 if ((restoreInfo->dumpLevel == 0)
1727 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1728 restoreflags |= RV_FULLRST;
1729 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1730 restoreflags |= RV_OFFLINE;
1732 if (checkAbortByTaskId(taskId))
1733 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1735 /* Start the restore of the volume data. This is the code we
1739 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1740 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1742 /* Read the FileEnd marker for the volume and step to next FM */
1743 rc = butm_ReadFileEnd(tapeInfoPtr);
1745 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1746 "Can't read EOF on tape\n");
1754 * created as a LWP by the server stub, <newNode> is a pointer to all
1755 * the parameters Restorer needs
1758 Restorer(void *param) {
1759 struct dumpNode *newNode = (struct dumpNode *) param;
1761 afs_int32 code = 0, tcode;
1764 struct butm_tapeInfo tapeInfo;
1765 struct tc_restoreDesc *Restore;
1766 struct tc_restoreDesc *RestoreDesc;
1767 struct restoreParams rparams;
1768 afs_int32 allocbufferSize;
1769 time_t startTime, endTime;
1770 afs_int32 goodrestore = 0;
1772 taskId = newNode->taskID;
1773 setStatus(taskId, DRIVE_WAIT);
1774 EnterDeviceQueue(deviceLatch);
1775 clearStatus(taskId, DRIVE_WAIT);
1778 TLog(taskId, "Restore\n");
1780 memset(&tapeInfo, 0, sizeof(tapeInfo));
1782 tapeInfo.structVersion = BUTM_MAJORVERSION;
1783 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1785 ErrorLog(0, taskId, tcode, tapeInfo.error,
1786 "Can't initialize the tape module\n");
1791 if (checkAbortByTaskId(taskId))
1792 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1794 memset(&rparams, 0, sizeof(rparams));
1795 rparams.nodePtr = newNode;
1796 rparams.tapeInfoPtr = &tapeInfo;
1797 Restore = newNode->restores; /* Array of vol fragments to restore */
1799 /* Allocate memory in which to restore the volumes data into */
1801 allocbufferSize = dataSize = BufferSize;
1803 /* Must have at least two tape blocks */
1804 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1807 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1810 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1812 ERROR_EXIT(TC_NOMEMORY);
1813 memset(bufferBlock, 0, allocbufferSize);
1815 startTime = time(0);
1816 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1818 RestoreDesc = &Restore[rparams.frag];
1820 /* Skip the volume if it was requested to */
1821 if (RestoreDesc->flags & RDFLAG_SKIP) {
1822 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1823 /* If the volume was restored, should bring it online */
1828 newVolName = RestoreDesc->newName;
1830 /* Make sure the server to restore to is good */
1831 if (!RestoreDesc->hostAddr) {
1832 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1834 ERROR_EXIT(TC_INTERNALERROR);
1837 if (checkAbortByTaskId(taskId))
1838 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1840 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1842 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1846 /* restoreVolume function takes care of all the related fragments
1847 * spanning various tapes. On return the complete volume has been
1851 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1853 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1856 if (tcode == TC_ABORTEDBYREQUEST) {
1858 } else if (tcode == TC_SKIPTAPE) {
1861 (RestoreDesc->initialDumpId ? RestoreDesc->
1862 initialDumpId : RestoreDesc->dbDumpId);
1863 SkipTape(Restore, newNode->arraySize, rparams.frag,
1864 RestoreDesc->tapeName, tapeID, taskId);
1866 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1868 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1869 RestoreDesc->origVid, taskId);
1881 unmountTape(taskId, &tapeInfo);
1884 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1891 if (code == TC_ABORTEDBYREQUEST) {
1892 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1893 clearStatus(taskId, ABORT_REQUEST);
1894 setStatus(taskId, ABORT_DONE);
1896 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1897 setStatus(taskId, TASK_ERROR);
1899 TLog(taskId, "Restore: Finished\n");
1902 if (centralLogIO && startTime) {
1904 afs_int32 hrs, min, sec, tmp;
1906 struct tm tmstart, tmend;
1908 localtime_r(&startTime, &tmstart);
1909 localtime_r(&endTime, &tmend);
1910 timediff = (int)endTime - (int)startTime;
1911 hrs = timediff / 3600;
1912 tmp = timediff % 3600;
1917 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1918 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1919 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1920 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1921 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1922 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1923 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1924 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1926 fwrite(line, strlen(line), 1, centralLogIO);
1927 fflush(centralLogIO);
1930 setStatus(taskId, TASK_DONE);
1933 LeaveDeviceQueue(deviceLatch);
1934 return (void *)(intptr_t)(code);
1937 /* this is just scaffolding, creates new tape label with name <tapeName> */
1940 GetNewLabel(struct butm_tapeInfo *tapeInfoPtr, char *pName, char *AFSName,
1941 struct butm_tapeLabel *tapeLabel)
1944 struct timezone tzp;
1947 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1950 butm_GetSize(tapeInfoPtr, &size);
1952 size = globalTapeConfig.capacity;
1954 size = 0; /* no tape size */
1956 gettimeofday(&tp, &tzp);
1958 tapeLabel->structVersion = CUR_TAPE_VERSION;
1959 tapeLabel->creationTime = tp.tv_sec;
1960 tapeLabel->size = size;
1961 tapeLabel->expirationDate = 0; /* 1970 sometime */
1962 tapeLabel->dumpPath[0] = 0; /* no path name */
1963 tapeLabel->useCount = 0;
1964 strcpy(tapeLabel->AFSName, AFSName);
1965 strcpy(tapeLabel->pName, pName);
1966 strcpy(tapeLabel->cell, globalCellName);
1967 strcpy(tapeLabel->comment, "AFS Backup Software");
1968 strcpy(tapeLabel->creator.name, "AFS 3.6");
1969 strcpy(tapeLabel->creator.instance, "");
1970 strcpy(tapeLabel->creator.cell, globalCellName);
1973 /* extracts trailer out of buffer, nbytes is set to total data in
1974 * buffer - trailer size */
1976 ExtractTrailer(char *buffer, afs_int32 size, afs_int32 *nbytes,
1977 struct volumeHeader *volTrailerPtr)
1981 struct volumeHeader tempTrailer;
1985 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1987 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1989 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1995 return 1; /* saw the trailer */
2001 return 0; /* did not see the trailer */
2005 FindVolTrailer(char *buffer, afs_int32 size, afs_int32 *dSize,
2006 struct volumeHeader *volTrailerPtr)
2008 afs_int32 offset, s;
2015 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2019 found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
2021 *dSize -= (s - offset);
2026 FindVolTrailer2(char *buffera, afs_int32 sizea, afs_int32 *dataSizea,
2027 char *bufferb, afs_int32 sizeb, afs_int32 *dataSizeb,
2028 struct volumeHeader *volTrailerPtr)
2030 afs_int32 offset, s;
2031 afs_int32 headB, tailB;
2041 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2043 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
2046 headB = (s - sizeb); /*(s > sizeb) */
2047 if (headB > sizea) {
2054 memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
2056 memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
2058 memcpy(tapeVolumeHT + headB, bufferb, tailB);
2059 if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
2061 if (offset > headB) {
2062 /* *dataSizea remains unchanged */
2063 *dataSizeb = offset - headB;
2065 *dataSizea -= (headB - offset); /*(headB >= offset) */
2075 ExpirationDate(afs_int32 dumpid)
2078 Date expiration = 0;
2079 struct budb_dumpEntry dumpEntry;
2080 struct budb_tapeEntry tapeEntry;
2081 struct budb_volumeEntry volEntry;
2085 * Get the expiration date from DB if its there. The expiration of
2086 * any tape will be the most future expiration of any dump in the
2087 * set. Can't use bcdb_FindTape because dumpid here pertains to the
2090 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
2092 expiration = tapeEntry.expires;
2094 return (expiration);
2097 /* Returns true or false depending on whether the tape is expired or not */
2100 tapeExpired(struct butm_tapeLabel *tapeLabelPtr)
2104 struct timezone tzp;
2106 expiration = ExpirationDate(tapeLabelPtr->dumpid);
2108 expiration = tapeLabelPtr->expirationDate;
2110 gettimeofday(&tp, &tzp);
2111 return ((expiration < tp.tv_sec) ? 1 : 0);
2115 * given the label on the tape, delete any old information from the
2118 * Deletes all entries that match the volset.dumpnode
2119 * and the dump path.
2123 updateTapeLabel(struct labelTapeIf *labelIfPtr,
2124 struct butm_tapeInfo *tapeInfoPtr,
2125 struct butm_tapeLabel *newLabelPtr)
2127 struct butm_tapeLabel oldLabel;
2128 afs_int32 i, code = 0;
2130 int tapeIsLabeled = 0;
2131 int interactiveFlag;
2134 interactiveFlag = autoQuery;
2135 taskId = labelIfPtr->taskId;
2138 if (interactiveFlag) {
2140 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2141 labelIfPtr->taskId, tapecount);
2145 interactiveFlag = 1;
2148 /* mount the tape */
2149 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2151 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2155 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2159 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2160 && (strcmp(oldLabel.pName, "") != 0)) {
2161 /* We are setting the AFS name, yet tape
2162 * has a permanent name (not allowed).
2164 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2169 if (!tapeExpired(&oldLabel)) {
2170 if (!queryoperator) {
2171 TLog(taskId, "This tape has not expired\n");
2174 if (Ask("This tape has not expired - proceed") == 0)
2178 /* Keep the permanent name */
2179 if (strcmp(newLabelPtr->pName, "") == 0) {
2180 strcpy(newLabelPtr->pName, oldLabel.pName);
2181 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2182 strcpy(newLabelPtr->pName, "");
2186 /* extract useful information from the old label */
2187 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2188 newLabelPtr->dumpid = 0;
2189 newLabelPtr->useCount = oldLabel.useCount + 1;
2192 /* now write the new label */
2193 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2195 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2196 "Can't label tape\n");
2203 unmountTape(taskId, tapeInfoPtr);
2206 /* delete obsolete information from the database */
2207 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2208 /* delete based on dump id */
2209 if (oldLabel.dumpid) {
2210 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2211 if (i && (i != BUDB_NOENT))
2212 ErrorLog(0, taskId, i, 0,
2213 "Warning: Can't delete old dump %u from database\n",
2219 unmountTape(taskId, tapeInfoPtr);
2224 * LWP created by the server stub. Labels the tape with name and size
2225 * specified by <label>
2229 Labeller(void *param)
2231 struct labelTapeIf *labelIfPtr = (struct labelTapeIf *)param;
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);
2283 return (void *)(intptr_t)(code);
2287 * print out the tape label.
2291 PrintTapeLabel(struct butm_tapeLabel *labelptr)
2293 char tapeName[BU_MAXTAPELEN + 32];
2296 printf("Tape label\n");
2297 printf("----------\n");
2298 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2299 printf("permanent tape name = %s\n", tapeName);
2300 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2301 printf("AFS tape name = %s\n", tapeName);
2302 t = labelptr->creationTime;
2303 printf("creationTime = %s", ctime(&t));
2304 if (labelptr->expirationDate) {
2305 t = labelptr->expirationDate;
2306 printf("expirationDate = %s", cTIME(&t));
2308 printf("cell = %s\n", labelptr->cell);
2309 printf("size = %u Kbytes\n", labelptr->size);
2310 printf("dump path = %s\n", labelptr->dumpPath);
2312 if (labelptr->structVersion >= TAPE_VERSION_3) {
2313 printf("dump id = %u\n", labelptr->dumpid);
2314 printf("useCount = %d\n", labelptr->useCount);
2316 printf("-- End of tape label --\n\n");
2320 * Read the label from a tape.
2321 * Currently prints out a "detailed" summary of the label but passes
2322 * back only selected fields.
2326 ReadLabel(struct tc_tapeLabel *label)
2328 struct butm_tapeLabel newTapeLabel;
2329 struct butm_tapeInfo tapeInfo;
2333 int interactiveFlag;
2336 EnterDeviceQueue(deviceLatch);
2337 taskId = allocTaskId(); /* reqd for lower level rtns */
2340 TLog(taskId, "Readlabel\n");
2342 memset(&tapeInfo, 0, sizeof(tapeInfo));
2343 tapeInfo.structVersion = BUTM_MAJORVERSION;
2344 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2346 ErrorLog(0, taskId, code, tapeInfo.error,
2347 "Can't initialize the tape module\n");
2350 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2352 interactiveFlag = autoQuery;
2355 if (interactiveFlag) {
2356 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2360 interactiveFlag = 1;
2363 code = butm_Mount(&tapeInfo, "");
2365 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2371 unmountTape(taskId, &tapeInfo);
2374 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2376 if (code == BUTM_NOLABEL) {
2377 printf("Tape is unlabelled\n");
2380 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2384 /* copy the fields to be passed to the caller */
2385 label->size = newTapeLabel.size;
2386 label->tapeId = newTapeLabel.dumpid;
2387 strcpy(label->afsname, newTapeLabel.AFSName);
2388 strcpy(label->pname, newTapeLabel.pName);
2391 expir = ExpirationDate(newTapeLabel.dumpid);
2393 newTapeLabel.expirationDate = expir;
2395 PrintTapeLabel(&newTapeLabel);
2398 unmountTape(taskId, &tapeInfo);
2400 if (code == TC_ABORTEDBYREQUEST)
2401 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2402 else if (code && (code != BUTM_NOLABEL))
2403 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2405 TLog(taskId, "ReadLabel: Finished\n");
2407 LeaveDeviceQueue(deviceLatch);
2411 /* Function to read volume header and trailer structure from tape, taking
2412 into consideration, different word alignment rules.
2415 readVolumeHeader(char *buffer, /* in - buffer to read header from */
2416 afs_int32 bufloc, /* in - header's location in buffer */
2417 struct volumeHeader *header) /* out -header structure */
2419 struct volumeHeader vhptr, *tempvhptr;
2420 afs_int32 firstSplice = (afs_int32) ((char*)& vhptr.pad - (char*) & vhptr);
2421 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2422 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2424 /* Four cases are to be handled
2426 * Volume Header (byte alignment)
2427 * -----------------------
2434 * -----------------------
2436 * Case 2 and Case 3 are identical cases and handled the same way.
2437 * Case 1 and Case 4 are separate cases. In one case the pad needs
2438 * to be removed and in the other, it needs to be spliced in. The
2439 * four cases are handled as follows
2441 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2442 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2443 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2444 /* Handle Cases 2 & 3 */
2445 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2446 HEADER_CHECKS(vhptr, header);
2449 memset(&vhptr, 0, sizeof(struct volumeHeader));
2450 memcpy(&vhptr, buffer + bufloc, firstSplice);
2451 memset(&vhptr.pad, 0, padLen);
2452 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2453 HEADER_CHECKS(vhptr, header);
2456 memset(&vhptr, 0, sizeof(struct volumeHeader));
2457 memcpy(&vhptr, buffer + bufloc, firstSplice);
2458 /* probably GCC bug 37060; however, no guarantee on length of buffer */
2459 tempvhptr = (struct volumeHeader *)(buffer + firstSplice);
2460 memcpy(tempvhptr, buffer + bufloc + firstSplice + padLen,
2462 HEADER_CHECKS(vhptr, header);
2465 return (TC_BADVOLHEADER);