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 queryoperator;
44 extern int tapemounted;
45 extern char *opencallout;
46 extern char *closecallout;
48 extern char *extractDumpName();
49 extern int BufferSize; /* Size in B stored for header info */
50 FILE *restoretofilefd;
52 extern char *restoretofile;
53 extern int forcemultiple;
56 /* XBSA Global Parameters */
59 struct butx_transactionInfo butxInfo;
62 static struct TapeBlock { /* A 16KB tapeblock */
63 char mark[BUTM_HDRSIZE]; /* Header info */
64 char data[BUTM_BLKSIZE]; /* data */
67 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
68 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
71 * Need to re-write to:
72 * 1) non-interactive tape handling (optional)
73 * 2) compute tape and volume sizes for the database
74 * 3) compute and use tape id's for tape tracking (put on tape label)
75 * 4) status management
78 /* All the relevant info shared between Restorer and restoreVolume */
79 struct restoreParams {
80 struct dumpNode *nodePtr;
82 char mntTapeName[BU_MAXTAPELEN];
84 struct butm_tapeInfo *tapeInfoPtr;
87 /* Abort checks are done after each BIGCHUNK of data transfer */
88 #define BIGCHUNK 102400
90 #define HEADER_CHECKS(vhptr, header) \
92 afs_int32 magic, versionflags; \
94 versionflags = ntohl(vhptr.versionflags); \
95 if ( versionflags == TAPE_VERSION_0 || \
96 versionflags == TAPE_VERSION_1 || \
97 versionflags == TAPE_VERSION_2 || \
98 versionflags == TAPE_VERSION_3 || \
99 versionflags == TAPE_VERSION_4 ) { \
101 magic = ntohl(vhptr.magic); /* another sanity check */ \
102 if (magic == TC_VOLBEGINMAGIC || \
103 magic == TC_VOLENDMAGIC || \
104 magic == TC_VOLCONTD ) { \
106 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
109 } /* versionflags */ \
113 extern FILE *ErrorlogIO;
114 extern FILE *centralLogIO;
115 extern FILE *lastLogIO;
116 extern afs_int32 lastPass; /* Set true during last pass of dump */
117 extern int debugLevel;
118 extern int autoQuery;
119 extern struct tapeConfig globalTapeConfig;
120 extern struct deviceSyncNode *deviceLatch;
121 extern char globalCellName[];
125 /* forward declaration */
126 afs_int32 readVolumeHeader( /*char *buffer,afs_int32 bufloc,(struct volumeHeader *)vhptr */ );
128 /* The on-disk volume header or trailer can differ in size from platform to platform */
129 static struct TapeBlock tapeBlock;
130 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
133 PrintLog(log, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
135 afs_int32 error1, error2;
136 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
140 fprintf(log, str, a, b, c, d, e, f, g, h, i, j);
145 err1 = "Volume needs to be salvaged";
148 err1 = "Bad vnode number quoted";
151 err1 = "Volume not attached, does not exist, or not on line";
154 err1 = "Volume already exists";
157 err1 = "Volume is not in service";
160 err1 = "Volume is off line";
163 err1 = "Volume is already on line";
166 err1 = "Partition is full";
169 err1 = "Volume max quota exceeded";
172 err1 = "Volume temporarily unavailable";
175 err1 = "Volume has moved to another server";
178 err1 = (char *)afs_error_message(error1);
179 err2 = (char *)afs_error_table_name(error1);
183 fprintf(log, " Possible communication failure");
185 fprintf(log, " %s: %s", err2, err1);
187 fprintf(log, ": %s", afs_error_message(error2));
194 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
196 afs_int32 task, error1, error2;
197 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
200 char tbuffer[32], *timestr;
203 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
206 fprintf(logIO, "%s: ", timestr);
208 fprintf(logIO, "Task %u: ", task);
209 PrintLog(logIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
211 if (lastPass && lastLogIO) {
212 fprintf(lastLogIO, "%s: ", timestr);
214 fprintf(lastLogIO, "Task %u: ", task);
215 PrintLog(lastLogIO, error1, error2, str, a, b, c, d, e, f, g, h, i,
219 /* Now print to the screen if debug level requires */
220 if (debug <= debugLevel)
221 PrintLog(stdout, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
225 TLog(task, str, a, b, c, d, e, f, g, h, i, j)
227 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
229 /* Sends message to TapeLog and stdout */
230 TapeLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
234 ErrorLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
236 afs_int32 task, error1, error2;
237 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
240 char tbuffer[32], *timestr;
243 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
245 fprintf(ErrorlogIO, "%s: ", timestr);
247 /* Print the time and task number */
249 fprintf(ErrorlogIO, "Task %u: ", task);
250 PrintLog(ErrorlogIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
252 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
256 ELog(task, str, a, b, c, d, e, f, g, h, i, j)
258 char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
260 /* Sends message to ErrorLog, TapeLog and stdout */
261 ErrorLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
264 /* first proc called by anybody who intends to use the device */
266 EnterDeviceQueue(devLatch)
267 struct deviceSyncNode *devLatch;
269 ObtainWriteLock(&(devLatch->lock));
270 devLatch->flags = TC_DEVICEINUSE;
273 /* last proc called by anybody finishing using the device */
275 LeaveDeviceQueue(devLatch)
276 struct deviceSyncNode *devLatch;
279 ReleaseWriteLock(&(devLatch->lock));
282 #define BELLTIME 60 /* 60 seconds before a bell rings */
283 #define BELLCHAR 7 /* ascii for bell */
286 #ifdef AFS_PTHREAD_ENV
288 /* WaitForKeystroke : Wait until a key has been struck or time (secconds)
289 * runs out and return to caller. The NT version of this function will return
290 * immediately after a key has been pressed (doesn't wait for cr).
292 * seconds: wait for <seconds> seconds before returning. If seconds < 0,
295 * 1: Keyboard input available
296 * 0: seconds elapsed. Timeout.
298 * STOLEN FROM LWP_WaitForKeystroke()
301 WaitForKeystroke(int seconds)
303 time_t startTime, nowTime;
305 struct timeval twait;
314 /* check if we have a keystroke */
320 /* sleep for LWP_KEYSTROKE_DELAY ms and let other
322 select(0, 0, 0, 0, &twait);
324 if (seconds > 0) { /* we only worry about elapsed time if
325 * not looping forever (seconds < 0) */
327 timeleft = seconds - difftime(nowTime, startTime);
329 } while (timeleft > 0);
332 #else /* AFS_NT40)ENV */
333 extern int WaitForKeystroke(int);
335 * STOLEN FROM LWP_WaitForKeystroke()
338 WaitForKeystroke(int seconds)
342 struct timeval twait;
343 struct timeval *tp = NULL;
345 #ifdef AFS_LINUX20_ENV
346 if (stdin->_IO_read_ptr < stdin->_IO_read_end)
353 FD_SET(fileno(stdin), &rdfds);
356 twait.tv_sec = seconds;
360 code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
361 return (code == 1) ? 1 : 0;
365 /* GetResponseKey() - Waits for a specified period of time and
366 * returns a char when one has been typed by the user.
368 * seconds - how long to wait for a key press.
369 * *key - char entered by user
371 * 0 - Time ran out before the user typed a key.
372 * 1 - Valid char is being returned.
374 * STOLEN FROM LWP_GetResponseKey();
377 GetResponseKey(int seconds, char *key)
382 return 0; /* need space to store char */
383 fflush(stdin); /* flush all existing data and start anew */
385 rc = WaitForKeystroke(seconds);
386 if (rc == 0) { /* time ran out */
391 /* now read the char. */
393 *key = getche(); /* get char and echo it to screen */
399 #endif /* AFS_PTHREAD_ENV
404 * * only external clients are in recoverDb.c. Was static. PA
414 #ifdef AFS_PTHREAD_ENV
415 w = WaitForKeystroke(0);
417 w = LWP_WaitForKeystroke(0);
418 #endif /* AFS_PTHREAD_ENV */
425 #endif /* AFS_NT40_ENV */
433 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;
554 int cpid, status, rcpid;
556 code = butm_Dismount(tapeInfoPtr);
557 if (code && (code != BUTM_NOMOUNT))
558 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
559 "Warning: Can't close tape\n");
561 if (tapemounted && closecallout) {
562 setStatus(taskId, CALL_WAIT);
565 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
567 while (cpid) { /* Wait until return */
569 rcpid = waitpid(cpid, &status, WNOHANG);
574 if (rcpid == -1 && errno != EINTR) {
576 afs_com_err(whoami, errno,
577 "Error waiting for callout script to terminate.");
580 #ifdef AFS_PTHREAD_ENV
586 if (checkAbortByTaskId(taskId)) {
587 TLog(taskId, "Callout routine has been aborted\n");
588 if (kill(cpid, SIGKILL)) /* Cancel callout */
589 ErrorLog(0, taskId, errno, 0,
590 "Kill of callout process %d failed\n", cpid);
595 clearStatus(taskId, CALL_WAIT);
599 * print out prompt to operator
601 * PromptForTape only.
605 PrintPrompt(flag, name, dumpid)
609 char tapename[BU_MAXTAPELEN + 32];
612 TAPENAME(tapename, name, dumpid);
614 printf("******* OPERATOR ATTENTION *******\n");
615 printf("Device : %s \n", globalTapeConfig.device);
618 case READOPCODE: /* mount for restore */
619 printf("Please put in tape %s for reading", tapename);
622 case APPENDOPCODE: /* mount for dump (appends) */
624 dn = extractDumpName(name);
627 printf("Please put in last tape of dump set for appending dump");
630 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
634 case WRITEOPCODE: /* mount for dump */
635 if (strcmp(name, "") == 0)
636 printf("Please put in tape for writing");
638 /* The name is what we are going to label the tape as */
640 printf("Please put in tape %s for writing", tapename);
643 case LABELOPCODE: /* mount for labeltape */
644 printf("Please put in tape to be labelled as %s", tapename);
647 case READLABELOPCODE: /* mount for readlabel */
648 printf("Please put in tape whose label is to be read");
651 case SCANOPCODE: /* mount for scantape */
652 if (strcmp(name, "") == 0)
653 printf("Please put in tape to be scanned");
655 printf("Please put in tape %s for scanning", tapename);
658 case RESTOREDBOPCODE: /* Mount for restoredb */
659 printf("Please insert a tape %s for the database restore", tapename);
662 case SAVEDBOPCODE: /* Mount for savedb */
663 printf("Please insert a writeable tape %s for the database dump",
670 printf(" and hit return when done\n");
674 * Prompt the operator to change the tape.
675 * Use to be a void routine but now returns an error. Some calls
676 * don't use the error code.
678 * only external clients are in recoverDb.c. Was static PA
681 PromptForTape(flag, name, dbDumpId, taskId, tapecount)
684 afs_uint32 dbDumpId; /* Specific dump ID - If non-zero */
688 register afs_int32 code = 0;
693 int cpid, status, rcpid;
695 if (checkAbortByTaskId(taskId))
696 ERROR_EXIT(TC_ABORTEDBYREQUEST);
699 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
701 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
703 CallOut = (opencallout ? 1 : 0);
705 setStatus(taskId, CALL_WAIT);
708 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
709 dbDumpId, tapecount);
711 CallOut = 0; /* prompt at screen */
713 while (CallOut) { /* Check if callout routine finished */
715 rcpid = waitpid(cpid, &status, WNOHANG);
719 else if (WIFEXITED(status))
720 wcode = WEXITSTATUS(status);
725 break; /* All done */
726 } else if (wcode == 1) {
727 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
728 } else if ((flag == READOPCODE) && (wcode == 3)) {
729 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
732 "Callout routine has exited with code %d: will prompt\n",
734 CallOut = 0; /* Switch to keyboard input */
738 /* if waitpid experienced an error, we prompt */
739 if (rcpid == -1 && errno != EINTR) {
740 afs_com_err(whoami, errno,
741 "Error waiting for callout script to terminate.");
743 "Can't get exit status from callout script. will prompt\n");
747 #ifdef AFS_PTHREAD_ENV
753 if (checkAbortByTaskId(taskId)) {
755 ("This tape operation has been aborted by the coordinator.\n");
757 if (kill(cpid, SIGKILL)) /* Cancel callout */
758 ErrorLog(0, taskId, errno, 0,
759 "Kill of callout process %d failed\n", cpid);
761 ERROR_EXIT(TC_ABORTEDBYREQUEST);
767 clearStatus(taskId, CALL_WAIT);
768 setStatus(taskId, OPR_WAIT);
770 PrintPrompt(flag, name, dbDumpId);
772 /* Loop until we get ok to go ahead (or abort) */
774 if (time(0) > start + BELLTIME) {
780 #ifdef AFS_PTHREAD_ENV
781 wcode = GetResponseKey(5, &inchr); /* inchr stores key read */
783 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
785 if (wcode == 1) { /* keyboard input is available */
787 if ((inchr == 'a') || (inchr == 'A')) {
788 printf("This tape operation has been aborted.\n");
789 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
790 } else if ((flag == READOPCODE)
791 && ((inchr == 's') || (inchr == 'S'))) {
792 printf("This tape will be skipped.\n");
793 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
795 break; /* continue */
798 if (checkAbortByTaskId(taskId)) {
800 ("This tape operation has been aborted by the coordinator.\n");
801 ERROR_EXIT(TC_ABORTEDBYREQUEST);
807 printf("Thanks, now proceeding with tape ");
809 case RESTOREDBOPCODE:
815 printf("append writing");
827 case READLABELOPCODE:
828 printf("label reading");
840 printf(" operation.\n");
842 printf("**********************************\n");
844 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
848 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
854 * convert the fields in the tapeVolHeader into host byte order,
855 * placing the converted copy of the structure into the hostVolHeader
857 * tapeVolHeader - points to volume header read from tape
858 * hostVolHeader - pointer to struct for result
860 * hostVolHeader - information in host byte order
864 VolHeaderToHost(hostVolHeader, tapeVolHeader)
865 struct volumeHeader *hostVolHeader, *tapeVolHeader;
867 switch (ntohl(tapeVolHeader->versionflags)) {
869 /* sizes in bytes and fields in host order */
870 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
875 case TAPE_VERSION_3: /* for present */
877 /* sizes in K and fields in network order */
878 /* do the conversion field by field */
880 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
881 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
882 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
883 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
884 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
885 hostVolHeader->server = ntohl(tapeVolHeader->server);
886 hostVolHeader->part = ntohl(tapeVolHeader->part);
887 hostVolHeader->from = ntohl(tapeVolHeader->from);
888 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
889 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
890 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
891 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
892 hostVolHeader->level = ntohl(tapeVolHeader->level);
893 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
894 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
895 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
896 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
900 return (TC_BADVOLHEADER);
906 ReadVolHeader(taskId, tapeInfoPtr, volHeaderPtr)
908 struct butm_tapeInfo *tapeInfoPtr;
909 struct volumeHeader *volHeaderPtr;
913 struct volumeHeader volHead;
915 /* Read the volume header */
917 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
920 ErrorLog(0, taskId, code, tapeInfoPtr->error,
921 "Can't read volume header on tape\n");
925 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
927 ErrorLog(0, taskId, code, 0,
928 "Can't find volume header on tape block\n");
932 code = VolHeaderToHost(volHeaderPtr, &volHead);
934 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
943 GetVolumeHead(taskId, tapeInfoPtr, position, volName, volId)
945 struct butm_tapeInfo *tapeInfoPtr;
951 struct volumeHeader tapeVolHeader;
953 /* Position directly to the volume and read the header */
955 code = butm_Seek(tapeInfoPtr, position);
957 ErrorLog(0, taskId, code, tapeInfoPtr->error,
958 "Can't seek to position %u on tape\n", position);
962 code = butm_ReadFileBegin(tapeInfoPtr);
964 ErrorLog(0, taskId, code, tapeInfoPtr->error,
965 "Can't read FileBegin on tape\n");
969 /* Read the volume header */
970 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
974 /* Check if volume header matches */
975 if (strcmp(tapeVolHeader.volumeName, volName))
976 ERROR_EXIT(TC_BADVOLHEADER);
977 if (volId && (tapeVolHeader.volumeID != volId))
978 ERROR_EXIT(TC_BADVOLHEADER);
979 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
980 ERROR_EXIT(TC_BADVOLHEADER);
983 /* Do a sequential search for the volume */
986 code = butm_ReadFileBegin(tapeInfoPtr);
988 ErrorLog(0, taskId, code, tapeInfoPtr->error,
989 "Can't read FileBegin on tape\n");
993 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
995 ERROR_EXIT(TC_VOLUMENOTONTAPE);
997 /* Test if we found the volume */
998 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
999 && (!volId || (volId == tapeVolHeader.volumeID)))
1002 /* skip to the next HW EOF marker */
1003 code = SeekFile(tapeInfoPtr, 1);
1005 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1006 "Can't seek to next EOF on tape\n");
1017 GetRestoreTape(taskId, tapeInfoPtr, tname, tapeID, prompt)
1019 struct butm_tapeInfo *tapeInfoPtr;
1024 struct butm_tapeLabel tapeLabel;
1025 afs_int32 code = 0, rc;
1027 struct budb_dumpEntry dumpEntry;
1029 /* Make sure that the dump/tape is not a XBSA dump */
1030 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
1031 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1032 ErrorLog(0, taskId, 0, 0,
1033 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
1034 ERROR_EXIT(TC_SKIPTAPE);
1040 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
1047 code = butm_Mount(tapeInfoPtr, tname);
1049 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
1053 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
1055 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1056 "Can't read tape label\n");
1060 /* Now check the label to see if the tapename matches or tapeids match */
1061 if (strcmp(TNAME(&tapeLabel), tname)
1062 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
1063 && (tapeLabel.dumpid != tapeID))) {
1064 char expectedName[BU_MAXTAPELEN + 32],
1065 gotName[BU_MAXTAPELEN + 32];
1067 TAPENAME(expectedName, tname, tapeID);
1068 LABELNAME(gotName, &tapeLabel);
1070 TapeLog(0, taskId, 0, 0,
1071 "Tape label expected %s, label seen %s\n", expectedName,
1079 unmountTape(taskId, tapeInfoPtr);
1087 xbsaRestoreVolumeData(call, rparamsPtr)
1088 register struct rx_call *call;
1089 struct restoreParams *rparamsPtr;
1093 afs_int32 curChunk, rc;
1094 afs_uint32 totalWritten;
1095 afs_int32 headBytes, tailBytes, w;
1097 struct volumeHeader volTrailer;
1098 afs_int32 vtsize = 0;
1100 struct dumpNode *nodePtr;
1101 struct tc_restoreDesc *Restore;
1102 afs_int32 bytesRead, tbuffersize, endData = 0;
1103 char *buffer = (char *)bufferBlock, tbuffer[256];
1105 nodePtr = rparamsPtr->nodePtr;
1106 Restore = nodePtr->restores;
1107 taskId = nodePtr->taskID;
1109 /* Read the volume fragment one block at a time until
1110 * find a volume trailer
1112 curChunk = BIGCHUNK + 1;
1117 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1119 if (restoretofile && (bytesRead > 0)) {
1120 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1122 if (rc != XBSA_SUCCESS) {
1123 ErrorLog(0, taskId, rc, 0,
1124 "Unable to read volume data from the server\n");
1128 /* Periodically update status structure and check if should abort */
1129 curChunk += bytesRead;
1130 if (curChunk > BIGCHUNK) {
1133 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1136 if (checkAbortByTaskId(taskId))
1137 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1140 if (!endData && (bytesRead > 0)) {
1141 /* Fill tbuffer up with data from end of buffer and write
1142 * the remainder of buffer out.
1144 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1145 /* Write out contents of tbuffer */
1147 w = rx_Write(call, tbuffer, tbuffersize);
1148 if (w != tbuffersize) {
1149 ErrorLog(0, taskId, -1, 0,
1150 "Error in RX write: Wrote %d bytes\n", w);
1155 /* fill tbuffer with end of buffer */
1156 bytesRead -= sizeof(tbuffer);
1157 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1158 tbuffersize = sizeof(tbuffer);
1159 /* Write out whatever is left over in buffer */
1161 w = rx_Write(call, buffer, bytesRead);
1162 if (w != bytesRead) {
1163 ErrorLog(0, taskId, -1, 0,
1164 "Error in RX data write: Wrote %d bytes\n",
1171 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1172 /* Copy all of buffer into tbuffer (it will fit) */
1173 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1174 tbuffersize += bytesRead;
1177 /* We need to write some of tbuffer out and fill it with buffer */
1178 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1179 w = rx_Write(call, tbuffer, towrite);
1181 ErrorLog(0, taskId, -1, 0,
1182 "Error in RX write: Wrote %d bytes\n", w);
1188 /* Move the data in tbuffer up */
1189 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1191 /* Now copy buffer in */
1192 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1193 tbuffersize += bytesRead;
1199 /* Pull the volume trailer from the last two buffers */
1201 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1202 &tailBytes, &volTrailer);
1205 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1206 ERROR_EXIT(TC_MISSINGTRAILER);
1209 /* Now rx_write the data in the last two blocks */
1211 w = rx_Write(call, tbuffer, headBytes);
1212 if (w != headBytes) {
1213 ErrorLog(0, taskId, -1, 0,
1214 "Error in RX trail1 write: Wrote %d bytes\n", w);
1220 w = rx_Write(call, buffer, tailBytes);
1221 if (w != tailBytes) {
1222 ErrorLog(0, taskId, -1, 0,
1223 "Error in RX trail2 write: Wrote %d bytes\n", w);
1235 * sends the contents of volume dump to Rx Stream associated
1240 restoreVolumeData(call, rparamsPtr)
1241 register struct rx_call *call;
1242 struct restoreParams *rparamsPtr;
1245 afs_uint32 totalWritten = 0;
1247 afs_int32 headBytes, tailBytes, w;
1249 afs_int32 nbytes; /* # bytes data in last tape block read */
1250 struct volumeHeader tapeVolTrailer;
1253 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1254 struct tc_restoreDesc *Restore;
1255 struct dumpNode *nodePtr;
1256 struct butm_tapeInfo *tapeInfoPtr;
1258 afs_int32 origVolID;
1260 nodePtr = rparamsPtr->nodePtr;
1261 taskId = nodePtr->taskID;
1262 Restore = nodePtr->restores;
1263 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1264 origVolName = Restore[rparamsPtr->frag].oldName;
1265 origVolID = Restore[rparamsPtr->frag].origVid;
1267 /* Read the volume one fragment at a time */
1268 while (rparamsPtr->frag < nodePtr->arraySize) {
1270 curChunk = BIGCHUNK + 1; /* Check if should abort */
1272 /* Read the volume fragment one block at a time until
1273 * find a volume trailer
1279 while (moretoread) {
1280 /* Fill the circular buffer with tape blocks
1281 * Search for volume trailer in the process.
1286 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1287 BUTM_BLKSIZE, &nbytes);
1289 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1290 "Can't read FileData on tape %s\n",
1291 rparamsPtr->mntTapeName);
1294 curChunk += BUTM_BLKSIZE;
1296 /* Periodically update status structure and check if should abort */
1297 if (curChunk > BIGCHUNK) {
1301 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1304 if (checkAbortByTaskId(taskId))
1305 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1308 /* step to next block in buffer */
1310 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1312 /* If this is the end of the volume, the exit the loop */
1313 if ((nbytes != BUTM_BLKSIZE)
1316 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1320 } while (moretoread && (buf != endRbuf));
1322 /* Write the buffer upto (but not including) the last read block
1323 * If volume is completely read, then leave the last two blocks.
1325 lastbuf = endWbuf = pbuf;
1326 if (!moretoread && (endWbuf != startWbuf))
1327 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1329 for (buf = startWbuf; buf != endWbuf;
1330 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1331 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1332 if (w != BUTM_BLKSIZE) {
1333 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1336 totalWritten += BUTM_BLKSIZE;
1339 /* Setup pointers to refill buffer */
1340 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1342 startWbuf = endWbuf;
1345 /* lastbuf is last block read and it has nbytes of data
1346 * startWbuf is the 2nd to last block read
1347 * Seach for the volume trailer in these two blocks.
1349 if (lastbuf == startWbuf)
1351 FindVolTrailer2(NULL, 0, &headBytes,
1352 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1356 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1357 &headBytes, bufferBlock[lastbuf].data, nbytes,
1358 &tailBytes, &tapeVolTrailer);
1360 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1361 "Missing volume trailer on tape %s\n",
1362 rparamsPtr->mntTapeName);
1363 ERROR_EXIT(TC_MISSINGTRAILER);
1366 /* Now rx_write the data in the last two blocks */
1368 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1369 if (w != headBytes) {
1370 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1373 totalWritten += headBytes;
1376 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1377 if (w != tailBytes) {
1378 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1381 totalWritten += tailBytes;
1384 /* Exit the loop if the volume is not continued on next tape */
1385 if (!tapeVolTrailer.contd)
1386 break; /* We've read the entire volume */
1388 /* Volume is continued on next tape.
1389 * Step to the next volume fragment and prompt for its tape.
1390 * When a volume has multiple frags, those frags are on different
1391 * tapes. So we know that we need to prompt for a tape.
1394 if (rparamsPtr->frag >= nodePtr->arraySize)
1397 unmountTape(taskId, tapeInfoPtr);
1398 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1399 rparamsPtr->tapeID =
1400 (Restore[rparamsPtr->frag].
1401 initialDumpId ? Restore[rparamsPtr->frag].
1402 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1404 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1405 rparamsPtr->tapeID, 1);
1409 /* Position to the frag and read the volume header */
1411 GetVolumeHead(taskId, tapeInfoPtr,
1412 Restore[rparamsPtr->frag].position, origVolName,
1415 ErrorLog(0, taskId, code, 0,
1416 "Can't find volume %s (%u) on tape %s\n", origVolName,
1417 origVolID, rparamsPtr->mntTapeName);
1418 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1427 * Find all the volumes on a specific tape and mark them to skip.
1429 SkipTape(Restore, size, index, tapename, tapeid, taskid)
1430 struct tc_restoreDesc *Restore;
1431 afs_int32 size, index, tapeid, taskid;
1436 for (i = index; i < size; i++) {
1437 if (Restore[i].flags & RDFLAG_SKIP)
1440 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1442 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1443 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1450 * Find all the entries for a volume and mark them to skip.
1452 SkipVolume(Restore, size, index, volid, taskid)
1453 struct tc_restoreDesc *Restore;
1454 afs_int32 size, index, volid, taskid;
1459 for (i = index; i < size; i++) {
1460 if (Restore[i].flags & RDFLAG_SKIP)
1462 if (Restore[i].origVid == volid) {
1463 Restore[i].flags |= RDFLAG_SKIP;
1465 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1466 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1467 Restore[i].oldName, volid);
1475 xbsaRestoreVolume(taskId, restoreInfo, rparamsPtr)
1477 struct tc_restoreDesc *restoreInfo;
1478 struct restoreParams *rparamsPtr;
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;
1679 /* Check if we need a tape and prompt for one if so */
1681 (restoreInfo->initialDumpId ? restoreInfo->
1682 initialDumpId : restoreInfo->dbDumpId);
1683 if ((rparamsPtr->frag == 0)
1684 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1685 || (tapeID != rparamsPtr->tapeID)) {
1686 /* Unmount the previous tape */
1687 unmountTape(taskId, tapeInfoPtr);
1689 /* Remember this new tape */
1690 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1691 rparamsPtr->tapeID = tapeID;
1693 /* Mount a new tape */
1694 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1696 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1701 /* Seek to the correct spot and read the header information */
1702 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1703 restoreInfo->oldName, restoreInfo->origVid);
1707 /* Set up prior restoring volume data */
1708 newVolName = restoreInfo->newName;
1709 newVolId = restoreInfo->vid;
1710 newServer = restoreInfo->hostAddr;
1711 newPart = restoreInfo->partition;
1713 if ((restoreInfo->dumpLevel == 0)
1714 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1715 restoreflags |= RV_FULLRST;
1716 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1717 restoreflags |= RV_OFFLINE;
1719 if (checkAbortByTaskId(taskId))
1720 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1722 /* Start the restore of the volume data. This is the code we
1726 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1727 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1729 /* Read the FileEnd marker for the volume and step to next FM */
1730 rc = butm_ReadFileEnd(tapeInfoPtr);
1732 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1733 "Can't read EOF on tape\n");
1741 * created as a LWP by the server stub, <newNode> is a pointer to all
1742 * the parameters Restorer needs
1745 struct dumpNode *newNode;
1747 afs_int32 code = 0, tcode;
1750 struct butm_tapeInfo tapeInfo;
1751 struct tc_restoreDesc *Restore;
1752 struct tc_restoreDesc *RestoreDesc;
1753 struct restoreParams rparams;
1754 afs_int32 allocbufferSize;
1755 time_t startTime, endTime;
1756 afs_int32 goodrestore = 0;
1758 taskId = newNode->taskID;
1759 setStatus(taskId, DRIVE_WAIT);
1760 EnterDeviceQueue(deviceLatch);
1761 clearStatus(taskId, DRIVE_WAIT);
1764 TLog(taskId, "Restore\n");
1766 memset(&tapeInfo, 0, sizeof(tapeInfo));
1768 tapeInfo.structVersion = BUTM_MAJORVERSION;
1769 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1771 ErrorLog(0, taskId, tcode, tapeInfo.error,
1772 "Can't initialize the tape module\n");
1777 if (checkAbortByTaskId(taskId))
1778 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1780 memset(&rparams, 0, sizeof(rparams));
1781 rparams.nodePtr = newNode;
1782 rparams.tapeInfoPtr = &tapeInfo;
1783 Restore = newNode->restores; /* Array of vol fragments to restore */
1785 /* Allocate memory in which to restore the volumes data into */
1787 allocbufferSize = dataSize = BufferSize;
1789 /* Must have at least two tape blocks */
1790 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1793 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1796 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1798 ERROR_EXIT(TC_NOMEMORY);
1799 memset(bufferBlock, 0, allocbufferSize);
1801 startTime = time(0);
1802 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1804 RestoreDesc = &Restore[rparams.frag];
1806 /* Skip the volume if it was requested to */
1807 if (RestoreDesc->flags & RDFLAG_SKIP) {
1808 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1809 /* If the volume was restored, should bring it online */
1814 newVolName = RestoreDesc->newName;
1816 /* Make sure the server to restore to is good */
1817 if (!RestoreDesc->hostAddr) {
1818 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1820 ERROR_EXIT(TC_INTERNALERROR);
1823 if (checkAbortByTaskId(taskId))
1824 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1826 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1828 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1832 /* restoreVolume function takes care of all the related fragments
1833 * spanning various tapes. On return the complete volume has been
1837 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1839 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1842 if (tcode == TC_ABORTEDBYREQUEST) {
1844 } else if (tcode == TC_SKIPTAPE) {
1847 (RestoreDesc->initialDumpId ? RestoreDesc->
1848 initialDumpId : RestoreDesc->dbDumpId);
1849 SkipTape(Restore, newNode->arraySize, rparams.frag,
1850 RestoreDesc->tapeName, tapeID, taskId);
1852 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1854 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1855 RestoreDesc->origVid, taskId);
1867 unmountTape(taskId, &tapeInfo);
1870 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1877 if (code == TC_ABORTEDBYREQUEST) {
1878 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1879 clearStatus(taskId, ABORT_REQUEST);
1880 setStatus(taskId, ABORT_DONE);
1882 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1883 setStatus(taskId, TASK_ERROR);
1885 TLog(taskId, "Restore: Finished\n");
1888 if (centralLogIO && startTime) {
1890 afs_int32 hrs, min, sec, tmp;
1892 struct tm tmstart, tmend;
1894 localtime_r(&startTime, &tmstart);
1895 localtime_r(&endTime, &tmend);
1896 timediff = (int)endTime - (int)startTime;
1897 hrs = timediff / 3600;
1898 tmp = timediff % 3600;
1903 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1904 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1905 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1906 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1907 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1908 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1909 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1910 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1912 fwrite(line, strlen(line), 1, centralLogIO);
1913 fflush(centralLogIO);
1916 setStatus(taskId, TASK_DONE);
1919 LeaveDeviceQueue(deviceLatch);
1923 /* this is just scaffolding, creates new tape label with name <tapeName> */
1925 GetNewLabel(tapeInfoPtr, pName, AFSName, tapeLabel)
1926 struct butm_tapeInfo *tapeInfoPtr;
1927 char *pName, *AFSName;
1928 struct butm_tapeLabel *tapeLabel;
1931 struct timezone tzp;
1934 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1937 butm_GetSize(tapeInfoPtr, &size);
1939 size = globalTapeConfig.capacity;
1941 size = 0; /* no tape size */
1943 gettimeofday(&tp, &tzp);
1945 tapeLabel->structVersion = CUR_TAPE_VERSION;
1946 tapeLabel->creationTime = tp.tv_sec;
1947 tapeLabel->size = size;
1948 tapeLabel->expirationDate = 0; /* 1970 sometime */
1949 tapeLabel->dumpPath[0] = 0; /* no path name */
1950 tapeLabel->useCount = 0;
1951 strcpy(tapeLabel->AFSName, AFSName);
1952 strcpy(tapeLabel->pName, pName);
1953 strcpy(tapeLabel->cell, globalCellName);
1954 strcpy(tapeLabel->comment, "AFS Backup Software");
1955 strcpy(tapeLabel->creator.name, "AFS 3.6");
1956 strcpy(tapeLabel->creator.instance, "");
1957 strcpy(tapeLabel->creator.cell, globalCellName);
1960 /* extracts trailer out of buffer, nbytes is set to total data in buffer - trailer size */
1962 ExtractTrailer(buffer, size, nbytes, volTrailerPtr)
1966 struct volumeHeader *volTrailerPtr;
1970 struct volumeHeader tempTrailer;
1974 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1976 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1978 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1984 return 1; /* saw the trailer */
1990 return 0; /* did not see the trailer */
1994 FindVolTrailer(buffer, size, dSize, volTrailerPtr)
1997 struct volumeHeader *volTrailerPtr;
1998 afs_int32 *dSize; /* dataSize */
2000 afs_int32 offset, s;
2007 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2011 found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
2013 *dSize -= (s - offset);
2018 FindVolTrailer2(buffera, sizea, dataSizea, bufferb, sizeb, dataSizeb,
2022 afs_int32 *dataSizea;
2025 afs_int32 *dataSizeb;
2026 struct volumeHeader *volTrailerPtr;
2028 afs_int32 offset, s;
2029 afs_int32 headB, tailB;
2039 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2041 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
2044 headB = (s - sizeb); /*(s > sizeb) */
2045 if (headB > sizea) {
2052 memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
2054 memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
2056 memcpy(tapeVolumeHT + headB, bufferb, tailB);
2057 if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
2059 if (offset > headB) {
2060 /* *dataSizea remains unchanged */
2061 *dataSizeb = offset - headB;
2063 *dataSizea -= (headB - offset); /*(headB >= offset) */
2071 /* Returns true or false depending on whether the tape is expired or not */
2074 ExpirationDate(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 any tape
2086 * will be the most future expiration of any dump in the set. Can't use
2087 * bcdb_FindTape because dumpid here pertains to the initial dump id.
2089 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
2091 expiration = tapeEntry.expires;
2093 return (expiration);
2097 tapeExpired(tapeLabelPtr)
2098 struct butm_tapeLabel *tapeLabelPtr;
2102 struct timezone tzp;
2104 expiration = ExpirationDate(tapeLabelPtr->dumpid);
2106 expiration = tapeLabelPtr->expirationDate;
2108 gettimeofday(&tp, &tzp);
2109 return ((expiration < tp.tv_sec) ? 1 : 0);
2113 * given the label on the tape, delete any old information from the
2116 * Deletes all entries that match the volset.dumpnode
2117 * and the dump path.
2120 updateTapeLabel(labelIfPtr, tapeInfoPtr, newLabelPtr)
2121 struct labelTapeIf *labelIfPtr;
2122 struct butm_tapeInfo *tapeInfoPtr;
2123 struct butm_tapeLabel *newLabelPtr;
2125 struct butm_tapeLabel oldLabel;
2126 afs_int32 i, code = 0;
2128 int tapeIsLabeled = 0;
2129 int interactiveFlag;
2132 interactiveFlag = autoQuery;
2133 taskId = labelIfPtr->taskId;
2136 if (interactiveFlag) {
2138 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2139 labelIfPtr->taskId, tapecount);
2143 interactiveFlag = 1;
2146 /* mount the tape */
2147 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2149 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2153 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2157 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2158 && (strcmp(oldLabel.pName, "") != 0)) {
2159 /* We are setting the AFS name, yet tape
2160 * has a permanent name (not allowed).
2162 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2167 if (!tapeExpired(&oldLabel)) {
2168 if (!queryoperator) {
2169 TLog(taskId, "This tape has not expired\n");
2172 if (Ask("This tape has not expired - proceed") == 0)
2176 /* Keep the permanent name */
2177 if (strcmp(newLabelPtr->pName, "") == 0) {
2178 strcpy(newLabelPtr->pName, oldLabel.pName);
2179 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2180 strcpy(newLabelPtr->pName, "");
2184 /* extract useful information from the old label */
2185 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2186 newLabelPtr->dumpid = 0;
2187 newLabelPtr->useCount = oldLabel.useCount + 1;
2190 /* now write the new label */
2191 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2193 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2194 "Can't label tape\n");
2201 unmountTape(taskId, tapeInfoPtr);
2204 /* delete obsolete information from the database */
2205 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2206 /* delete based on dump id */
2207 if (oldLabel.dumpid) {
2208 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2209 if (i && (i != BUDB_NOENT))
2210 ErrorLog(0, taskId, i, 0,
2211 "Warning: Can't delete old dump %u from database\n",
2217 unmountTape(taskId, tapeInfoPtr);
2222 * LWP created by the server stub. Labels the tape with name and size
2223 * specified by <label>
2226 Labeller(labelIfPtr)
2227 struct labelTapeIf *labelIfPtr;
2229 struct tc_tapeLabel *label = &labelIfPtr->label;
2231 struct butm_tapeLabel newTapeLabel;
2232 struct butm_tapeInfo tapeInfo;
2236 taskId = labelIfPtr->taskId;
2237 setStatus(taskId, DRIVE_WAIT);
2238 EnterDeviceQueue(deviceLatch);
2239 clearStatus(taskId, DRIVE_WAIT);
2242 TLog(taskId, "Labeltape\n");
2244 memset(&tapeInfo, 0, sizeof(tapeInfo));
2245 tapeInfo.structVersion = BUTM_MAJORVERSION;
2246 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2248 ErrorLog(0, taskId, code, tapeInfo.error,
2249 "Can't initialize the tape module\n");
2253 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2255 newTapeLabel.size = label->size;
2257 newTapeLabel.size = globalTapeConfig.capacity;
2259 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2264 if (code == TC_ABORTEDBYREQUEST) {
2265 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2266 clearStatus(taskId, ABORT_REQUEST);
2267 setStatus(taskId, ABORT_DONE);
2269 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2270 setStatus(taskId, TASK_ERROR);
2272 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2273 TNAME(&newTapeLabel), newTapeLabel.size);
2275 setStatus(labelIfPtr->taskId, TASK_DONE);
2278 LeaveDeviceQueue(deviceLatch);
2283 * print out the tape label.
2286 PrintTapeLabel(labelptr)
2287 struct butm_tapeLabel *labelptr;
2289 char tapeName[BU_MAXTAPELEN + 32];
2292 printf("Tape label\n");
2293 printf("----------\n");
2294 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2295 printf("permanent tape name = %s\n", tapeName);
2296 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2297 printf("AFS tape name = %s\n", tapeName);
2298 t = labelptr->creationTime;
2299 printf("creationTime = %s", ctime(&t));
2300 if (labelptr->expirationDate) {
2301 t = labelptr->expirationDate;
2302 printf("expirationDate = %s", cTIME(&t));
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) ((char*)& vhptr.pad - (char*) & 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);