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>
16 #include <sys/types.h>
23 #include <netinet/in.h>
30 #include <afs/procmgmt.h>
36 #include <afs/tcdata.h>
37 #include <afs/bubasics.h> /* PA */
38 #include <afs/budb_client.h>
39 #include <afs/bucoord_prototypes.h>
40 #include <afs/butm_prototypes.h>
41 #include <afs/volser.h>
42 #include <afs/volser_prototypes.h>
43 #include <afs/com_err.h>
44 #include "error_macros.h"
45 #include <afs/afsutil.h>
47 #include "butc_xbsa.h"
48 #include "butc_internal.h"
50 /* GLOBAL CONFIGURATION PARAMETERS */
51 extern int queryoperator;
52 extern int tapemounted;
53 extern char *opencallout;
54 extern char *closecallout;
56 extern char *extractDumpName(char *);
57 extern int BufferSize; /* Size in B stored for header info */
58 FILE *restoretofilefd;
60 extern char *restoretofile;
61 extern int forcemultiple;
64 /* XBSA Global Parameters */
67 struct butx_transactionInfo butxInfo;
70 static struct TapeBlock { /* A 16KB tapeblock */
71 char mark[BUTM_HDRSIZE]; /* Header info */
72 char data[BUTM_BLKSIZE]; /* data */
75 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
76 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
79 * Need to re-write to:
80 * 1) non-interactive tape handling (optional)
81 * 2) compute tape and volume sizes for the database
82 * 3) compute and use tape id's for tape tracking (put on tape label)
83 * 4) status management
86 /* All the relevant info shared between Restorer and restoreVolume */
87 struct restoreParams {
88 struct dumpNode *nodePtr;
90 char mntTapeName[BU_MAXTAPELEN];
92 struct butm_tapeInfo *tapeInfoPtr;
95 /* Abort checks are done after each BIGCHUNK of data transfer */
96 #define BIGCHUNK 102400
98 #define HEADER_CHECKS(vhptr, header) \
100 afs_int32 magic, versionflags; \
102 versionflags = ntohl(vhptr.versionflags); \
103 if ( versionflags == TAPE_VERSION_0 || \
104 versionflags == TAPE_VERSION_1 || \
105 versionflags == TAPE_VERSION_2 || \
106 versionflags == TAPE_VERSION_3 || \
107 versionflags == TAPE_VERSION_4 ) { \
109 magic = ntohl(vhptr.magic); /* another sanity check */ \
110 if (magic == TC_VOLBEGINMAGIC || \
111 magic == TC_VOLENDMAGIC || \
112 magic == TC_VOLCONTD ) { \
114 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
117 } /* versionflags */ \
121 extern FILE *ErrorlogIO;
122 extern FILE *centralLogIO;
123 extern FILE *lastLogIO;
124 extern afs_int32 lastPass; /* Set true during last pass of dump */
125 extern int debugLevel;
126 extern int autoQuery;
127 extern struct tapeConfig globalTapeConfig;
128 extern struct deviceSyncNode *deviceLatch;
129 extern char globalCellName[];
133 /* forward declaration */
134 afs_int32 readVolumeHeader(char *, afs_int32, struct volumeHeader *);
135 int FindVolTrailer(char *, afs_int32, afs_int32 *, struct volumeHeader *);
136 int FindVolTrailer2(char *, afs_int32, afs_int32 *, char *, afs_int32,
137 afs_int32 *, struct volumeHeader *);
138 int SkipVolume(struct tc_restoreDesc *, afs_int32, afs_int32, afs_int32,
143 /* The on-disk volume header or trailer can differ in size from platform to platform */
144 static struct TapeBlock tapeBlock;
145 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
148 PrintLogStr(FILE *log, afs_int32 error1, afs_int32 error2, char *str)
152 fprintf(log, "%s", str);
157 err1 = "Volume needs to be salvaged";
160 err1 = "Bad vnode number quoted";
163 err1 = "Volume not attached, does not exist, or not on line";
166 err1 = "Volume already exists";
169 err1 = "Volume is not in service";
172 err1 = "Volume is off line";
175 err1 = "Volume is already on line";
178 err1 = "Partition is full";
181 err1 = "Volume max quota exceeded";
184 err1 = "Volume temporarily unavailable";
187 err1 = "Volume has moved to another server";
190 err1 = (char *)afs_error_message(error1);
191 err2 = (char *)afs_error_table_name(error1);
195 fprintf(log, " Possible communication failure");
197 fprintf(log, " %s: %s", err2, err1);
199 fprintf(log, ": %s", afs_error_message(error2));
206 TapeLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
210 char tbuffer[32], *timestr;
213 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
216 fprintf(logIO, "%s: ", timestr);
218 fprintf(logIO, "Task %u: ", task);
219 PrintLogStr(logIO, error1, error2, str);
221 if (lastPass && lastLogIO) {
222 fprintf(lastLogIO, "%s: ", timestr);
224 fprintf(lastLogIO, "Task %u: ", task);
225 PrintLogStr(lastLogIO, error1, error2, str);
228 /* Now print to the screen if debug level requires */
229 if (debug <= debugLevel)
230 PrintLogStr(stdout, error1, error2, str);
234 TapeLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
241 vsnprintf(tmp, sizeof(tmp), fmt, ap);
244 TapeLogStr(debug, task, error1, error2, tmp);
248 TLog(afs_int32 task, char *fmt, ...)
254 vsnprintf(tmp, sizeof(tmp), fmt, ap);
257 /* Sends message to TapeLog and stdout */
258 TapeLogStr(0, task, 0, 0, tmp);
262 ErrorLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
266 char tbuffer[32], *timestr;
269 timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
271 fprintf(ErrorlogIO, "%s: ", timestr);
273 /* Print the time and task number */
275 fprintf(ErrorlogIO, "Task %u: ", task);
277 PrintLogStr(ErrorlogIO, error1, error2, errStr);
278 TapeLogStr(debug, task, error1, error2, errStr);
282 ErrorLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
289 vsnprintf(tmp, sizeof(tmp), fmt, ap);
292 ErrorLogStr(debug, task, error1, error2, tmp);
297 ELog(afs_int32 task, char *fmt, ...)
303 vsnprintf(tmp, sizeof(tmp), fmt, ap);
306 /* Sends message to ErrorLog, TapeLog and stdout */
307 ErrorLog(0, task, 0, 0, "%s", tmp);
310 /* first proc called by anybody who intends to use the device */
312 EnterDeviceQueue(struct deviceSyncNode *devLatch)
314 ObtainWriteLock(&(devLatch->lock));
315 devLatch->flags = TC_DEVICEINUSE;
318 /* last proc called by anybody finishing using the device */
320 LeaveDeviceQueue(struct deviceSyncNode *devLatch)
323 ReleaseWriteLock(&(devLatch->lock));
326 #define BELLTIME 60 /* 60 seconds before a bell rings */
327 #define BELLCHAR 7 /* ascii for bell */
333 * only external clients are in recoverDb.c. Was static. PA
343 w = LWP_WaitForKeystroke(0);
349 #endif /* AFS_NT40_ENV */
357 callOutRoutine(afs_int32 taskId, char *tapePath, int flag, char *name,
358 afs_uint32 dbDumpId, int tapecount)
374 callOut = opencallout;
377 strcpy(Sopcode, "restore");
380 strcpy(Sopcode, "appenddump");
383 strcpy(Sopcode, "dump");
386 strcpy(Sopcode, "labeltape");
388 case READLABELOPCODE:
389 strcpy(Sopcode, "readlabel");
392 strcpy(Sopcode, "scantape");
394 case RESTOREDBOPCODE:
395 strcpy(Sopcode, "restoredb");
398 strcpy(Sopcode, "savedb");
401 strcpy(Sopcode, "unmount");
402 callOut = closecallout;
405 strcpy(Sopcode, "unknown");
409 if (!callOut) /* no script to call */
412 strcpy(ScallOut, callOut);
413 CO_argv[0] = ScallOut;
415 strcpy(StapePath, tapePath);
416 CO_argv[1] = StapePath;
418 CO_argv[2] = Sopcode;
420 if (flag == CLOSEOPCODE) {
423 sprintf(Scount, "%d", tapecount);
426 /* The tape label name - special case labeltape */
427 if (!name || (strcmp(name, "") == 0)) /* no label */
428 strcpy(Stape, "none");
429 else { /* labeltape */
431 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
432 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
441 strcpy(Sdumpid, "none");
443 sprintf(Sdumpid, "%u", dbDumpId);
444 CO_argv[5] = Sdumpid;
451 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
453 ErrorLog(0, taskId, errno, 0,
454 "Call to %s outside routine %s failed\n", Sopcode, callOut);
463 * Unmounts a tape and prints a warning if it can't unmount it.
464 * Regardless of error, the closecallout routine will be called
465 * (unless a tape is not mounted in the first place).
468 unmountTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr)
471 int cpid, status, rcpid;
473 code = butm_Dismount(tapeInfoPtr);
474 if (code && (code != BUTM_NOMOUNT))
475 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
476 "Warning: Can't close tape\n");
478 if (tapemounted && closecallout) {
479 setStatus(taskId, CALL_WAIT);
482 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
484 while (cpid) { /* Wait until return */
486 rcpid = waitpid(cpid, &status, WNOHANG);
491 if (rcpid == -1 && errno != EINTR) {
493 afs_com_err(whoami, errno,
494 "Error waiting for callout script to terminate.");
497 #ifdef AFS_PTHREAD_ENV
503 if (checkAbortByTaskId(taskId)) {
504 TLog(taskId, "Callout routine has been aborted\n");
505 if (kill(cpid, SIGKILL)) /* Cancel callout */
506 ErrorLog(0, taskId, errno, 0,
507 "Kill of callout process %d failed\n", cpid);
512 clearStatus(taskId, CALL_WAIT);
516 * print out prompt to operator
518 * PromptForTape only.
522 PrintPrompt(int flag, char *name, int dumpid)
524 char tapename[BU_MAXTAPELEN + 32];
527 TAPENAME(tapename, name, dumpid);
529 printf("******* OPERATOR ATTENTION *******\n");
530 printf("Device : %s \n", globalTapeConfig.device);
533 case READOPCODE: /* mount for restore */
534 printf("Please put in tape %s for reading", tapename);
537 case APPENDOPCODE: /* mount for dump (appends) */
539 dn = extractDumpName(name);
542 printf("Please put in last tape of dump set for appending dump");
545 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
549 case WRITEOPCODE: /* mount for dump */
550 if (strcmp(name, "") == 0)
551 printf("Please put in tape for writing");
553 /* The name is what we are going to label the tape as */
555 printf("Please put in tape %s for writing", tapename);
558 case LABELOPCODE: /* mount for labeltape */
559 printf("Please put in tape to be labelled as %s", tapename);
562 case READLABELOPCODE: /* mount for readlabel */
563 printf("Please put in tape whose label is to be read");
566 case SCANOPCODE: /* mount for scantape */
567 if (strcmp(name, "") == 0)
568 printf("Please put in tape to be scanned");
570 printf("Please put in tape %s for scanning", tapename);
573 case RESTOREDBOPCODE: /* Mount for restoredb */
574 printf("Please insert a tape %s for the database restore", tapename);
577 case SAVEDBOPCODE: /* Mount for savedb */
578 printf("Please insert a writeable tape %s for the database dump",
585 printf(" and hit return when done\n");
589 * Prompt the operator to change the tape.
590 * Use to be a void routine but now returns an error. Some calls
591 * don't use the error code.
593 * only external clients are in recoverDb.c. Was static PA
596 PromptForTape(int flag, char *name, afs_uint32 dbDumpId, afs_uint32 taskId,
604 int cpid, status, rcpid;
606 if (checkAbortByTaskId(taskId))
607 ERROR_EXIT(TC_ABORTEDBYREQUEST);
610 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
612 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
614 CallOut = (opencallout ? 1 : 0);
616 setStatus(taskId, CALL_WAIT);
619 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
620 dbDumpId, tapecount);
622 CallOut = 0; /* prompt at screen */
624 while (CallOut) { /* Check if callout routine finished */
626 rcpid = waitpid(cpid, &status, WNOHANG);
630 else if (WIFEXITED(status))
631 wcode = WEXITSTATUS(status);
636 break; /* All done */
637 } else if (wcode == 1) {
638 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
639 } else if ((flag == READOPCODE) && (wcode == 3)) {
640 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
643 "Callout routine has exited with code %d: will prompt\n",
645 CallOut = 0; /* Switch to keyboard input */
649 /* if waitpid experienced an error, we prompt */
650 if (rcpid == -1 && errno != EINTR) {
651 afs_com_err(whoami, errno,
652 "Error waiting for callout script to terminate.");
654 "Can't get exit status from callout script. will prompt\n");
658 #ifdef AFS_PTHREAD_ENV
664 if (checkAbortByTaskId(taskId)) {
666 ("This tape operation has been aborted by the coordinator.\n");
668 if (kill(cpid, SIGKILL)) /* Cancel callout */
669 ErrorLog(0, taskId, errno, 0,
670 "Kill of callout process %d failed\n", cpid);
672 ERROR_EXIT(TC_ABORTEDBYREQUEST);
678 clearStatus(taskId, CALL_WAIT);
679 setStatus(taskId, OPR_WAIT);
681 PrintPrompt(flag, name, dbDumpId);
683 /* Loop until we get ok to go ahead (or abort) */
685 if (time(0) > start + BELLTIME) {
691 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
692 if (wcode == 1) { /* keyboard input is available */
694 if ((inchr == 'a') || (inchr == 'A')) {
695 printf("This tape operation has been aborted.\n");
696 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
697 } else if ((flag == READOPCODE)
698 && ((inchr == 's') || (inchr == 'S'))) {
699 printf("This tape will be skipped.\n");
700 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
702 break; /* continue */
705 if (checkAbortByTaskId(taskId)) {
707 ("This tape operation has been aborted by the coordinator.\n");
708 ERROR_EXIT(TC_ABORTEDBYREQUEST);
714 printf("Thanks, now proceeding with tape ");
716 case RESTOREDBOPCODE:
722 printf("append writing");
734 case READLABELOPCODE:
735 printf("label reading");
747 printf(" operation.\n");
749 printf("**********************************\n");
751 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
755 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
761 * convert the fields in the tapeVolHeader into host byte order,
762 * placing the converted copy of the structure into the hostVolHeader
764 * tapeVolHeader - points to volume header read from tape
765 * hostVolHeader - pointer to struct for result
767 * hostVolHeader - information in host byte order
771 VolHeaderToHost(struct volumeHeader *hostVolHeader,
772 struct volumeHeader *tapeVolHeader)
774 switch (ntohl(tapeVolHeader->versionflags)) {
776 /* sizes in bytes and fields in host order */
777 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
782 case TAPE_VERSION_3: /* for present */
784 /* sizes in K and fields in network order */
785 /* do the conversion field by field */
787 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
788 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
789 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
790 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
791 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
792 hostVolHeader->server = ntohl(tapeVolHeader->server);
793 hostVolHeader->part = ntohl(tapeVolHeader->part);
794 hostVolHeader->from = ntohl(tapeVolHeader->from);
795 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
796 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
797 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
798 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
799 hostVolHeader->level = ntohl(tapeVolHeader->level);
800 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
801 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
802 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
803 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
807 return (TC_BADVOLHEADER);
813 ReadVolHeader(afs_int32 taskId,
814 struct butm_tapeInfo *tapeInfoPtr,
815 struct volumeHeader *volHeaderPtr)
819 struct volumeHeader volHead;
821 /* Read the volume header */
823 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
826 ErrorLog(0, taskId, code, tapeInfoPtr->error,
827 "Can't read volume header on tape\n");
831 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
833 ErrorLog(0, taskId, code, 0,
834 "Can't find volume header on tape block\n");
838 code = VolHeaderToHost(volHeaderPtr, &volHead);
840 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
849 GetVolumeHead(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
850 afs_int32 position, char *volName, afs_int32 volId)
853 struct volumeHeader tapeVolHeader;
855 /* Position directly to the volume and read the header */
857 code = butm_Seek(tapeInfoPtr, position);
859 ErrorLog(0, taskId, code, tapeInfoPtr->error,
860 "Can't seek to position %u on tape\n", position);
864 code = butm_ReadFileBegin(tapeInfoPtr);
866 ErrorLog(0, taskId, code, tapeInfoPtr->error,
867 "Can't read FileBegin on tape\n");
871 /* Read the volume header */
872 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
876 /* Check if volume header matches */
877 if (strcmp(tapeVolHeader.volumeName, volName))
878 ERROR_EXIT(TC_BADVOLHEADER);
879 if (volId && (tapeVolHeader.volumeID != volId))
880 ERROR_EXIT(TC_BADVOLHEADER);
881 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
882 ERROR_EXIT(TC_BADVOLHEADER);
885 /* Do a sequential search for the volume */
888 code = butm_ReadFileBegin(tapeInfoPtr);
890 ErrorLog(0, taskId, code, tapeInfoPtr->error,
891 "Can't read FileBegin on tape\n");
895 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
897 ERROR_EXIT(TC_VOLUMENOTONTAPE);
899 /* Test if we found the volume */
900 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
901 && (!volId || (volId == tapeVolHeader.volumeID)))
904 /* skip to the next HW EOF marker */
905 code = SeekFile(tapeInfoPtr, 1);
907 ErrorLog(0, taskId, code, tapeInfoPtr->error,
908 "Can't seek to next EOF on tape\n");
919 GetRestoreTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
920 char *tname, afs_int32 tapeID, int prompt)
922 struct butm_tapeLabel tapeLabel;
923 afs_int32 code = 0, rc;
925 struct budb_dumpEntry dumpEntry;
927 /* Make sure that the dump/tape is not a XBSA dump */
928 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
929 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
930 ErrorLog(0, taskId, 0, 0,
931 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
932 ERROR_EXIT(TC_SKIPTAPE);
938 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
945 code = butm_Mount(tapeInfoPtr, tname);
947 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
951 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
953 ErrorLog(0, taskId, code, tapeInfoPtr->error,
954 "Can't read tape label\n");
958 /* Now check the label to see if the tapename matches or tapeids match */
959 if (strcmp(TNAME(&tapeLabel), tname)
960 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
961 && (tapeLabel.dumpid != tapeID))) {
962 char expectedName[BU_MAXTAPELEN + 32],
963 gotName[BU_MAXTAPELEN + 32];
965 TAPENAME(expectedName, tname, tapeID);
966 LABELNAME(gotName, &tapeLabel);
968 TapeLog(0, taskId, 0, 0,
969 "Tape label expected %s, label seen %s\n", expectedName,
977 unmountTape(taskId, tapeInfoPtr);
985 xbsaRestoreVolumeData(struct rx_call *call, void *rock)
989 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
990 afs_int32 curChunk, rc;
991 afs_uint32 totalWritten;
992 afs_int32 headBytes, tailBytes, w;
994 struct volumeHeader volTrailer;
995 afs_int32 vtsize = 0;
997 struct dumpNode *nodePtr;
998 struct tc_restoreDesc *Restore;
999 afs_int32 bytesRead, tbuffersize, endData = 0;
1000 char *buffer = (char *)bufferBlock, tbuffer[256];
1002 nodePtr = rparamsPtr->nodePtr;
1003 Restore = nodePtr->restores;
1004 taskId = nodePtr->taskID;
1006 /* Read the volume fragment one block at a time until
1007 * find a volume trailer
1009 curChunk = BIGCHUNK + 1;
1014 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1016 if (restoretofile && (bytesRead > 0)) {
1017 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1019 if (rc != XBSA_SUCCESS) {
1020 ErrorLog(0, taskId, rc, 0,
1021 "Unable to read volume data from the server\n");
1025 /* Periodically update status structure and check if should abort */
1026 curChunk += bytesRead;
1027 if (curChunk > BIGCHUNK) {
1030 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1033 if (checkAbortByTaskId(taskId))
1034 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1037 if (!endData && (bytesRead > 0)) {
1038 /* Fill tbuffer up with data from end of buffer and write
1039 * the remainder of buffer out.
1041 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1042 /* Write out contents of tbuffer */
1044 w = rx_Write(call, tbuffer, tbuffersize);
1045 if (w != tbuffersize) {
1046 ErrorLog(0, taskId, -1, 0,
1047 "Error in RX write: Wrote %d bytes\n", w);
1052 /* fill tbuffer with end of buffer */
1053 bytesRead -= sizeof(tbuffer);
1054 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1055 tbuffersize = sizeof(tbuffer);
1056 /* Write out whatever is left over in buffer */
1058 w = rx_Write(call, buffer, bytesRead);
1059 if (w != bytesRead) {
1060 ErrorLog(0, taskId, -1, 0,
1061 "Error in RX data write: Wrote %d bytes\n",
1068 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1069 /* Copy all of buffer into tbuffer (it will fit) */
1070 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1071 tbuffersize += bytesRead;
1074 /* We need to write some of tbuffer out and fill it with buffer */
1075 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1076 w = rx_Write(call, tbuffer, towrite);
1078 ErrorLog(0, taskId, -1, 0,
1079 "Error in RX write: Wrote %d bytes\n", w);
1085 /* Move the data in tbuffer up */
1086 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1088 /* Now copy buffer in */
1089 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1090 tbuffersize += bytesRead;
1096 /* Pull the volume trailer from the last two buffers */
1098 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1099 &tailBytes, &volTrailer);
1102 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1103 ERROR_EXIT(TC_MISSINGTRAILER);
1106 /* Now rx_write the data in the last two blocks */
1108 w = rx_Write(call, tbuffer, headBytes);
1109 if (w != headBytes) {
1110 ErrorLog(0, taskId, -1, 0,
1111 "Error in RX trail1 write: Wrote %d bytes\n", w);
1117 w = rx_Write(call, buffer, tailBytes);
1118 if (w != tailBytes) {
1119 ErrorLog(0, taskId, -1, 0,
1120 "Error in RX trail2 write: Wrote %d bytes\n", w);
1132 * sends the contents of volume dump to Rx Stream associated
1137 restoreVolumeData(struct rx_call *call, void *rock)
1139 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
1141 afs_uint32 totalWritten = 0;
1143 afs_int32 headBytes, tailBytes, w;
1145 afs_int32 nbytes; /* # bytes data in last tape block read */
1146 struct volumeHeader tapeVolTrailer;
1149 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1150 struct tc_restoreDesc *Restore;
1151 struct dumpNode *nodePtr;
1152 struct butm_tapeInfo *tapeInfoPtr;
1154 afs_int32 origVolID;
1156 nodePtr = rparamsPtr->nodePtr;
1157 taskId = nodePtr->taskID;
1158 Restore = nodePtr->restores;
1159 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1160 origVolName = Restore[rparamsPtr->frag].oldName;
1161 origVolID = Restore[rparamsPtr->frag].origVid;
1163 /* Read the volume one fragment at a time */
1164 while (rparamsPtr->frag < nodePtr->arraySize) {
1166 curChunk = BIGCHUNK + 1; /* Check if should abort */
1168 /* Read the volume fragment one block at a time until
1169 * find a volume trailer
1175 while (moretoread) {
1176 /* Fill the circular buffer with tape blocks
1177 * Search for volume trailer in the process.
1182 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1183 BUTM_BLKSIZE, &nbytes);
1185 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1186 "Can't read FileData on tape %s\n",
1187 rparamsPtr->mntTapeName);
1190 curChunk += BUTM_BLKSIZE;
1192 /* Periodically update status structure and check if should abort */
1193 if (curChunk > BIGCHUNK) {
1197 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1200 if (checkAbortByTaskId(taskId))
1201 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1204 /* step to next block in buffer */
1206 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1208 /* If this is the end of the volume, the exit the loop */
1209 if ((nbytes != BUTM_BLKSIZE)
1212 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1216 } while (moretoread && (buf != endRbuf));
1218 /* Write the buffer upto (but not including) the last read block
1219 * If volume is completely read, then leave the last two blocks.
1221 lastbuf = endWbuf = pbuf;
1222 if (!moretoread && (endWbuf != startWbuf))
1223 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1225 for (buf = startWbuf; buf != endWbuf;
1226 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1227 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1228 if (w != BUTM_BLKSIZE) {
1229 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1232 totalWritten += BUTM_BLKSIZE;
1235 /* Setup pointers to refill buffer */
1236 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1238 startWbuf = endWbuf;
1241 /* lastbuf is last block read and it has nbytes of data
1242 * startWbuf is the 2nd to last block read
1243 * Seach for the volume trailer in these two blocks.
1245 if (lastbuf == startWbuf)
1247 FindVolTrailer2(NULL, 0, &headBytes,
1248 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1252 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1253 &headBytes, bufferBlock[lastbuf].data, nbytes,
1254 &tailBytes, &tapeVolTrailer);
1256 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1257 "Missing volume trailer on tape %s\n",
1258 rparamsPtr->mntTapeName);
1259 ERROR_EXIT(TC_MISSINGTRAILER);
1262 /* Now rx_write the data in the last two blocks */
1264 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1265 if (w != headBytes) {
1266 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1269 totalWritten += headBytes;
1272 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1273 if (w != tailBytes) {
1274 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1277 totalWritten += tailBytes;
1280 /* Exit the loop if the volume is not continued on next tape */
1281 if (!tapeVolTrailer.contd)
1282 break; /* We've read the entire volume */
1284 /* Volume is continued on next tape.
1285 * Step to the next volume fragment and prompt for its tape.
1286 * When a volume has multiple frags, those frags are on different
1287 * tapes. So we know that we need to prompt for a tape.
1290 if (rparamsPtr->frag >= nodePtr->arraySize)
1293 unmountTape(taskId, tapeInfoPtr);
1294 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1295 rparamsPtr->tapeID =
1296 (Restore[rparamsPtr->frag].
1297 initialDumpId ? Restore[rparamsPtr->frag].
1298 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1300 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1301 rparamsPtr->tapeID, 1);
1305 /* Position to the frag and read the volume header */
1307 GetVolumeHead(taskId, tapeInfoPtr,
1308 Restore[rparamsPtr->frag].position, origVolName,
1311 ErrorLog(0, taskId, code, 0,
1312 "Can't find volume %s (%u) on tape %s\n", origVolName,
1313 origVolID, rparamsPtr->mntTapeName);
1314 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1323 * Find all the volumes on a specific tape and mark them to skip.
1326 SkipTape(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1327 char *tapename, afs_int32 tapeid, afs_int32 taskid)
1331 for (i = index; i < size; i++) {
1332 if (Restore[i].flags & RDFLAG_SKIP)
1335 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1337 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1338 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1345 * Find all the entries for a volume and mark them to skip.
1348 SkipVolume(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1349 afs_int32 volid, afs_int32 taskid)
1354 for (i = index; i < size; i++) {
1355 if (Restore[i].flags & RDFLAG_SKIP)
1357 if (Restore[i].origVid == volid) {
1358 Restore[i].flags |= RDFLAG_SKIP;
1360 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1361 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1362 Restore[i].oldName, volid);
1371 xbsaRestoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1372 struct restoreParams *rparamsPtr)
1377 afs_int32 newServer, newPart, newVolId;
1379 int restoreflags, havetrans = 0, startread = 0;
1380 afs_int32 bytesRead, endData = 0;
1382 struct budb_dumpEntry dumpEntry;
1383 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1384 struct volumeHeader volHeader, hostVolHeader;
1386 if (restoretofile) {
1387 restoretofilefd = fopen(restoretofile, "w+");
1390 dumpID = restoreInfo->dbDumpId;
1392 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1394 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1399 /* ADSM servers restore ADSM and BUTA dumps */
1400 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1401 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1403 "The dump requested by this restore operation for the "
1404 "volumeset is incompatible with this instance of butc\n");
1405 /* Skip the entire dump (one dump per tape) */
1406 ERROR_EXIT(TC_SKIPTAPE);
1409 /* make sure we are connected to the correct server. */
1410 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1411 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1413 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1414 && !forcemultiple) {
1416 "Dump %d is on server %s but butc is connected "
1417 "to server %s (attempting to restore)\n", dumpID,
1418 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1421 "Dump %d is on server %s but butc is connected "
1422 "to server %s (switching servers)\n", dumpID,
1423 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1425 rc = InitToServer(taskId, &butxInfo,
1426 (char *)dumpEntry.tapes.tapeServer);
1427 if (rc != XBSA_SUCCESS)
1428 ERROR_EXIT(TC_SKIPTAPE);
1432 /* Start a transaction and query the server for the correct fileset dump */
1433 rc = xbsa_BeginTrans(&butxInfo);
1434 if (rc != XBSA_SUCCESS) {
1435 ELog(taskId, "Unable to create a new transaction\n");
1436 ERROR_EXIT(TC_SKIPTAPE);
1440 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1441 sprintf(dumpIdStr, "/%d", dumpID);
1442 strcpy(volumeNameStr, "/");
1443 strcat(volumeNameStr, restoreInfo->oldName);
1444 } else { /* new butc names */
1445 extern char *butcdumpIdStr;
1446 strcpy(dumpIdStr, butcdumpIdStr);
1447 sprintf(volumeNameStr, "/%d", dumpID);
1448 strcat(volumeNameStr, "/");
1449 strcat(volumeNameStr, restoreInfo->oldName);
1452 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1453 if (rc != XBSA_SUCCESS) {
1455 "Unable to locate object (%s) of dump (%s) on the server\n",
1456 volumeNameStr, dumpIdStr);
1460 rc = xbsa_EndTrans(&butxInfo);
1462 if (rc != XBSA_SUCCESS) {
1463 ELog(taskId, "Unable to terminate the current transaction\n");
1467 if (checkAbortByTaskId(taskId))
1468 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1470 /* Now start a transaction on the volume to restore and read the
1471 * volumeheader. We do this before starting a transaction on
1472 * volserver to restore the volume because the XBSA server may take
1473 * a while to mount and seek to the volume causing the volserver to
1476 rc = xbsa_BeginTrans(&butxInfo);
1477 if (rc != XBSA_SUCCESS) {
1478 ELog(taskId, "Unable to create a new transaction\n");
1479 ERROR_EXIT(TC_SKIPTAPE);
1483 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1484 sizeof(volHeader), &bytesRead, &endData);
1485 if (restoretofile && (bytesRead > 0)) {
1486 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1488 if (rc != XBSA_SUCCESS) {
1490 "Unable to begin reading of the volume from the server\n");
1495 if ((bytesRead != sizeof(volHeader)) || endData) {
1497 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1498 bytesRead, sizeof(volHeader));
1499 ERROR_EXIT(TC_BADVOLHEADER);
1502 /* convert and check the volume header */
1503 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1505 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1509 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1510 || (restoreInfo->origVid
1511 && (hostVolHeader.volumeID != restoreInfo->origVid))
1512 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1513 ERROR_EXIT(TC_BADVOLHEADER);
1515 /* Set up prior restoring volume data */
1516 newVolName = restoreInfo->newName;
1517 newVolId = restoreInfo->vid;
1518 newServer = restoreInfo->hostAddr;
1519 newPart = restoreInfo->partition;
1521 if ((restoreInfo->dumpLevel == 0)
1522 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1523 restoreflags |= RV_FULLRST;
1524 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1525 restoreflags |= RV_OFFLINE;
1527 if (checkAbortByTaskId(taskId))
1528 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1530 /* Start the restore of the volume data. This is the code we want to return */
1532 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1533 restoreflags, xbsaRestoreVolumeData,
1534 (char *)rparamsPtr);
1537 rc = xbsa_ReadObjectEnd(&butxInfo);
1538 if (rc != XBSA_SUCCESS) {
1540 "Unable to terminate reading of the volume from the server\n");
1546 rc = xbsa_EndTrans(&butxInfo);
1547 if (rc != XBSA_SUCCESS) {
1548 ELog(taskId, "Unable to terminate the current transaction\n");
1554 if (restoretofile && restoretofilefd) {
1555 fclose(restoretofilefd);
1562 restoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1563 struct restoreParams *rparamsPtr)
1565 afs_int32 code = 0, rc;
1566 afs_int32 newServer, newPart, newVolId;
1570 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1572 /* Check if we need a tape and prompt for one if so */
1574 (restoreInfo->initialDumpId ? restoreInfo->
1575 initialDumpId : restoreInfo->dbDumpId);
1576 if ((rparamsPtr->frag == 0)
1577 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1578 || (tapeID != rparamsPtr->tapeID)) {
1579 /* Unmount the previous tape */
1580 unmountTape(taskId, tapeInfoPtr);
1582 /* Remember this new tape */
1583 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1584 rparamsPtr->tapeID = tapeID;
1586 /* Mount a new tape */
1587 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1589 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1594 /* Seek to the correct spot and read the header information */
1595 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1596 restoreInfo->oldName, restoreInfo->origVid);
1600 /* Set up prior restoring volume data */
1601 newVolName = restoreInfo->newName;
1602 newVolId = restoreInfo->vid;
1603 newServer = restoreInfo->hostAddr;
1604 newPart = restoreInfo->partition;
1606 if ((restoreInfo->dumpLevel == 0)
1607 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1608 restoreflags |= RV_FULLRST;
1609 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1610 restoreflags |= RV_OFFLINE;
1612 if (checkAbortByTaskId(taskId))
1613 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1615 /* Start the restore of the volume data. This is the code we
1619 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1620 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1622 /* Read the FileEnd marker for the volume and step to next FM */
1623 rc = butm_ReadFileEnd(tapeInfoPtr);
1625 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1626 "Can't read EOF on tape\n");
1634 * created as a LWP by the server stub, <newNode> is a pointer to all
1635 * the parameters Restorer needs
1638 Restorer(void *param) {
1639 struct dumpNode *newNode = (struct dumpNode *) param;
1641 afs_int32 code = 0, tcode;
1644 struct butm_tapeInfo tapeInfo;
1645 struct tc_restoreDesc *Restore;
1646 struct tc_restoreDesc *RestoreDesc;
1647 struct restoreParams rparams;
1648 afs_int32 allocbufferSize;
1649 time_t startTime, endTime;
1650 afs_int32 goodrestore = 0;
1652 taskId = newNode->taskID;
1653 setStatus(taskId, DRIVE_WAIT);
1654 EnterDeviceQueue(deviceLatch);
1655 clearStatus(taskId, DRIVE_WAIT);
1658 TLog(taskId, "Restore\n");
1660 memset(&tapeInfo, 0, sizeof(tapeInfo));
1662 tapeInfo.structVersion = BUTM_MAJORVERSION;
1663 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1665 ErrorLog(0, taskId, tcode, tapeInfo.error,
1666 "Can't initialize the tape module\n");
1671 if (checkAbortByTaskId(taskId))
1672 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1674 memset(&rparams, 0, sizeof(rparams));
1675 rparams.nodePtr = newNode;
1676 rparams.tapeInfoPtr = &tapeInfo;
1677 Restore = newNode->restores; /* Array of vol fragments to restore */
1679 /* Allocate memory in which to restore the volumes data into */
1681 allocbufferSize = dataSize = BufferSize;
1683 /* Must have at least two tape blocks */
1684 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1687 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1690 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1692 ERROR_EXIT(TC_NOMEMORY);
1693 memset(bufferBlock, 0, allocbufferSize);
1695 startTime = time(0);
1696 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1698 RestoreDesc = &Restore[rparams.frag];
1700 /* Skip the volume if it was requested to */
1701 if (RestoreDesc->flags & RDFLAG_SKIP) {
1702 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1703 /* If the volume was restored, should bring it online */
1708 newVolName = RestoreDesc->newName;
1710 /* Make sure the server to restore to is good */
1711 if (!RestoreDesc->hostAddr) {
1712 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1714 ERROR_EXIT(TC_INTERNALERROR);
1717 if (checkAbortByTaskId(taskId))
1718 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1720 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1722 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1726 /* restoreVolume function takes care of all the related fragments
1727 * spanning various tapes. On return the complete volume has been
1731 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1733 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1736 if (tcode == TC_ABORTEDBYREQUEST) {
1738 } else if (tcode == TC_SKIPTAPE) {
1741 (RestoreDesc->initialDumpId ? RestoreDesc->
1742 initialDumpId : RestoreDesc->dbDumpId);
1743 SkipTape(Restore, newNode->arraySize, rparams.frag,
1744 RestoreDesc->tapeName, tapeID, taskId);
1746 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1748 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1749 RestoreDesc->origVid, taskId);
1761 unmountTape(taskId, &tapeInfo);
1764 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1771 if (code == TC_ABORTEDBYREQUEST) {
1772 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1773 clearStatus(taskId, ABORT_REQUEST);
1774 setStatus(taskId, ABORT_DONE);
1776 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1777 setStatus(taskId, TASK_ERROR);
1779 TLog(taskId, "Restore: Finished\n");
1782 if (centralLogIO && startTime) {
1784 afs_int32 hrs, min, sec, tmp;
1786 struct tm tmstart, tmend;
1788 localtime_r(&startTime, &tmstart);
1789 localtime_r(&endTime, &tmend);
1790 timediff = (int)endTime - (int)startTime;
1791 hrs = timediff / 3600;
1792 tmp = timediff % 3600;
1797 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1798 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1799 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1800 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1801 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1802 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1803 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1804 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1806 fwrite(line, strlen(line), 1, centralLogIO);
1807 fflush(centralLogIO);
1810 setStatus(taskId, TASK_DONE);
1813 LeaveDeviceQueue(deviceLatch);
1814 return (void *)(intptr_t)(code);
1817 /* this is just scaffolding, creates new tape label with name <tapeName> */
1820 GetNewLabel(struct butm_tapeInfo *tapeInfoPtr, char *pName, char *AFSName,
1821 struct butm_tapeLabel *tapeLabel)
1824 struct timezone tzp;
1827 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1830 butm_GetSize(tapeInfoPtr, &size);
1832 size = globalTapeConfig.capacity;
1834 size = 0; /* no tape size */
1836 gettimeofday(&tp, &tzp);
1838 tapeLabel->structVersion = CUR_TAPE_VERSION;
1839 tapeLabel->creationTime = tp.tv_sec;
1840 tapeLabel->size = size;
1841 tapeLabel->expirationDate = 0; /* 1970 sometime */
1842 tapeLabel->dumpPath[0] = 0; /* no path name */
1843 tapeLabel->useCount = 0;
1844 strcpy(tapeLabel->AFSName, AFSName);
1845 strcpy(tapeLabel->pName, pName);
1846 strcpy(tapeLabel->cell, globalCellName);
1847 strcpy(tapeLabel->comment, "AFS Backup Software");
1848 strcpy(tapeLabel->creator.name, "AFS 3.6");
1849 strcpy(tapeLabel->creator.instance, "");
1850 strcpy(tapeLabel->creator.cell, globalCellName);
1853 /* extracts trailer out of buffer, nbytes is set to total data in
1854 * buffer - trailer size */
1856 ExtractTrailer(char *buffer, afs_int32 size, afs_int32 *nbytes,
1857 struct volumeHeader *volTrailerPtr)
1861 struct volumeHeader tempTrailer;
1865 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1867 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1869 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1875 return 1; /* saw the trailer */
1881 return 0; /* did not see the trailer */
1885 FindVolTrailer(char *buffer, afs_int32 size, afs_int32 *dSize,
1886 struct volumeHeader *volTrailerPtr)
1888 afs_int32 offset, s;
1895 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1899 found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
1901 *dSize -= (s - offset);
1906 FindVolTrailer2(char *buffera, afs_int32 sizea, afs_int32 *dataSizea,
1907 char *bufferb, afs_int32 sizeb, afs_int32 *dataSizeb,
1908 struct volumeHeader *volTrailerPtr)
1910 afs_int32 offset, s;
1911 afs_int32 headB, tailB;
1921 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1923 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
1926 headB = (s - sizeb); /*(s > sizeb) */
1927 if (headB > sizea) {
1934 memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
1936 memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
1938 memcpy(tapeVolumeHT + headB, bufferb, tailB);
1939 if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
1941 if (offset > headB) {
1942 /* *dataSizea remains unchanged */
1943 *dataSizeb = offset - headB;
1945 *dataSizea -= (headB - offset); /*(headB >= offset) */
1955 ExpirationDate(afs_int32 dumpid)
1958 Date expiration = 0;
1959 struct budb_dumpEntry dumpEntry;
1960 struct budb_tapeEntry tapeEntry;
1961 struct budb_volumeEntry volEntry;
1965 * Get the expiration date from DB if its there. The expiration of
1966 * any tape will be the most future expiration of any dump in the
1967 * set. Can't use bcdb_FindTape because dumpid here pertains to the
1970 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
1972 expiration = tapeEntry.expires;
1974 return (expiration);
1977 /* Returns true or false depending on whether the tape is expired or not */
1980 tapeExpired(struct butm_tapeLabel *tapeLabelPtr)
1984 struct timezone tzp;
1986 expiration = ExpirationDate(tapeLabelPtr->dumpid);
1988 expiration = tapeLabelPtr->expirationDate;
1990 gettimeofday(&tp, &tzp);
1991 return ((expiration < tp.tv_sec) ? 1 : 0);
1995 * given the label on the tape, delete any old information from the
1998 * Deletes all entries that match the volset.dumpnode
1999 * and the dump path.
2003 updateTapeLabel(struct labelTapeIf *labelIfPtr,
2004 struct butm_tapeInfo *tapeInfoPtr,
2005 struct butm_tapeLabel *newLabelPtr)
2007 struct butm_tapeLabel oldLabel;
2008 afs_int32 i, code = 0;
2010 int tapeIsLabeled = 0;
2011 int interactiveFlag;
2014 interactiveFlag = autoQuery;
2015 taskId = labelIfPtr->taskId;
2018 if (interactiveFlag) {
2020 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2021 labelIfPtr->taskId, tapecount);
2025 interactiveFlag = 1;
2028 /* mount the tape */
2029 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2031 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2035 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2039 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2040 && (strcmp(oldLabel.pName, "") != 0)) {
2041 /* We are setting the AFS name, yet tape
2042 * has a permanent name (not allowed).
2044 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2049 if (!tapeExpired(&oldLabel)) {
2050 if (!queryoperator) {
2051 TLog(taskId, "This tape has not expired\n");
2054 if (Ask("This tape has not expired - proceed") == 0)
2058 /* Keep the permanent name */
2059 if (strcmp(newLabelPtr->pName, "") == 0) {
2060 strcpy(newLabelPtr->pName, oldLabel.pName);
2061 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2062 strcpy(newLabelPtr->pName, "");
2066 /* extract useful information from the old label */
2067 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2068 newLabelPtr->dumpid = 0;
2069 newLabelPtr->useCount = oldLabel.useCount + 1;
2072 /* now write the new label */
2073 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2075 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2076 "Can't label tape\n");
2083 unmountTape(taskId, tapeInfoPtr);
2086 /* delete obsolete information from the database */
2087 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2088 /* delete based on dump id */
2089 if (oldLabel.dumpid) {
2090 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2091 if (i && (i != BUDB_NOENT))
2092 ErrorLog(0, taskId, i, 0,
2093 "Warning: Can't delete old dump %u from database\n",
2099 unmountTape(taskId, tapeInfoPtr);
2104 * LWP created by the server stub. Labels the tape with name and size
2105 * specified by <label>
2109 Labeller(void *param)
2111 struct labelTapeIf *labelIfPtr = (struct labelTapeIf *)param;
2113 struct tc_tapeLabel *label = &labelIfPtr->label;
2115 struct butm_tapeLabel newTapeLabel;
2116 struct butm_tapeInfo tapeInfo;
2120 taskId = labelIfPtr->taskId;
2121 setStatus(taskId, DRIVE_WAIT);
2122 EnterDeviceQueue(deviceLatch);
2123 clearStatus(taskId, DRIVE_WAIT);
2126 TLog(taskId, "Labeltape\n");
2128 memset(&tapeInfo, 0, sizeof(tapeInfo));
2129 tapeInfo.structVersion = BUTM_MAJORVERSION;
2130 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2132 ErrorLog(0, taskId, code, tapeInfo.error,
2133 "Can't initialize the tape module\n");
2137 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2139 newTapeLabel.size = label->size;
2141 newTapeLabel.size = globalTapeConfig.capacity;
2143 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2148 if (code == TC_ABORTEDBYREQUEST) {
2149 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2150 clearStatus(taskId, ABORT_REQUEST);
2151 setStatus(taskId, ABORT_DONE);
2153 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2154 setStatus(taskId, TASK_ERROR);
2156 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2157 TNAME(&newTapeLabel), newTapeLabel.size);
2159 setStatus(labelIfPtr->taskId, TASK_DONE);
2162 LeaveDeviceQueue(deviceLatch);
2163 return (void *)(intptr_t)(code);
2167 * print out the tape label.
2171 PrintTapeLabel(struct butm_tapeLabel *labelptr)
2173 char tapeName[BU_MAXTAPELEN + 32];
2176 printf("Tape label\n");
2177 printf("----------\n");
2178 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2179 printf("permanent tape name = %s\n", tapeName);
2180 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2181 printf("AFS tape name = %s\n", tapeName);
2182 t = labelptr->creationTime;
2183 printf("creationTime = %s", ctime(&t));
2184 if (labelptr->expirationDate) {
2185 t = labelptr->expirationDate;
2186 printf("expirationDate = %s", cTIME(&t));
2188 printf("cell = %s\n", labelptr->cell);
2189 printf("size = %u Kbytes\n", labelptr->size);
2190 printf("dump path = %s\n", labelptr->dumpPath);
2192 if (labelptr->structVersion >= TAPE_VERSION_3) {
2193 printf("dump id = %u\n", labelptr->dumpid);
2194 printf("useCount = %d\n", labelptr->useCount);
2196 printf("-- End of tape label --\n\n");
2200 * Read the label from a tape.
2201 * Currently prints out a "detailed" summary of the label but passes
2202 * back only selected fields.
2206 ReadLabel(struct tc_tapeLabel *label)
2208 struct butm_tapeLabel newTapeLabel;
2209 struct butm_tapeInfo tapeInfo;
2213 int interactiveFlag;
2216 EnterDeviceQueue(deviceLatch);
2217 taskId = allocTaskId(); /* reqd for lower level rtns */
2220 TLog(taskId, "Readlabel\n");
2222 memset(&tapeInfo, 0, sizeof(tapeInfo));
2223 tapeInfo.structVersion = BUTM_MAJORVERSION;
2224 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2226 ErrorLog(0, taskId, code, tapeInfo.error,
2227 "Can't initialize the tape module\n");
2230 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2232 interactiveFlag = autoQuery;
2235 if (interactiveFlag) {
2236 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2240 interactiveFlag = 1;
2243 code = butm_Mount(&tapeInfo, "");
2245 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2251 unmountTape(taskId, &tapeInfo);
2254 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2256 if (code == BUTM_NOLABEL) {
2257 printf("Tape is unlabelled\n");
2260 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2264 /* copy the fields to be passed to the caller */
2265 label->size = newTapeLabel.size;
2266 label->tapeId = newTapeLabel.dumpid;
2267 strcpy(label->afsname, newTapeLabel.AFSName);
2268 strcpy(label->pname, newTapeLabel.pName);
2271 expir = ExpirationDate(newTapeLabel.dumpid);
2273 newTapeLabel.expirationDate = expir;
2275 PrintTapeLabel(&newTapeLabel);
2278 unmountTape(taskId, &tapeInfo);
2280 if (code == TC_ABORTEDBYREQUEST)
2281 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2282 else if (code && (code != BUTM_NOLABEL))
2283 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2285 TLog(taskId, "ReadLabel: Finished\n");
2287 LeaveDeviceQueue(deviceLatch);
2291 /* Function to read volume header and trailer structure from tape, taking
2292 into consideration, different word alignment rules.
2295 readVolumeHeader(char *buffer, /* in - buffer to read header from */
2296 afs_int32 bufloc, /* in - header's location in buffer */
2297 struct volumeHeader *header) /* out -header structure */
2299 struct volumeHeader vhptr, *tempvhptr;
2300 afs_int32 firstSplice = (afs_int32) ((char*)& vhptr.pad - (char*) & vhptr);
2301 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2302 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2304 /* Four cases are to be handled
2306 * Volume Header (byte alignment)
2307 * -----------------------
2314 * -----------------------
2316 * Case 2 and Case 3 are identical cases and handled the same way.
2317 * Case 1 and Case 4 are separate cases. In one case the pad needs
2318 * to be removed and in the other, it needs to be spliced in. The
2319 * four cases are handled as follows
2321 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2322 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2323 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2324 /* Handle Cases 2 & 3 */
2325 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2326 HEADER_CHECKS(vhptr, header);
2329 memset(&vhptr, 0, sizeof(struct volumeHeader));
2330 memcpy(&vhptr, buffer + bufloc, firstSplice);
2331 memset(&vhptr.pad, 0, padLen);
2332 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2333 HEADER_CHECKS(vhptr, header);
2336 memset(&vhptr, 0, sizeof(struct volumeHeader));
2337 memcpy(&vhptr, buffer + bufloc, firstSplice);
2338 /* probably GCC bug 37060; however, no guarantee on length of buffer */
2339 tempvhptr = (struct volumeHeader *)(buffer + firstSplice);
2340 memcpy(tempvhptr, buffer + bufloc + firstSplice + padLen,
2342 HEADER_CHECKS(vhptr, header);
2345 return (TC_BADVOLHEADER);