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>
13 #include <afs/procmgmt.h>
24 #include <afs/tcdata.h>
25 #include <afs/bubasics.h> /* PA */
26 #include <afs/budb_client.h>
27 #include <afs/bucoord_prototypes.h>
28 #include <afs/butm_prototypes.h>
29 #include <afs/volser.h>
30 #include <afs/volser_prototypes.h>
31 #include <afs/com_err.h>
32 #include <afs/afsutil.h>
34 #include "error_macros.h"
35 #include "butc_xbsa.h"
36 #include "butc_internal.h"
38 /* GLOBAL CONFIGURATION PARAMETERS */
39 extern int queryoperator;
40 extern int tapemounted;
41 extern char *opencallout;
42 extern char *closecallout;
44 extern char *extractDumpName(char *);
45 extern int BufferSize; /* Size in B stored for header info */
46 FILE *restoretofilefd;
48 extern char *restoretofile;
49 extern int forcemultiple;
52 /* XBSA Global Parameters */
55 struct butx_transactionInfo butxInfo;
58 static struct TapeBlock { /* A 16KB tapeblock */
59 char mark[BUTM_HDRSIZE]; /* Header info */
60 char data[BUTM_BLKSIZE]; /* data */
63 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
64 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
67 * Need to re-write to:
68 * 1) non-interactive tape handling (optional)
69 * 2) compute tape and volume sizes for the database
70 * 3) compute and use tape id's for tape tracking (put on tape label)
71 * 4) status management
74 /* All the relevant info shared between Restorer and restoreVolume */
75 struct restoreParams {
76 struct dumpNode *nodePtr;
78 char mntTapeName[BU_MAXTAPELEN];
80 struct butm_tapeInfo *tapeInfoPtr;
83 /* Abort checks are done after each BIGCHUNK of data transfer */
84 #define BIGCHUNK 102400
86 #define HEADER_CHECKS(vhptr, header) \
88 afs_int32 magic, versionflags; \
90 versionflags = ntohl(vhptr.versionflags); \
91 if ( versionflags == TAPE_VERSION_0 || \
92 versionflags == TAPE_VERSION_1 || \
93 versionflags == TAPE_VERSION_2 || \
94 versionflags == TAPE_VERSION_3 || \
95 versionflags == TAPE_VERSION_4 ) { \
97 magic = ntohl(vhptr.magic); /* another sanity check */ \
98 if (magic == TC_VOLBEGINMAGIC || \
99 magic == TC_VOLENDMAGIC || \
100 magic == TC_VOLCONTD ) { \
102 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
105 } /* versionflags */ \
109 extern FILE *ErrorlogIO;
110 extern FILE *centralLogIO;
111 extern FILE *lastLogIO;
112 extern afs_int32 lastPass; /* Set true during last pass of dump */
113 extern int debugLevel;
114 extern int autoQuery;
115 extern struct tapeConfig globalTapeConfig;
116 extern struct deviceSyncNode *deviceLatch;
117 extern char globalCellName[];
121 /* forward declaration */
122 afs_int32 readVolumeHeader(char *, afs_int32, struct volumeHeader *);
123 int FindVolTrailer(char *, afs_int32, afs_int32 *, struct volumeHeader *);
124 int FindVolTrailer2(char *, afs_int32, afs_int32 *, char *, afs_int32,
125 afs_int32 *, struct volumeHeader *);
126 int SkipVolume(struct tc_restoreDesc *, afs_int32, afs_int32, afs_int32,
131 /* The on-disk volume header or trailer can differ in size from platform to platform */
132 static struct TapeBlock tapeBlock;
133 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
136 PrintLogStr(FILE *log, afs_int32 error1, afs_int32 error2, char *str)
140 fprintf(log, "%s", str);
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 TapeLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
198 char tbuffer[32], *timestr;
201 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
204 fprintf(logIO, "%s: ", timestr);
206 fprintf(logIO, "Task %u: ", task);
207 PrintLogStr(logIO, error1, error2, str);
209 if (lastPass && lastLogIO) {
210 fprintf(lastLogIO, "%s: ", timestr);
212 fprintf(lastLogIO, "Task %u: ", task);
213 PrintLogStr(lastLogIO, error1, error2, str);
216 /* Now print to the screen if debug level requires */
217 if (debug <= debugLevel)
218 PrintLogStr(stdout, error1, error2, str);
222 TapeLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
229 vsnprintf(tmp, sizeof(tmp), fmt, ap);
232 TapeLogStr(debug, task, error1, error2, tmp);
236 TLog(afs_int32 task, char *fmt, ...)
242 vsnprintf(tmp, sizeof(tmp), fmt, ap);
245 /* Sends message to TapeLog and stdout */
246 TapeLogStr(0, task, 0, 0, tmp);
250 ErrorLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
254 char tbuffer[32], *timestr;
257 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
259 fprintf(ErrorlogIO, "%s: ", timestr);
261 /* Print the time and task number */
263 fprintf(ErrorlogIO, "Task %u: ", task);
265 PrintLogStr(ErrorlogIO, error1, error2, errStr);
266 TapeLogStr(debug, task, error1, error2, errStr);
270 ErrorLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
277 vsnprintf(tmp, sizeof(tmp), fmt, ap);
280 ErrorLogStr(debug, task, error1, error2, tmp);
285 ELog(afs_int32 task, char *fmt, ...)
291 vsnprintf(tmp, sizeof(tmp), fmt, ap);
294 /* Sends message to ErrorLog, TapeLog and stdout */
295 ErrorLog(0, task, 0, 0, "%s", tmp);
298 /* first proc called by anybody who intends to use the device */
300 EnterDeviceQueue(struct deviceSyncNode *devLatch)
302 ObtainWriteLock(&(devLatch->lock));
303 devLatch->flags = TC_DEVICEINUSE;
306 /* last proc called by anybody finishing using the device */
308 LeaveDeviceQueue(struct deviceSyncNode *devLatch)
311 ReleaseWriteLock(&(devLatch->lock));
314 #define BELLTIME 60 /* 60 seconds before a bell rings */
315 #define BELLCHAR 7 /* ascii for bell */
321 * only external clients are in recoverDb.c. Was static. PA
331 w = LWP_WaitForKeystroke(0);
337 #endif /* AFS_NT40_ENV */
345 callOutRoutine(afs_int32 taskId, char *tapePath, int flag, char *name,
346 afs_uint32 dbDumpId, int tapecount)
362 callOut = opencallout;
365 strcpy(Sopcode, "restore");
368 strcpy(Sopcode, "appenddump");
371 strcpy(Sopcode, "dump");
374 strcpy(Sopcode, "labeltape");
376 case READLABELOPCODE:
377 strcpy(Sopcode, "readlabel");
380 strcpy(Sopcode, "scantape");
382 case RESTOREDBOPCODE:
383 strcpy(Sopcode, "restoredb");
386 strcpy(Sopcode, "savedb");
389 strcpy(Sopcode, "unmount");
390 callOut = closecallout;
393 strcpy(Sopcode, "unknown");
397 if (!callOut) /* no script to call */
400 strcpy(ScallOut, callOut);
401 CO_argv[0] = ScallOut;
403 strcpy(StapePath, tapePath);
404 CO_argv[1] = StapePath;
406 CO_argv[2] = Sopcode;
408 if (flag == CLOSEOPCODE) {
411 sprintf(Scount, "%d", tapecount);
414 /* The tape label name - special case labeltape */
415 if (!name || (strcmp(name, "") == 0)) /* no label */
416 strcpy(Stape, "none");
417 else { /* labeltape */
419 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
420 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
429 strcpy(Sdumpid, "none");
431 sprintf(Sdumpid, "%u", dbDumpId);
432 CO_argv[5] = Sdumpid;
439 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
441 ErrorLog(0, taskId, errno, 0,
442 "Call to %s outside routine %s failed\n", Sopcode, callOut);
451 * Unmounts a tape and prints a warning if it can't unmount it.
452 * Regardless of error, the closecallout routine will be called
453 * (unless a tape is not mounted in the first place).
456 unmountTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr)
459 int cpid, status, rcpid;
461 code = butm_Dismount(tapeInfoPtr);
462 if (code && (code != BUTM_NOMOUNT))
463 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
464 "Warning: Can't close tape\n");
466 if (tapemounted && closecallout) {
467 setStatus(taskId, CALL_WAIT);
470 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
472 while (cpid) { /* Wait until return */
474 rcpid = waitpid(cpid, &status, WNOHANG);
479 if (rcpid == -1 && errno != EINTR) {
481 afs_com_err(whoami, errno,
482 "Error waiting for callout script to terminate.");
485 #ifdef AFS_PTHREAD_ENV
491 if (checkAbortByTaskId(taskId)) {
492 TLog(taskId, "Callout routine has been aborted\n");
493 if (kill(cpid, SIGKILL)) /* Cancel callout */
494 ErrorLog(0, taskId, errno, 0,
495 "Kill of callout process %d failed\n", cpid);
500 clearStatus(taskId, CALL_WAIT);
504 * print out prompt to operator
506 * PromptForTape only.
510 PrintPrompt(int flag, char *name, int dumpid)
512 char tapename[BU_MAXTAPELEN + 32];
515 TAPENAME(tapename, name, dumpid);
517 printf("******* OPERATOR ATTENTION *******\n");
518 printf("Device : %s \n", globalTapeConfig.device);
521 case READOPCODE: /* mount for restore */
522 printf("Please put in tape %s for reading", tapename);
525 case APPENDOPCODE: /* mount for dump (appends) */
527 dn = extractDumpName(name);
530 printf("Please put in last tape of dump set for appending dump");
533 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
537 case WRITEOPCODE: /* mount for dump */
538 if (strcmp(name, "") == 0)
539 printf("Please put in tape for writing");
541 /* The name is what we are going to label the tape as */
543 printf("Please put in tape %s for writing", tapename);
546 case LABELOPCODE: /* mount for labeltape */
547 printf("Please put in tape to be labelled as %s", tapename);
550 case READLABELOPCODE: /* mount for readlabel */
551 printf("Please put in tape whose label is to be read");
554 case SCANOPCODE: /* mount for scantape */
555 if (strcmp(name, "") == 0)
556 printf("Please put in tape to be scanned");
558 printf("Please put in tape %s for scanning", tapename);
561 case RESTOREDBOPCODE: /* Mount for restoredb */
562 printf("Please insert a tape %s for the database restore", tapename);
565 case SAVEDBOPCODE: /* Mount for savedb */
566 printf("Please insert a writeable tape %s for the database dump",
573 printf(" and hit return when done\n");
577 * Prompt the operator to change the tape.
578 * Use to be a void routine but now returns an error. Some calls
579 * don't use the error code.
581 * only external clients are in recoverDb.c. Was static PA
584 PromptForTape(int flag, char *name, afs_uint32 dbDumpId, afs_uint32 taskId,
592 int cpid, status, rcpid;
594 if (checkAbortByTaskId(taskId))
595 ERROR_EXIT(TC_ABORTEDBYREQUEST);
598 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
600 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
602 CallOut = (opencallout ? 1 : 0);
604 setStatus(taskId, CALL_WAIT);
607 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
608 dbDumpId, tapecount);
610 CallOut = 0; /* prompt at screen */
612 while (CallOut) { /* Check if callout routine finished */
614 rcpid = waitpid(cpid, &status, WNOHANG);
618 else if (WIFEXITED(status))
619 wcode = WEXITSTATUS(status);
624 break; /* All done */
625 } else if (wcode == 1) {
626 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
627 } else if ((flag == READOPCODE) && (wcode == 3)) {
628 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
631 "Callout routine has exited with code %d: will prompt\n",
633 CallOut = 0; /* Switch to keyboard input */
637 /* if waitpid experienced an error, we prompt */
638 if (rcpid == -1 && errno != EINTR) {
639 afs_com_err(whoami, errno,
640 "Error waiting for callout script to terminate.");
642 "Can't get exit status from callout script. will prompt\n");
646 #ifdef AFS_PTHREAD_ENV
652 if (checkAbortByTaskId(taskId)) {
654 ("This tape operation has been aborted by the coordinator.\n");
656 if (kill(cpid, SIGKILL)) /* Cancel callout */
657 ErrorLog(0, taskId, errno, 0,
658 "Kill of callout process %d failed\n", cpid);
660 ERROR_EXIT(TC_ABORTEDBYREQUEST);
666 clearStatus(taskId, CALL_WAIT);
667 setStatus(taskId, OPR_WAIT);
669 PrintPrompt(flag, name, dbDumpId);
671 /* Loop until we get ok to go ahead (or abort) */
673 if (time(0) > start + BELLTIME) {
679 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
680 if (wcode == 1) { /* keyboard input is available */
682 if ((inchr == 'a') || (inchr == 'A')) {
683 printf("This tape operation has been aborted.\n");
684 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
685 } else if ((flag == READOPCODE)
686 && ((inchr == 's') || (inchr == 'S'))) {
687 printf("This tape will be skipped.\n");
688 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
690 break; /* continue */
693 if (checkAbortByTaskId(taskId)) {
695 ("This tape operation has been aborted by the coordinator.\n");
696 ERROR_EXIT(TC_ABORTEDBYREQUEST);
702 printf("Thanks, now proceeding with tape ");
704 case RESTOREDBOPCODE:
710 printf("append writing");
722 case READLABELOPCODE:
723 printf("label reading");
735 printf(" operation.\n");
737 printf("**********************************\n");
739 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
743 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
749 * convert the fields in the tapeVolHeader into host byte order,
750 * placing the converted copy of the structure into the hostVolHeader
752 * tapeVolHeader - points to volume header read from tape
753 * hostVolHeader - pointer to struct for result
755 * hostVolHeader - information in host byte order
759 VolHeaderToHost(struct volumeHeader *hostVolHeader,
760 struct volumeHeader *tapeVolHeader)
762 switch (ntohl(tapeVolHeader->versionflags)) {
764 /* sizes in bytes and fields in host order */
765 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
770 case TAPE_VERSION_3: /* for present */
772 /* sizes in K and fields in network order */
773 /* do the conversion field by field */
775 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
776 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
777 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
778 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
779 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
780 hostVolHeader->server = ntohl(tapeVolHeader->server);
781 hostVolHeader->part = ntohl(tapeVolHeader->part);
782 hostVolHeader->from = ntohl(tapeVolHeader->from);
783 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
784 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
785 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
786 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
787 hostVolHeader->level = ntohl(tapeVolHeader->level);
788 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
789 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
790 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
791 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
795 return (TC_BADVOLHEADER);
801 ReadVolHeader(afs_int32 taskId,
802 struct butm_tapeInfo *tapeInfoPtr,
803 struct volumeHeader *volHeaderPtr)
807 struct volumeHeader volHead;
809 /* Read the volume header */
811 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
814 ErrorLog(0, taskId, code, tapeInfoPtr->error,
815 "Can't read volume header on tape\n");
819 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
821 ErrorLog(0, taskId, code, 0,
822 "Can't find volume header on tape block\n");
826 code = VolHeaderToHost(volHeaderPtr, &volHead);
828 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
837 GetVolumeHead(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
838 afs_int32 position, char *volName, afs_int32 volId)
841 struct volumeHeader tapeVolHeader;
843 /* Position directly to the volume and read the header */
845 code = butm_Seek(tapeInfoPtr, position);
847 ErrorLog(0, taskId, code, tapeInfoPtr->error,
848 "Can't seek to position %u on tape\n", position);
852 code = butm_ReadFileBegin(tapeInfoPtr);
854 ErrorLog(0, taskId, code, tapeInfoPtr->error,
855 "Can't read FileBegin on tape\n");
859 /* Read the volume header */
860 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
864 /* Check if volume header matches */
865 if (strcmp(tapeVolHeader.volumeName, volName))
866 ERROR_EXIT(TC_BADVOLHEADER);
867 if (volId && (tapeVolHeader.volumeID != volId))
868 ERROR_EXIT(TC_BADVOLHEADER);
869 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
870 ERROR_EXIT(TC_BADVOLHEADER);
873 /* Do a sequential search for the volume */
876 code = butm_ReadFileBegin(tapeInfoPtr);
878 ErrorLog(0, taskId, code, tapeInfoPtr->error,
879 "Can't read FileBegin on tape\n");
883 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
885 ERROR_EXIT(TC_VOLUMENOTONTAPE);
887 /* Test if we found the volume */
888 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
889 && (!volId || (volId == tapeVolHeader.volumeID)))
892 /* skip to the next HW EOF marker */
893 code = SeekFile(tapeInfoPtr, 1);
895 ErrorLog(0, taskId, code, tapeInfoPtr->error,
896 "Can't seek to next EOF on tape\n");
907 GetRestoreTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
908 char *tname, afs_int32 tapeID, int prompt)
910 struct butm_tapeLabel tapeLabel;
911 afs_int32 code = 0, rc;
913 struct budb_dumpEntry dumpEntry;
915 /* Make sure that the dump/tape is not a XBSA dump */
916 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
917 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
918 ErrorLog(0, taskId, 0, 0,
919 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
920 ERROR_EXIT(TC_SKIPTAPE);
926 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
933 code = butm_Mount(tapeInfoPtr, tname);
935 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
939 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
941 ErrorLog(0, taskId, code, tapeInfoPtr->error,
942 "Can't read tape label\n");
946 /* Now check the label to see if the tapename matches or tapeids match */
947 if (strcmp(TNAME(&tapeLabel), tname)
948 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
949 && (tapeLabel.dumpid != tapeID))) {
950 char expectedName[BU_MAXTAPELEN + 32],
951 gotName[BU_MAXTAPELEN + 32];
953 TAPENAME(expectedName, tname, tapeID);
954 LABELNAME(gotName, &tapeLabel);
956 TapeLog(0, taskId, 0, 0,
957 "Tape label expected %s, label seen %s\n", expectedName,
965 unmountTape(taskId, tapeInfoPtr);
973 xbsaRestoreVolumeData(struct rx_call *call, void *rock)
977 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
978 afs_int32 curChunk, rc;
979 afs_uint32 totalWritten;
980 afs_int32 headBytes, tailBytes, w;
982 struct volumeHeader volTrailer;
983 afs_int32 vtsize = 0;
985 struct dumpNode *nodePtr;
986 struct tc_restoreDesc *Restore;
987 afs_int32 bytesRead, tbuffersize, endData = 0;
988 char *buffer = (char *)bufferBlock, tbuffer[256];
990 nodePtr = rparamsPtr->nodePtr;
991 Restore = nodePtr->restores;
992 taskId = nodePtr->taskID;
994 /* Read the volume fragment one block at a time until
995 * find a volume trailer
997 curChunk = BIGCHUNK + 1;
1002 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1004 if (restoretofile && (bytesRead > 0)) {
1005 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1007 if (rc != XBSA_SUCCESS) {
1008 ErrorLog(0, taskId, rc, 0,
1009 "Unable to read volume data from the server\n");
1013 /* Periodically update status structure and check if should abort */
1014 curChunk += bytesRead;
1015 if (curChunk > BIGCHUNK) {
1018 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1021 if (checkAbortByTaskId(taskId))
1022 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1025 if (!endData && (bytesRead > 0)) {
1026 /* Fill tbuffer up with data from end of buffer and write
1027 * the remainder of buffer out.
1029 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1030 /* Write out contents of tbuffer */
1032 w = rx_Write(call, tbuffer, tbuffersize);
1033 if (w != tbuffersize) {
1034 ErrorLog(0, taskId, -1, 0,
1035 "Error in RX write: Wrote %d bytes\n", w);
1040 /* fill tbuffer with end of buffer */
1041 bytesRead -= sizeof(tbuffer);
1042 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1043 tbuffersize = sizeof(tbuffer);
1044 /* Write out whatever is left over in buffer */
1046 w = rx_Write(call, buffer, bytesRead);
1047 if (w != bytesRead) {
1048 ErrorLog(0, taskId, -1, 0,
1049 "Error in RX data write: Wrote %d bytes\n",
1056 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1057 /* Copy all of buffer into tbuffer (it will fit) */
1058 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1059 tbuffersize += bytesRead;
1062 /* We need to write some of tbuffer out and fill it with buffer */
1063 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1064 w = rx_Write(call, tbuffer, towrite);
1066 ErrorLog(0, taskId, -1, 0,
1067 "Error in RX write: Wrote %d bytes\n", w);
1073 /* Move the data in tbuffer up */
1074 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1076 /* Now copy buffer in */
1077 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1078 tbuffersize += bytesRead;
1084 /* Pull the volume trailer from the last two buffers */
1086 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1087 &tailBytes, &volTrailer);
1090 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1091 ERROR_EXIT(TC_MISSINGTRAILER);
1094 /* Now rx_write the data in the last two blocks */
1096 w = rx_Write(call, tbuffer, headBytes);
1097 if (w != headBytes) {
1098 ErrorLog(0, taskId, -1, 0,
1099 "Error in RX trail1 write: Wrote %d bytes\n", w);
1105 w = rx_Write(call, buffer, tailBytes);
1106 if (w != tailBytes) {
1107 ErrorLog(0, taskId, -1, 0,
1108 "Error in RX trail2 write: Wrote %d bytes\n", w);
1120 * sends the contents of volume dump to Rx Stream associated
1125 restoreVolumeData(struct rx_call *call, void *rock)
1127 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
1129 afs_uint32 totalWritten = 0;
1131 afs_int32 headBytes, tailBytes, w;
1133 afs_int32 nbytes; /* # bytes data in last tape block read */
1134 struct volumeHeader tapeVolTrailer;
1137 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1138 struct tc_restoreDesc *Restore;
1139 struct dumpNode *nodePtr;
1140 struct butm_tapeInfo *tapeInfoPtr;
1142 afs_int32 origVolID;
1144 nodePtr = rparamsPtr->nodePtr;
1145 taskId = nodePtr->taskID;
1146 Restore = nodePtr->restores;
1147 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1148 origVolName = Restore[rparamsPtr->frag].oldName;
1149 origVolID = Restore[rparamsPtr->frag].origVid;
1151 /* Read the volume one fragment at a time */
1152 while (rparamsPtr->frag < nodePtr->arraySize) {
1154 curChunk = BIGCHUNK + 1; /* Check if should abort */
1156 /* Read the volume fragment one block at a time until
1157 * find a volume trailer
1163 while (moretoread) {
1164 /* Fill the circular buffer with tape blocks
1165 * Search for volume trailer in the process.
1170 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1171 BUTM_BLKSIZE, &nbytes);
1173 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1174 "Can't read FileData on tape %s\n",
1175 rparamsPtr->mntTapeName);
1178 curChunk += BUTM_BLKSIZE;
1180 /* Periodically update status structure and check if should abort */
1181 if (curChunk > BIGCHUNK) {
1185 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1188 if (checkAbortByTaskId(taskId))
1189 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1192 /* step to next block in buffer */
1194 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1196 /* If this is the end of the volume, the exit the loop */
1197 if ((nbytes != BUTM_BLKSIZE)
1200 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1204 } while (moretoread && (buf != endRbuf));
1206 /* Write the buffer upto (but not including) the last read block
1207 * If volume is completely read, then leave the last two blocks.
1209 lastbuf = endWbuf = pbuf;
1210 if (!moretoread && (endWbuf != startWbuf))
1211 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1213 for (buf = startWbuf; buf != endWbuf;
1214 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1215 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1216 if (w != BUTM_BLKSIZE) {
1217 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1220 totalWritten += BUTM_BLKSIZE;
1223 /* Setup pointers to refill buffer */
1224 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1226 startWbuf = endWbuf;
1229 /* lastbuf is last block read and it has nbytes of data
1230 * startWbuf is the 2nd to last block read
1231 * Seach for the volume trailer in these two blocks.
1233 if (lastbuf == startWbuf)
1235 FindVolTrailer2(NULL, 0, &headBytes,
1236 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1240 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1241 &headBytes, bufferBlock[lastbuf].data, nbytes,
1242 &tailBytes, &tapeVolTrailer);
1244 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1245 "Missing volume trailer on tape %s\n",
1246 rparamsPtr->mntTapeName);
1247 ERROR_EXIT(TC_MISSINGTRAILER);
1250 /* Now rx_write the data in the last two blocks */
1252 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1253 if (w != headBytes) {
1254 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1257 totalWritten += headBytes;
1260 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1261 if (w != tailBytes) {
1262 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1265 totalWritten += tailBytes;
1268 /* Exit the loop if the volume is not continued on next tape */
1269 if (!tapeVolTrailer.contd)
1270 break; /* We've read the entire volume */
1272 /* Volume is continued on next tape.
1273 * Step to the next volume fragment and prompt for its tape.
1274 * When a volume has multiple frags, those frags are on different
1275 * tapes. So we know that we need to prompt for a tape.
1278 if (rparamsPtr->frag >= nodePtr->arraySize)
1281 unmountTape(taskId, tapeInfoPtr);
1282 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1283 rparamsPtr->tapeID =
1284 (Restore[rparamsPtr->frag].
1285 initialDumpId ? Restore[rparamsPtr->frag].
1286 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1288 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1289 rparamsPtr->tapeID, 1);
1293 /* Position to the frag and read the volume header */
1295 GetVolumeHead(taskId, tapeInfoPtr,
1296 Restore[rparamsPtr->frag].position, origVolName,
1299 ErrorLog(0, taskId, code, 0,
1300 "Can't find volume %s (%u) on tape %s\n", origVolName,
1301 origVolID, rparamsPtr->mntTapeName);
1302 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1311 * Find all the volumes on a specific tape and mark them to skip.
1314 SkipTape(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1315 char *tapename, afs_int32 tapeid, afs_int32 taskid)
1319 for (i = index; i < size; i++) {
1320 if (Restore[i].flags & RDFLAG_SKIP)
1323 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1325 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1326 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1333 * Find all the entries for a volume and mark them to skip.
1336 SkipVolume(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1337 afs_int32 volid, afs_int32 taskid)
1342 for (i = index; i < size; i++) {
1343 if (Restore[i].flags & RDFLAG_SKIP)
1345 if (Restore[i].origVid == volid) {
1346 Restore[i].flags |= RDFLAG_SKIP;
1348 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1349 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1350 Restore[i].oldName, volid);
1359 xbsaRestoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1360 struct restoreParams *rparamsPtr)
1365 afs_int32 newServer, newPart, newVolId;
1367 int restoreflags, havetrans = 0, startread = 0;
1368 afs_int32 bytesRead, endData = 0;
1370 struct budb_dumpEntry dumpEntry;
1371 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1372 struct volumeHeader volHeader, hostVolHeader;
1374 if (restoretofile) {
1375 restoretofilefd = fopen(restoretofile, "w+");
1378 dumpID = restoreInfo->dbDumpId;
1380 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1382 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1387 /* ADSM servers restore ADSM and BUTA dumps */
1388 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1389 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1391 "The dump requested by this restore operation for the "
1392 "volumeset is incompatible with this instance of butc\n");
1393 /* Skip the entire dump (one dump per tape) */
1394 ERROR_EXIT(TC_SKIPTAPE);
1397 /* make sure we are connected to the correct server. */
1398 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1399 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1401 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1402 && !forcemultiple) {
1404 "Dump %d is on server %s but butc is connected "
1405 "to server %s (attempting to restore)\n", dumpID,
1406 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1409 "Dump %d is on server %s but butc is connected "
1410 "to server %s (switching servers)\n", dumpID,
1411 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1413 rc = InitToServer(taskId, &butxInfo,
1414 (char *)dumpEntry.tapes.tapeServer);
1415 if (rc != XBSA_SUCCESS)
1416 ERROR_EXIT(TC_SKIPTAPE);
1420 /* Start a transaction and query the server for the correct fileset dump */
1421 rc = xbsa_BeginTrans(&butxInfo);
1422 if (rc != XBSA_SUCCESS) {
1423 ELog(taskId, "Unable to create a new transaction\n");
1424 ERROR_EXIT(TC_SKIPTAPE);
1428 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1429 sprintf(dumpIdStr, "/%d", dumpID);
1430 strcpy(volumeNameStr, "/");
1431 strcat(volumeNameStr, restoreInfo->oldName);
1432 } else { /* new butc names */
1433 extern char *butcdumpIdStr;
1434 strcpy(dumpIdStr, butcdumpIdStr);
1435 sprintf(volumeNameStr, "/%d", dumpID);
1436 strcat(volumeNameStr, "/");
1437 strcat(volumeNameStr, restoreInfo->oldName);
1440 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1441 if (rc != XBSA_SUCCESS) {
1443 "Unable to locate object (%s) of dump (%s) on the server\n",
1444 volumeNameStr, dumpIdStr);
1448 rc = xbsa_EndTrans(&butxInfo);
1450 if (rc != XBSA_SUCCESS) {
1451 ELog(taskId, "Unable to terminate the current transaction\n");
1455 if (checkAbortByTaskId(taskId))
1456 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1458 /* Now start a transaction on the volume to restore and read the
1459 * volumeheader. We do this before starting a transaction on
1460 * volserver to restore the volume because the XBSA server may take
1461 * a while to mount and seek to the volume causing the volserver to
1464 rc = xbsa_BeginTrans(&butxInfo);
1465 if (rc != XBSA_SUCCESS) {
1466 ELog(taskId, "Unable to create a new transaction\n");
1467 ERROR_EXIT(TC_SKIPTAPE);
1471 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1472 sizeof(volHeader), &bytesRead, &endData);
1473 if (restoretofile && (bytesRead > 0)) {
1474 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1476 if (rc != XBSA_SUCCESS) {
1478 "Unable to begin reading of the volume from the server\n");
1483 if ((bytesRead != sizeof(volHeader)) || endData) {
1485 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1486 bytesRead, sizeof(volHeader));
1487 ERROR_EXIT(TC_BADVOLHEADER);
1490 /* convert and check the volume header */
1491 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1493 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1497 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1498 || (restoreInfo->origVid
1499 && (hostVolHeader.volumeID != restoreInfo->origVid))
1500 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1501 ERROR_EXIT(TC_BADVOLHEADER);
1503 /* Set up prior restoring volume data */
1504 newVolName = restoreInfo->newName;
1505 newVolId = restoreInfo->vid;
1506 newServer = restoreInfo->hostAddr;
1507 newPart = restoreInfo->partition;
1509 if ((restoreInfo->dumpLevel == 0)
1510 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1511 restoreflags |= RV_FULLRST;
1512 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1513 restoreflags |= RV_OFFLINE;
1515 if (checkAbortByTaskId(taskId))
1516 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1518 /* Start the restore of the volume data. This is the code we want to return */
1520 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1521 restoreflags, xbsaRestoreVolumeData,
1522 (char *)rparamsPtr);
1525 rc = xbsa_ReadObjectEnd(&butxInfo);
1526 if (rc != XBSA_SUCCESS) {
1528 "Unable to terminate reading of the volume from the server\n");
1534 rc = xbsa_EndTrans(&butxInfo);
1535 if (rc != XBSA_SUCCESS) {
1536 ELog(taskId, "Unable to terminate the current transaction\n");
1542 if (restoretofile && restoretofilefd) {
1543 fclose(restoretofilefd);
1550 restoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1551 struct restoreParams *rparamsPtr)
1553 afs_int32 code = 0, rc;
1554 afs_int32 newServer, newPart, newVolId;
1558 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1560 /* Check if we need a tape and prompt for one if so */
1562 (restoreInfo->initialDumpId ? restoreInfo->
1563 initialDumpId : restoreInfo->dbDumpId);
1564 if ((rparamsPtr->frag == 0)
1565 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1566 || (tapeID != rparamsPtr->tapeID)) {
1567 /* Unmount the previous tape */
1568 unmountTape(taskId, tapeInfoPtr);
1570 /* Remember this new tape */
1571 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1572 rparamsPtr->tapeID = tapeID;
1574 /* Mount a new tape */
1575 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1577 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1582 /* Seek to the correct spot and read the header information */
1583 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1584 restoreInfo->oldName, restoreInfo->origVid);
1588 /* Set up prior restoring volume data */
1589 newVolName = restoreInfo->newName;
1590 newVolId = restoreInfo->vid;
1591 newServer = restoreInfo->hostAddr;
1592 newPart = restoreInfo->partition;
1594 if ((restoreInfo->dumpLevel == 0)
1595 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1596 restoreflags |= RV_FULLRST;
1597 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1598 restoreflags |= RV_OFFLINE;
1600 if (checkAbortByTaskId(taskId))
1601 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1603 /* Start the restore of the volume data. This is the code we
1607 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1608 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1610 /* Read the FileEnd marker for the volume and step to next FM */
1611 rc = butm_ReadFileEnd(tapeInfoPtr);
1613 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1614 "Can't read EOF on tape\n");
1622 * created as a LWP by the server stub, <newNode> is a pointer to all
1623 * the parameters Restorer needs
1626 Restorer(void *param) {
1627 struct dumpNode *newNode = (struct dumpNode *) param;
1629 afs_int32 code = 0, tcode;
1632 struct butm_tapeInfo tapeInfo;
1633 struct tc_restoreDesc *Restore;
1634 struct tc_restoreDesc *RestoreDesc;
1635 struct restoreParams rparams;
1636 afs_int32 allocbufferSize;
1637 time_t startTime, endTime;
1638 afs_int32 goodrestore = 0;
1640 taskId = newNode->taskID;
1641 setStatus(taskId, DRIVE_WAIT);
1642 EnterDeviceQueue(deviceLatch);
1643 clearStatus(taskId, DRIVE_WAIT);
1646 TLog(taskId, "Restore\n");
1648 memset(&tapeInfo, 0, sizeof(tapeInfo));
1650 tapeInfo.structVersion = BUTM_MAJORVERSION;
1651 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1653 ErrorLog(0, taskId, tcode, tapeInfo.error,
1654 "Can't initialize the tape module\n");
1659 if (checkAbortByTaskId(taskId))
1660 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1662 memset(&rparams, 0, sizeof(rparams));
1663 rparams.nodePtr = newNode;
1664 rparams.tapeInfoPtr = &tapeInfo;
1665 Restore = newNode->restores; /* Array of vol fragments to restore */
1667 /* Allocate memory in which to restore the volumes data into */
1669 allocbufferSize = dataSize = BufferSize;
1671 /* Must have at least two tape blocks */
1672 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1675 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1678 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1680 ERROR_EXIT(TC_NOMEMORY);
1681 memset(bufferBlock, 0, allocbufferSize);
1683 startTime = time(0);
1684 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1686 RestoreDesc = &Restore[rparams.frag];
1688 /* Skip the volume if it was requested to */
1689 if (RestoreDesc->flags & RDFLAG_SKIP) {
1690 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1691 /* If the volume was restored, should bring it online */
1696 newVolName = RestoreDesc->newName;
1698 /* Make sure the server to restore to is good */
1699 if (!RestoreDesc->hostAddr) {
1700 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1702 ERROR_EXIT(TC_INTERNALERROR);
1705 if (checkAbortByTaskId(taskId))
1706 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1708 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1710 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1714 /* restoreVolume function takes care of all the related fragments
1715 * spanning various tapes. On return the complete volume has been
1719 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1721 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1724 if (tcode == TC_ABORTEDBYREQUEST) {
1726 } else if (tcode == TC_SKIPTAPE) {
1729 (RestoreDesc->initialDumpId ? RestoreDesc->
1730 initialDumpId : RestoreDesc->dbDumpId);
1731 SkipTape(Restore, newNode->arraySize, rparams.frag,
1732 RestoreDesc->tapeName, tapeID, taskId);
1734 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1736 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1737 RestoreDesc->origVid, taskId);
1749 unmountTape(taskId, &tapeInfo);
1752 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1759 if (code == TC_ABORTEDBYREQUEST) {
1760 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1761 clearStatus(taskId, ABORT_REQUEST);
1762 setStatus(taskId, ABORT_DONE);
1764 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1765 setStatus(taskId, TASK_ERROR);
1767 TLog(taskId, "Restore: Finished\n");
1770 if (centralLogIO && startTime) {
1772 afs_int32 hrs, min, sec, tmp;
1774 struct tm tmstart, tmend;
1776 localtime_r(&startTime, &tmstart);
1777 localtime_r(&endTime, &tmend);
1778 timediff = (int)endTime - (int)startTime;
1779 hrs = timediff / 3600;
1780 tmp = timediff % 3600;
1785 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1786 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1787 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1788 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1789 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1790 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1791 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1792 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1794 fwrite(line, strlen(line), 1, centralLogIO);
1795 fflush(centralLogIO);
1798 setStatus(taskId, TASK_DONE);
1801 LeaveDeviceQueue(deviceLatch);
1802 return (void *)(intptr_t)(code);
1805 /* this is just scaffolding, creates new tape label with name <tapeName> */
1808 GetNewLabel(struct butm_tapeInfo *tapeInfoPtr, char *pName, char *AFSName,
1809 struct butm_tapeLabel *tapeLabel)
1812 struct timezone tzp;
1815 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1818 butm_GetSize(tapeInfoPtr, &size);
1820 size = globalTapeConfig.capacity;
1822 size = 0; /* no tape size */
1824 gettimeofday(&tp, &tzp);
1826 tapeLabel->structVersion = CUR_TAPE_VERSION;
1827 tapeLabel->creationTime = tp.tv_sec;
1828 tapeLabel->size = size;
1829 tapeLabel->expirationDate = 0; /* 1970 sometime */
1830 tapeLabel->dumpPath[0] = 0; /* no path name */
1831 tapeLabel->useCount = 0;
1832 strcpy(tapeLabel->AFSName, AFSName);
1833 strcpy(tapeLabel->pName, pName);
1834 strcpy(tapeLabel->cell, globalCellName);
1835 strcpy(tapeLabel->comment, "AFS Backup Software");
1836 strcpy(tapeLabel->creator.name, "AFS 3.6");
1837 strcpy(tapeLabel->creator.instance, "");
1838 strcpy(tapeLabel->creator.cell, globalCellName);
1841 /* extracts trailer out of buffer, nbytes is set to total data in
1842 * buffer - trailer size */
1844 ExtractTrailer(char *buffer, afs_int32 size, afs_int32 *nbytes,
1845 struct volumeHeader *volTrailerPtr)
1849 struct volumeHeader tempTrailer;
1853 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1855 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1857 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1863 return 1; /* saw the trailer */
1869 return 0; /* did not see the trailer */
1873 FindVolTrailer(char *buffer, afs_int32 size, afs_int32 *dSize,
1874 struct volumeHeader *volTrailerPtr)
1876 afs_int32 offset, s;
1883 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1887 found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
1889 *dSize -= (s - offset);
1894 FindVolTrailer2(char *buffera, afs_int32 sizea, afs_int32 *dataSizea,
1895 char *bufferb, afs_int32 sizeb, afs_int32 *dataSizeb,
1896 struct volumeHeader *volTrailerPtr)
1898 afs_int32 offset, s;
1899 afs_int32 headB, tailB;
1909 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1911 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
1914 headB = (s - sizeb); /*(s > sizeb) */
1915 if (headB > sizea) {
1922 memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
1924 memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
1926 memcpy(tapeVolumeHT + headB, bufferb, tailB);
1927 if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
1929 if (offset > headB) {
1930 /* *dataSizea remains unchanged */
1931 *dataSizeb = offset - headB;
1933 *dataSizea -= (headB - offset); /*(headB >= offset) */
1943 ExpirationDate(afs_int32 dumpid)
1946 Date expiration = 0;
1947 struct budb_dumpEntry dumpEntry;
1948 struct budb_tapeEntry tapeEntry;
1949 struct budb_volumeEntry volEntry;
1953 * Get the expiration date from DB if its there. The expiration of
1954 * any tape will be the most future expiration of any dump in the
1955 * set. Can't use bcdb_FindTape because dumpid here pertains to the
1958 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
1960 expiration = tapeEntry.expires;
1962 return (expiration);
1965 /* Returns true or false depending on whether the tape is expired or not */
1968 tapeExpired(struct butm_tapeLabel *tapeLabelPtr)
1972 struct timezone tzp;
1974 expiration = ExpirationDate(tapeLabelPtr->dumpid);
1976 expiration = tapeLabelPtr->expirationDate;
1978 gettimeofday(&tp, &tzp);
1979 return ((expiration < tp.tv_sec) ? 1 : 0);
1983 * given the label on the tape, delete any old information from the
1986 * Deletes all entries that match the volset.dumpnode
1987 * and the dump path.
1991 updateTapeLabel(struct labelTapeIf *labelIfPtr,
1992 struct butm_tapeInfo *tapeInfoPtr,
1993 struct butm_tapeLabel *newLabelPtr)
1995 struct butm_tapeLabel oldLabel;
1996 afs_int32 i, code = 0;
1998 int tapeIsLabeled = 0;
1999 int interactiveFlag;
2002 interactiveFlag = autoQuery;
2003 taskId = labelIfPtr->taskId;
2006 if (interactiveFlag) {
2008 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2009 labelIfPtr->taskId, tapecount);
2013 interactiveFlag = 1;
2016 /* mount the tape */
2017 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2019 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2023 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2027 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2028 && (strcmp(oldLabel.pName, "") != 0)) {
2029 /* We are setting the AFS name, yet tape
2030 * has a permanent name (not allowed).
2032 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2037 if (!tapeExpired(&oldLabel)) {
2038 if (!queryoperator) {
2039 TLog(taskId, "This tape has not expired\n");
2042 if (Ask("This tape has not expired - proceed") == 0)
2046 /* Keep the permanent name */
2047 if (strcmp(newLabelPtr->pName, "") == 0) {
2048 strcpy(newLabelPtr->pName, oldLabel.pName);
2049 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2050 strcpy(newLabelPtr->pName, "");
2054 /* extract useful information from the old label */
2055 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2056 newLabelPtr->dumpid = 0;
2057 newLabelPtr->useCount = oldLabel.useCount + 1;
2060 /* now write the new label */
2061 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2063 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2064 "Can't label tape\n");
2071 unmountTape(taskId, tapeInfoPtr);
2074 /* delete obsolete information from the database */
2075 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2076 /* delete based on dump id */
2077 if (oldLabel.dumpid) {
2078 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2079 if (i && (i != BUDB_NOENT))
2080 ErrorLog(0, taskId, i, 0,
2081 "Warning: Can't delete old dump %u from database\n",
2087 unmountTape(taskId, tapeInfoPtr);
2092 * LWP created by the server stub. Labels the tape with name and size
2093 * specified by <label>
2097 Labeller(void *param)
2099 struct labelTapeIf *labelIfPtr = (struct labelTapeIf *)param;
2101 struct tc_tapeLabel *label = &labelIfPtr->label;
2103 struct butm_tapeLabel newTapeLabel;
2104 struct butm_tapeInfo tapeInfo;
2108 taskId = labelIfPtr->taskId;
2109 setStatus(taskId, DRIVE_WAIT);
2110 EnterDeviceQueue(deviceLatch);
2111 clearStatus(taskId, DRIVE_WAIT);
2114 TLog(taskId, "Labeltape\n");
2116 memset(&tapeInfo, 0, sizeof(tapeInfo));
2117 tapeInfo.structVersion = BUTM_MAJORVERSION;
2118 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2120 ErrorLog(0, taskId, code, tapeInfo.error,
2121 "Can't initialize the tape module\n");
2125 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2127 newTapeLabel.size = label->size;
2129 newTapeLabel.size = globalTapeConfig.capacity;
2131 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2136 if (code == TC_ABORTEDBYREQUEST) {
2137 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2138 clearStatus(taskId, ABORT_REQUEST);
2139 setStatus(taskId, ABORT_DONE);
2141 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2142 setStatus(taskId, TASK_ERROR);
2144 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2145 TNAME(&newTapeLabel), newTapeLabel.size);
2147 setStatus(labelIfPtr->taskId, TASK_DONE);
2150 LeaveDeviceQueue(deviceLatch);
2151 return (void *)(intptr_t)(code);
2155 * print out the tape label.
2159 PrintTapeLabel(struct butm_tapeLabel *labelptr)
2161 char tapeName[BU_MAXTAPELEN + 32];
2164 printf("Tape label\n");
2165 printf("----------\n");
2166 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2167 printf("permanent tape name = %s\n", tapeName);
2168 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2169 printf("AFS tape name = %s\n", tapeName);
2170 t = labelptr->creationTime;
2171 printf("creationTime = %s", ctime(&t));
2172 if (labelptr->expirationDate) {
2173 t = labelptr->expirationDate;
2174 printf("expirationDate = %s", cTIME(&t));
2176 printf("cell = %s\n", labelptr->cell);
2177 printf("size = %u Kbytes\n", labelptr->size);
2178 printf("dump path = %s\n", labelptr->dumpPath);
2180 if (labelptr->structVersion >= TAPE_VERSION_3) {
2181 printf("dump id = %u\n", labelptr->dumpid);
2182 printf("useCount = %d\n", labelptr->useCount);
2184 printf("-- End of tape label --\n\n");
2188 * Read the label from a tape.
2189 * Currently prints out a "detailed" summary of the label but passes
2190 * back only selected fields.
2194 ReadLabel(struct tc_tapeLabel *label)
2196 struct butm_tapeLabel newTapeLabel;
2197 struct butm_tapeInfo tapeInfo;
2201 int interactiveFlag;
2204 EnterDeviceQueue(deviceLatch);
2205 taskId = allocTaskId(); /* reqd for lower level rtns */
2208 TLog(taskId, "Readlabel\n");
2210 memset(&tapeInfo, 0, sizeof(tapeInfo));
2211 tapeInfo.structVersion = BUTM_MAJORVERSION;
2212 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2214 ErrorLog(0, taskId, code, tapeInfo.error,
2215 "Can't initialize the tape module\n");
2218 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2220 interactiveFlag = autoQuery;
2223 if (interactiveFlag) {
2224 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2228 interactiveFlag = 1;
2231 code = butm_Mount(&tapeInfo, "");
2233 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2239 unmountTape(taskId, &tapeInfo);
2242 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2244 if (code == BUTM_NOLABEL) {
2245 printf("Tape is unlabelled\n");
2248 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2252 /* copy the fields to be passed to the caller */
2253 label->size = newTapeLabel.size;
2254 label->tapeId = newTapeLabel.dumpid;
2255 strcpy(label->afsname, newTapeLabel.AFSName);
2256 strcpy(label->pname, newTapeLabel.pName);
2259 expir = ExpirationDate(newTapeLabel.dumpid);
2261 newTapeLabel.expirationDate = expir;
2263 PrintTapeLabel(&newTapeLabel);
2266 unmountTape(taskId, &tapeInfo);
2268 if (code == TC_ABORTEDBYREQUEST)
2269 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2270 else if (code && (code != BUTM_NOLABEL))
2271 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2273 TLog(taskId, "ReadLabel: Finished\n");
2275 LeaveDeviceQueue(deviceLatch);
2279 /* Function to read volume header and trailer structure from tape, taking
2280 into consideration, different word alignment rules.
2283 readVolumeHeader(char *buffer, /* in - buffer to read header from */
2284 afs_int32 bufloc, /* in - header's location in buffer */
2285 struct volumeHeader *header) /* out -header structure */
2287 struct volumeHeader vhptr, *tempvhptr;
2288 afs_int32 firstSplice = (afs_int32) ((char*)& vhptr.pad - (char*) & vhptr);
2289 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2290 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2292 /* Four cases are to be handled
2294 * Volume Header (byte alignment)
2295 * -----------------------
2302 * -----------------------
2304 * Case 2 and Case 3 are identical cases and handled the same way.
2305 * Case 1 and Case 4 are separate cases. In one case the pad needs
2306 * to be removed and in the other, it needs to be spliced in. The
2307 * four cases are handled as follows
2309 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2310 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2311 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2312 /* Handle Cases 2 & 3 */
2313 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2314 HEADER_CHECKS(vhptr, header);
2317 memset(&vhptr, 0, sizeof(struct volumeHeader));
2318 memcpy(&vhptr, buffer + bufloc, firstSplice);
2319 memset(&vhptr.pad, 0, padLen);
2320 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2321 HEADER_CHECKS(vhptr, header);
2324 memset(&vhptr, 0, sizeof(struct volumeHeader));
2325 memcpy(&vhptr, buffer + bufloc, firstSplice);
2326 /* probably GCC bug 37060; however, no guarantee on length of buffer */
2327 tempvhptr = (struct volumeHeader *)(buffer + firstSplice);
2328 memcpy(tempvhptr, buffer + bufloc + firstSplice + padLen,
2330 HEADER_CHECKS(vhptr, header);
2333 return (TC_BADVOLHEADER);