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[];
120 /* forward declaration */
121 afs_int32 readVolumeHeader(char *, afs_int32, struct volumeHeader *);
122 int FindVolTrailer(char *, afs_int32, afs_int32 *, struct volumeHeader *);
123 int FindVolTrailer2(char *, afs_int32, afs_int32 *, char *, afs_int32,
124 afs_int32 *, struct volumeHeader *);
125 int SkipVolume(struct tc_restoreDesc *, afs_int32, afs_int32, afs_int32,
130 /* The on-disk volume header or trailer can differ in size from platform to platform */
131 static struct TapeBlock tapeBlock;
132 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
135 PrintLogStr(FILE *log, afs_int32 error1, afs_int32 error2, char *str)
139 fprintf(log, "%s", str);
144 err1 = "Volume needs to be salvaged";
147 err1 = "Bad vnode number quoted";
150 err1 = "Volume not attached, does not exist, or not on line";
153 err1 = "Volume already exists";
156 err1 = "Volume is not in service";
159 err1 = "Volume is off line";
162 err1 = "Volume is already on line";
165 err1 = "Partition is full";
168 err1 = "Volume max quota exceeded";
171 err1 = "Volume temporarily unavailable";
174 err1 = "Volume has moved to another server";
177 err1 = (char *)afs_error_message(error1);
178 err2 = (char *)afs_error_table_name(error1);
182 fprintf(log, " Possible communication failure");
184 fprintf(log, " %s: %s", err2, err1);
186 fprintf(log, ": %s", afs_error_message(error2));
193 TapeLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
201 if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %T %Y",
202 localtime_r(&now, &tm)) != 0)
203 fprintf(logIO, "%s: ", tbuffer);
206 fprintf(logIO, "Task %u: ", task);
207 PrintLogStr(logIO, error1, error2, str);
209 if (lastPass && lastLogIO) {
210 fprintf(lastLogIO, "%s: ", tbuffer);
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,
258 if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %T %Y",
259 localtime_r(&now, &tm)) != 0)
260 fprintf(ErrorlogIO, "%s: ", tbuffer);
262 /* Print the time and task number */
264 fprintf(ErrorlogIO, "Task %u: ", task);
266 PrintLogStr(ErrorlogIO, error1, error2, errStr);
267 TapeLogStr(debug, task, error1, error2, errStr);
271 ErrorLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
278 vsnprintf(tmp, sizeof(tmp), fmt, ap);
281 ErrorLogStr(debug, task, error1, error2, tmp);
286 ELog(afs_int32 task, char *fmt, ...)
292 vsnprintf(tmp, sizeof(tmp), fmt, ap);
295 /* Sends message to ErrorLog, TapeLog and stdout */
296 ErrorLog(0, task, 0, 0, "%s", tmp);
299 /* first proc called by anybody who intends to use the device */
301 EnterDeviceQueue(struct deviceSyncNode *devLatch)
303 ObtainWriteLock(&(devLatch->lock));
304 devLatch->flags = TC_DEVICEINUSE;
307 /* last proc called by anybody finishing using the device */
309 LeaveDeviceQueue(struct deviceSyncNode *devLatch)
312 ReleaseWriteLock(&(devLatch->lock));
315 #define BELLTIME 60 /* 60 seconds before a bell rings */
316 #define BELLCHAR 7 /* ascii for bell */
322 * only external clients are in recoverDb.c. Was static. PA
332 w = LWP_WaitForKeystroke(0);
338 #endif /* AFS_NT40_ENV */
346 callOutRoutine(afs_int32 taskId, char *tapePath, int flag, char *name,
347 afs_uint32 dbDumpId, int tapecount)
363 callOut = opencallout;
366 strcpy(Sopcode, "restore");
369 strcpy(Sopcode, "appenddump");
372 strcpy(Sopcode, "dump");
375 strcpy(Sopcode, "labeltape");
377 case READLABELOPCODE:
378 strcpy(Sopcode, "readlabel");
381 strcpy(Sopcode, "scantape");
383 case RESTOREDBOPCODE:
384 strcpy(Sopcode, "restoredb");
387 strcpy(Sopcode, "savedb");
390 strcpy(Sopcode, "unmount");
391 callOut = closecallout;
394 strcpy(Sopcode, "unknown");
398 if (!callOut) /* no script to call */
401 strcpy(ScallOut, callOut);
402 CO_argv[0] = ScallOut;
404 strcpy(StapePath, tapePath);
405 CO_argv[1] = StapePath;
407 CO_argv[2] = Sopcode;
409 if (flag == CLOSEOPCODE) {
412 sprintf(Scount, "%d", tapecount);
415 /* The tape label name - special case labeltape */
416 if (!name || (strcmp(name, "") == 0)) /* no label */
417 strcpy(Stape, "none");
418 else { /* labeltape */
420 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
421 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
430 strcpy(Sdumpid, "none");
432 sprintf(Sdumpid, "%u", dbDumpId);
433 CO_argv[5] = Sdumpid;
440 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
442 ErrorLog(0, taskId, errno, 0,
443 "Call to %s outside routine %s failed\n", Sopcode, callOut);
452 * Unmounts a tape and prints a warning if it can't unmount it.
453 * Regardless of error, the closecallout routine will be called
454 * (unless a tape is not mounted in the first place).
457 unmountTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr)
460 int cpid, status, rcpid;
462 code = butm_Dismount(tapeInfoPtr);
463 if (code && (code != BUTM_NOMOUNT))
464 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
465 "Warning: Can't close tape\n");
467 if (tapemounted && closecallout) {
468 setStatus(taskId, CALL_WAIT);
471 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
473 while (cpid) { /* Wait until return */
475 rcpid = waitpid(cpid, &status, WNOHANG);
480 if (rcpid == -1 && errno != EINTR) {
482 afs_com_err(whoami, errno,
483 "Error waiting for callout script to terminate.");
486 #ifdef AFS_PTHREAD_ENV
492 if (checkAbortByTaskId(taskId)) {
493 TLog(taskId, "Callout routine has been aborted\n");
494 if (kill(cpid, SIGKILL)) /* Cancel callout */
495 ErrorLog(0, taskId, errno, 0,
496 "Kill of callout process %d failed\n", cpid);
501 clearStatus(taskId, CALL_WAIT);
505 * print out prompt to operator
507 * PromptForTape only.
511 PrintPrompt(int flag, char *name, int dumpid)
513 char tapename[BU_MAXTAPELEN + 32];
516 TAPENAME(tapename, name, dumpid);
518 printf("******* OPERATOR ATTENTION *******\n");
519 printf("Device : %s \n", globalTapeConfig.device);
522 case READOPCODE: /* mount for restore */
523 printf("Please put in tape %s for reading", tapename);
526 case APPENDOPCODE: /* mount for dump (appends) */
528 dn = extractDumpName(name);
531 printf("Please put in last tape of dump set for appending dump");
534 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
538 case WRITEOPCODE: /* mount for dump */
539 if (strcmp(name, "") == 0)
540 printf("Please put in tape for writing");
542 /* The name is what we are going to label the tape as */
544 printf("Please put in tape %s for writing", tapename);
547 case LABELOPCODE: /* mount for labeltape */
548 printf("Please put in tape to be labelled as %s", tapename);
551 case READLABELOPCODE: /* mount for readlabel */
552 printf("Please put in tape whose label is to be read");
555 case SCANOPCODE: /* mount for scantape */
556 if (strcmp(name, "") == 0)
557 printf("Please put in tape to be scanned");
559 printf("Please put in tape %s for scanning", tapename);
562 case RESTOREDBOPCODE: /* Mount for restoredb */
563 printf("Please insert a tape %s for the database restore", tapename);
566 case SAVEDBOPCODE: /* Mount for savedb */
567 printf("Please insert a writable tape %s for the database dump",
574 printf(" and hit return when done\n");
578 * Prompt the operator to change the tape.
579 * Use to be a void routine but now returns an error. Some calls
580 * don't use the error code.
582 * only external clients are in recoverDb.c. Was static PA
585 PromptForTape(int flag, char *name, afs_uint32 dbDumpId, afs_uint32 taskId,
593 int cpid, status, rcpid;
595 if (checkAbortByTaskId(taskId))
596 ERROR_EXIT(TC_ABORTEDBYREQUEST);
599 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
601 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
603 CallOut = (opencallout ? 1 : 0);
605 setStatus(taskId, CALL_WAIT);
608 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
609 dbDumpId, tapecount);
611 CallOut = 0; /* prompt at screen */
613 while (CallOut) { /* Check if callout routine finished */
615 rcpid = waitpid(cpid, &status, WNOHANG);
619 else if (WIFEXITED(status))
620 wcode = WEXITSTATUS(status);
625 break; /* All done */
626 } else if (wcode == 1) {
627 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
628 } else if ((flag == READOPCODE) && (wcode == 3)) {
629 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
632 "Callout routine has exited with code %d: will prompt\n",
634 CallOut = 0; /* Switch to keyboard input */
638 /* if waitpid experienced an error, we prompt */
639 if (rcpid == -1 && errno != EINTR) {
640 afs_com_err(whoami, errno,
641 "Error waiting for callout script to terminate.");
643 "Can't get exit status from callout script. will prompt\n");
647 #ifdef AFS_PTHREAD_ENV
653 if (checkAbortByTaskId(taskId)) {
655 ("This tape operation has been aborted by the coordinator.\n");
657 if (kill(cpid, SIGKILL)) /* Cancel callout */
658 ErrorLog(0, taskId, errno, 0,
659 "Kill of callout process %d failed\n", cpid);
661 ERROR_EXIT(TC_ABORTEDBYREQUEST);
667 clearStatus(taskId, CALL_WAIT);
668 setStatus(taskId, OPR_WAIT);
670 PrintPrompt(flag, name, dbDumpId);
672 /* Loop until we get ok to go ahead (or abort) */
674 if (time(0) > start + BELLTIME) {
680 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
681 if (wcode == 1) { /* keyboard input is available */
683 if ((inchr == 'a') || (inchr == 'A')) {
684 printf("This tape operation has been aborted.\n");
685 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
686 } else if ((flag == READOPCODE)
687 && ((inchr == 's') || (inchr == 'S'))) {
688 printf("This tape will be skipped.\n");
689 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
691 break; /* continue */
694 if (checkAbortByTaskId(taskId)) {
696 ("This tape operation has been aborted by the coordinator.\n");
697 ERROR_EXIT(TC_ABORTEDBYREQUEST);
703 printf("Thanks, now proceeding with tape ");
705 case RESTOREDBOPCODE:
711 printf("append writing");
723 case READLABELOPCODE:
724 printf("label reading");
736 printf(" operation.\n");
738 printf("**********************************\n");
740 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
744 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
750 * convert the fields in the tapeVolHeader into host byte order,
751 * placing the converted copy of the structure into the hostVolHeader
753 * tapeVolHeader - points to volume header read from tape
754 * hostVolHeader - pointer to struct for result
756 * hostVolHeader - information in host byte order
760 VolHeaderToHost(struct volumeHeader *hostVolHeader,
761 struct volumeHeader *tapeVolHeader)
763 switch (ntohl(tapeVolHeader->versionflags)) {
765 /* sizes in bytes and fields in host order */
766 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
771 case TAPE_VERSION_3: /* for present */
773 /* sizes in K and fields in network order */
774 /* do the conversion field by field */
776 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
777 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
778 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
779 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
780 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
781 hostVolHeader->server = ntohl(tapeVolHeader->server);
782 hostVolHeader->part = ntohl(tapeVolHeader->part);
783 hostVolHeader->from = ntohl(tapeVolHeader->from);
784 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
785 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
786 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
787 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
788 hostVolHeader->level = ntohl(tapeVolHeader->level);
789 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
790 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
791 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
792 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
796 return (TC_BADVOLHEADER);
802 ReadVolHeader(afs_int32 taskId,
803 struct butm_tapeInfo *tapeInfoPtr,
804 struct volumeHeader *volHeaderPtr)
808 struct volumeHeader volHead;
810 /* Read the volume header */
812 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
815 ErrorLog(0, taskId, code, tapeInfoPtr->error,
816 "Can't read volume header on tape\n");
820 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
822 ErrorLog(0, taskId, code, 0,
823 "Can't find volume header on tape block\n");
827 code = VolHeaderToHost(volHeaderPtr, &volHead);
829 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
838 GetVolumeHead(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
839 afs_int32 position, char *volName, afs_int32 volId)
842 struct volumeHeader tapeVolHeader;
844 /* Position directly to the volume and read the header */
846 code = butm_Seek(tapeInfoPtr, position);
848 ErrorLog(0, taskId, code, tapeInfoPtr->error,
849 "Can't seek to position %u on tape\n", position);
853 code = butm_ReadFileBegin(tapeInfoPtr);
855 ErrorLog(0, taskId, code, tapeInfoPtr->error,
856 "Can't read FileBegin on tape\n");
860 /* Read the volume header */
861 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
865 /* Check if volume header matches */
866 if (strcmp(tapeVolHeader.volumeName, volName))
867 ERROR_EXIT(TC_BADVOLHEADER);
868 if (volId && (tapeVolHeader.volumeID != volId))
869 ERROR_EXIT(TC_BADVOLHEADER);
870 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
871 ERROR_EXIT(TC_BADVOLHEADER);
874 /* Do a sequential search for the volume */
877 code = butm_ReadFileBegin(tapeInfoPtr);
879 ErrorLog(0, taskId, code, tapeInfoPtr->error,
880 "Can't read FileBegin on tape\n");
884 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
886 ERROR_EXIT(TC_VOLUMENOTONTAPE);
888 /* Test if we found the volume */
889 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
890 && (!volId || (volId == tapeVolHeader.volumeID)))
893 /* skip to the next HW EOF marker */
894 code = SeekFile(tapeInfoPtr, 1);
896 ErrorLog(0, taskId, code, tapeInfoPtr->error,
897 "Can't seek to next EOF on tape\n");
908 GetRestoreTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
909 char *tname, afs_int32 tapeID, int prompt)
911 struct butm_tapeLabel tapeLabel;
912 afs_int32 code = 0, rc;
914 struct budb_dumpEntry dumpEntry;
916 /* Make sure that the dump/tape is not a XBSA dump */
917 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
918 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
919 ErrorLog(0, taskId, 0, 0,
920 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
921 ERROR_EXIT(TC_SKIPTAPE);
927 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
934 code = butm_Mount(tapeInfoPtr, tname);
936 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
940 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
942 ErrorLog(0, taskId, code, tapeInfoPtr->error,
943 "Can't read tape label\n");
947 /* Now check the label to see if the tapename matches or tapeids match */
948 if (strcmp(TNAME(&tapeLabel), tname)
949 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
950 && (tapeLabel.dumpid != tapeID))) {
951 char expectedName[BU_MAXTAPELEN + 32],
952 gotName[BU_MAXTAPELEN + 32];
954 TAPENAME(expectedName, tname, tapeID);
955 LABELNAME(gotName, &tapeLabel);
957 TapeLog(0, taskId, 0, 0,
958 "Tape label expected %s, label seen %s\n", expectedName,
966 unmountTape(taskId, tapeInfoPtr);
974 xbsaRestoreVolumeData(struct rx_call *call, void *rock)
978 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
979 afs_int32 curChunk, rc;
980 afs_uint32 totalWritten;
981 afs_int32 headBytes, tailBytes, w;
983 struct volumeHeader volTrailer;
984 afs_int32 vtsize = 0;
986 struct dumpNode *nodePtr;
987 struct tc_restoreDesc *Restore;
988 afs_int32 bytesRead, tbuffersize, endData = 0;
989 char *buffer = (char *)bufferBlock, tbuffer[256];
991 nodePtr = rparamsPtr->nodePtr;
992 Restore = nodePtr->restores;
993 taskId = nodePtr->taskID;
995 /* Read the volume fragment one block at a time until
996 * find a volume trailer
998 curChunk = BIGCHUNK + 1;
1003 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1005 if (restoretofile && (bytesRead > 0)) {
1006 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1008 if (rc != XBSA_SUCCESS) {
1009 ErrorLog(0, taskId, rc, 0,
1010 "Unable to read volume data from the server\n");
1014 /* Periodically update status structure and check if should abort */
1015 curChunk += bytesRead;
1016 if (curChunk > BIGCHUNK) {
1019 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1022 if (checkAbortByTaskId(taskId))
1023 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1026 if (!endData && (bytesRead > 0)) {
1027 /* Fill tbuffer up with data from end of buffer and write
1028 * the remainder of buffer out.
1030 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1031 /* Write out contents of tbuffer */
1033 w = rx_Write(call, tbuffer, tbuffersize);
1034 if (w != tbuffersize) {
1035 ErrorLog(0, taskId, -1, 0,
1036 "Error in RX write: Wrote %d bytes\n", w);
1041 /* fill tbuffer with end of buffer */
1042 bytesRead -= sizeof(tbuffer);
1043 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1044 tbuffersize = sizeof(tbuffer);
1045 /* Write out whatever is left over in buffer */
1047 w = rx_Write(call, buffer, bytesRead);
1048 if (w != bytesRead) {
1049 ErrorLog(0, taskId, -1, 0,
1050 "Error in RX data write: Wrote %d bytes\n",
1057 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1058 /* Copy all of buffer into tbuffer (it will fit) */
1059 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1060 tbuffersize += bytesRead;
1063 /* We need to write some of tbuffer out and fill it with buffer */
1064 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1065 w = rx_Write(call, tbuffer, towrite);
1067 ErrorLog(0, taskId, -1, 0,
1068 "Error in RX write: Wrote %d bytes\n", w);
1074 /* Move the data in tbuffer up */
1075 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1077 /* Now copy buffer in */
1078 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1079 tbuffersize += bytesRead;
1085 /* Pull the volume trailer from the last two buffers */
1087 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1088 &tailBytes, &volTrailer);
1091 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1092 ERROR_EXIT(TC_MISSINGTRAILER);
1095 /* Now rx_write the data in the last two blocks */
1097 w = rx_Write(call, tbuffer, headBytes);
1098 if (w != headBytes) {
1099 ErrorLog(0, taskId, -1, 0,
1100 "Error in RX trail1 write: Wrote %d bytes\n", w);
1106 w = rx_Write(call, buffer, tailBytes);
1107 if (w != tailBytes) {
1108 ErrorLog(0, taskId, -1, 0,
1109 "Error in RX trail2 write: Wrote %d bytes\n", w);
1121 * sends the contents of volume dump to Rx Stream associated
1126 restoreVolumeData(struct rx_call *call, void *rock)
1128 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
1130 afs_uint32 totalWritten = 0;
1132 afs_int32 headBytes, tailBytes, w;
1134 afs_int32 nbytes; /* # bytes data in last tape block read */
1135 struct volumeHeader tapeVolTrailer;
1138 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1139 struct tc_restoreDesc *Restore;
1140 struct dumpNode *nodePtr;
1141 struct butm_tapeInfo *tapeInfoPtr;
1143 afs_int32 origVolID;
1145 nodePtr = rparamsPtr->nodePtr;
1146 taskId = nodePtr->taskID;
1147 Restore = nodePtr->restores;
1148 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1149 origVolName = Restore[rparamsPtr->frag].oldName;
1150 origVolID = Restore[rparamsPtr->frag].origVid;
1152 /* Read the volume one fragment at a time */
1153 while (rparamsPtr->frag < nodePtr->arraySize) {
1155 curChunk = BIGCHUNK + 1; /* Check if should abort */
1157 /* Read the volume fragment one block at a time until
1158 * find a volume trailer
1164 while (moretoread) {
1165 /* Fill the circular buffer with tape blocks
1166 * Search for volume trailer in the process.
1171 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1172 BUTM_BLKSIZE, &nbytes);
1174 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1175 "Can't read FileData on tape %s\n",
1176 rparamsPtr->mntTapeName);
1179 curChunk += BUTM_BLKSIZE;
1181 /* Periodically update status structure and check if should abort */
1182 if (curChunk > BIGCHUNK) {
1186 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1189 if (checkAbortByTaskId(taskId))
1190 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1193 /* step to next block in buffer */
1195 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1197 /* If this is the end of the volume, the exit the loop */
1198 if ((nbytes != BUTM_BLKSIZE)
1201 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1205 } while (moretoread && (buf != endRbuf));
1207 /* Write the buffer upto (but not including) the last read block
1208 * If volume is completely read, then leave the last two blocks.
1210 lastbuf = endWbuf = pbuf;
1211 if (!moretoread && (endWbuf != startWbuf))
1212 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1214 for (buf = startWbuf; buf != endWbuf;
1215 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1216 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1217 if (w != BUTM_BLKSIZE) {
1218 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1221 totalWritten += BUTM_BLKSIZE;
1224 /* Setup pointers to refill buffer */
1225 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1227 startWbuf = endWbuf;
1230 /* lastbuf is last block read and it has nbytes of data
1231 * startWbuf is the 2nd to last block read
1232 * Seach for the volume trailer in these two blocks.
1234 if (lastbuf == startWbuf)
1236 FindVolTrailer2(NULL, 0, &headBytes,
1237 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1241 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1242 &headBytes, bufferBlock[lastbuf].data, nbytes,
1243 &tailBytes, &tapeVolTrailer);
1245 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1246 "Missing volume trailer on tape %s\n",
1247 rparamsPtr->mntTapeName);
1248 ERROR_EXIT(TC_MISSINGTRAILER);
1251 /* Now rx_write the data in the last two blocks */
1253 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1254 if (w != headBytes) {
1255 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1258 totalWritten += headBytes;
1261 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1262 if (w != tailBytes) {
1263 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1266 totalWritten += tailBytes;
1269 /* Exit the loop if the volume is not continued on next tape */
1270 if (!tapeVolTrailer.contd)
1271 break; /* We've read the entire volume */
1273 /* Volume is continued on next tape.
1274 * Step to the next volume fragment and prompt for its tape.
1275 * When a volume has multiple frags, those frags are on different
1276 * tapes. So we know that we need to prompt for a tape.
1279 if (rparamsPtr->frag >= nodePtr->arraySize)
1282 unmountTape(taskId, tapeInfoPtr);
1283 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1284 rparamsPtr->tapeID =
1285 (Restore[rparamsPtr->frag].
1286 initialDumpId ? Restore[rparamsPtr->frag].
1287 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1289 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1290 rparamsPtr->tapeID, 1);
1294 /* Position to the frag and read the volume header */
1296 GetVolumeHead(taskId, tapeInfoPtr,
1297 Restore[rparamsPtr->frag].position, origVolName,
1300 ErrorLog(0, taskId, code, 0,
1301 "Can't find volume %s (%u) on tape %s\n", origVolName,
1302 origVolID, rparamsPtr->mntTapeName);
1303 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1312 * Find all the volumes on a specific tape and mark them to skip.
1315 SkipTape(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1316 char *tapename, afs_int32 tapeid, afs_int32 taskid)
1320 for (i = index; i < size; i++) {
1321 if (Restore[i].flags & RDFLAG_SKIP)
1324 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1326 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1327 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1334 * Find all the entries for a volume and mark them to skip.
1337 SkipVolume(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1338 afs_int32 volid, afs_int32 taskid)
1343 for (i = index; i < size; i++) {
1344 if (Restore[i].flags & RDFLAG_SKIP)
1346 if (Restore[i].origVid == volid) {
1347 Restore[i].flags |= RDFLAG_SKIP;
1349 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1350 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1351 Restore[i].oldName, volid);
1360 xbsaRestoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1361 struct restoreParams *rparamsPtr)
1366 afs_int32 newServer, newPart, newVolId;
1368 int restoreflags, havetrans = 0, startread = 0;
1369 afs_int32 bytesRead, endData = 0;
1371 struct budb_dumpEntry dumpEntry;
1372 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1373 struct volumeHeader volHeader, hostVolHeader;
1375 if (restoretofile) {
1376 restoretofilefd = fopen(restoretofile, "w+");
1379 dumpID = restoreInfo->dbDumpId;
1381 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1383 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1388 /* ADSM servers restore ADSM and BUTA dumps */
1389 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1390 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1392 "The dump requested by this restore operation for the "
1393 "volumeset is incompatible with this instance of butc\n");
1394 /* Skip the entire dump (one dump per tape) */
1395 ERROR_EXIT(TC_SKIPTAPE);
1398 /* make sure we are connected to the correct server. */
1399 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1400 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1402 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1403 && !forcemultiple) {
1405 "Dump %d is on server %s but butc is connected "
1406 "to server %s (attempting to restore)\n", dumpID,
1407 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1410 "Dump %d is on server %s but butc is connected "
1411 "to server %s (switching servers)\n", dumpID,
1412 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1414 rc = InitToServer(taskId, &butxInfo,
1415 (char *)dumpEntry.tapes.tapeServer);
1416 if (rc != XBSA_SUCCESS)
1417 ERROR_EXIT(TC_SKIPTAPE);
1421 /* Start a transaction and query the server for the correct fileset dump */
1422 rc = xbsa_BeginTrans(&butxInfo);
1423 if (rc != XBSA_SUCCESS) {
1424 ELog(taskId, "Unable to create a new transaction\n");
1425 ERROR_EXIT(TC_SKIPTAPE);
1429 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1430 sprintf(dumpIdStr, "/%d", dumpID);
1431 strcpy(volumeNameStr, "/");
1432 strcat(volumeNameStr, restoreInfo->oldName);
1433 } else { /* new butc names */
1434 extern char *butcdumpIdStr;
1435 strcpy(dumpIdStr, butcdumpIdStr);
1436 sprintf(volumeNameStr, "/%d", dumpID);
1437 strcat(volumeNameStr, "/");
1438 strcat(volumeNameStr, restoreInfo->oldName);
1441 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1442 if (rc != XBSA_SUCCESS) {
1444 "Unable to locate object (%s) of dump (%s) on the server\n",
1445 volumeNameStr, dumpIdStr);
1449 rc = xbsa_EndTrans(&butxInfo);
1451 if (rc != XBSA_SUCCESS) {
1452 ELog(taskId, "Unable to terminate the current transaction\n");
1456 if (checkAbortByTaskId(taskId))
1457 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1459 /* Now start a transaction on the volume to restore and read the
1460 * volumeheader. We do this before starting a transaction on
1461 * volserver to restore the volume because the XBSA server may take
1462 * a while to mount and seek to the volume causing the volserver to
1465 rc = xbsa_BeginTrans(&butxInfo);
1466 if (rc != XBSA_SUCCESS) {
1467 ELog(taskId, "Unable to create a new transaction\n");
1468 ERROR_EXIT(TC_SKIPTAPE);
1472 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1473 sizeof(volHeader), &bytesRead, &endData);
1474 if (restoretofile && (bytesRead > 0)) {
1475 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1477 if (rc != XBSA_SUCCESS) {
1479 "Unable to begin reading of the volume from the server\n");
1484 if ((bytesRead != sizeof(volHeader)) || endData) {
1486 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1487 bytesRead, sizeof(volHeader));
1488 ERROR_EXIT(TC_BADVOLHEADER);
1491 /* convert and check the volume header */
1492 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1494 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1498 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1499 || (restoreInfo->origVid
1500 && (hostVolHeader.volumeID != restoreInfo->origVid))
1501 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1502 ERROR_EXIT(TC_BADVOLHEADER);
1504 /* Set up prior restoring volume data */
1505 newVolName = restoreInfo->newName;
1506 newVolId = restoreInfo->vid;
1507 newServer = restoreInfo->hostAddr;
1508 newPart = restoreInfo->partition;
1510 if ((restoreInfo->dumpLevel == 0)
1511 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1512 restoreflags |= RV_FULLRST;
1513 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1514 restoreflags |= RV_OFFLINE;
1516 if (checkAbortByTaskId(taskId))
1517 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1519 /* Start the restore of the volume data. This is the code we want to return */
1521 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1522 restoreflags, xbsaRestoreVolumeData,
1523 (char *)rparamsPtr);
1526 rc = xbsa_ReadObjectEnd(&butxInfo);
1527 if (rc != XBSA_SUCCESS) {
1529 "Unable to terminate reading of the volume from the server\n");
1535 rc = xbsa_EndTrans(&butxInfo);
1536 if (rc != XBSA_SUCCESS) {
1537 ELog(taskId, "Unable to terminate the current transaction\n");
1543 if (restoretofile && restoretofilefd) {
1544 fclose(restoretofilefd);
1551 restoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1552 struct restoreParams *rparamsPtr)
1554 afs_int32 code = 0, rc;
1555 afs_int32 newServer, newPart, newVolId;
1559 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1561 /* Check if we need a tape and prompt for one if so */
1563 (restoreInfo->initialDumpId ? restoreInfo->
1564 initialDumpId : restoreInfo->dbDumpId);
1565 if ((rparamsPtr->frag == 0)
1566 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1567 || (tapeID != rparamsPtr->tapeID)) {
1568 /* Unmount the previous tape */
1569 unmountTape(taskId, tapeInfoPtr);
1571 /* Remember this new tape */
1572 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1573 rparamsPtr->tapeID = tapeID;
1575 /* Mount a new tape */
1576 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1578 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1583 /* Seek to the correct spot and read the header information */
1584 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1585 restoreInfo->oldName, restoreInfo->origVid);
1589 /* Set up prior restoring volume data */
1590 newVolName = restoreInfo->newName;
1591 newVolId = restoreInfo->vid;
1592 newServer = restoreInfo->hostAddr;
1593 newPart = restoreInfo->partition;
1595 if ((restoreInfo->dumpLevel == 0)
1596 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1597 restoreflags |= RV_FULLRST;
1598 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1599 restoreflags |= RV_OFFLINE;
1601 if (checkAbortByTaskId(taskId))
1602 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1604 /* Start the restore of the volume data. This is the code we
1608 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1609 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1611 /* Read the FileEnd marker for the volume and step to next FM */
1612 rc = butm_ReadFileEnd(tapeInfoPtr);
1614 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1615 "Can't read EOF on tape\n");
1623 * created as a LWP by the server stub, <newNode> is a pointer to all
1624 * the parameters Restorer needs
1627 Restorer(void *param) {
1628 struct dumpNode *newNode = (struct dumpNode *) param;
1630 afs_int32 code = 0, tcode;
1633 struct butm_tapeInfo tapeInfo;
1634 struct tc_restoreDesc *Restore;
1635 struct tc_restoreDesc *RestoreDesc;
1636 struct restoreParams rparams;
1637 afs_int32 allocbufferSize;
1638 time_t startTime, endTime;
1639 afs_int32 goodrestore = 0;
1641 taskId = newNode->taskID;
1642 setStatus(taskId, DRIVE_WAIT);
1643 EnterDeviceQueue(deviceLatch);
1644 clearStatus(taskId, DRIVE_WAIT);
1647 TLog(taskId, "Restore\n");
1649 memset(&tapeInfo, 0, sizeof(tapeInfo));
1651 tapeInfo.structVersion = BUTM_MAJORVERSION;
1652 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1654 ErrorLog(0, taskId, tcode, tapeInfo.error,
1655 "Can't initialize the tape module\n");
1660 if (checkAbortByTaskId(taskId))
1661 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1663 memset(&rparams, 0, sizeof(rparams));
1664 rparams.nodePtr = newNode;
1665 rparams.tapeInfoPtr = &tapeInfo;
1666 Restore = newNode->restores; /* Array of vol fragments to restore */
1668 /* Allocate memory in which to restore the volumes data into */
1670 allocbufferSize = dataSize = BufferSize;
1672 /* Must have at least two tape blocks */
1673 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1676 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1679 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1681 ERROR_EXIT(TC_NOMEMORY);
1682 memset(bufferBlock, 0, allocbufferSize);
1684 startTime = time(0);
1685 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1687 RestoreDesc = &Restore[rparams.frag];
1689 /* Skip the volume if it was requested to */
1690 if (RestoreDesc->flags & RDFLAG_SKIP) {
1691 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1692 /* If the volume was restored, should bring it online */
1697 newVolName = RestoreDesc->newName;
1699 /* Make sure the server to restore to is good */
1700 if (!RestoreDesc->hostAddr) {
1701 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1703 ERROR_EXIT(TC_INTERNALERROR);
1706 if (checkAbortByTaskId(taskId))
1707 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1709 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1711 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1715 /* restoreVolume function takes care of all the related fragments
1716 * spanning various tapes. On return the complete volume has been
1720 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1722 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1725 if (tcode == TC_ABORTEDBYREQUEST) {
1727 } else if (tcode == TC_SKIPTAPE) {
1730 (RestoreDesc->initialDumpId ? RestoreDesc->
1731 initialDumpId : RestoreDesc->dbDumpId);
1732 SkipTape(Restore, newNode->arraySize, rparams.frag,
1733 RestoreDesc->tapeName, tapeID, taskId);
1735 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1737 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1738 RestoreDesc->origVid, taskId);
1750 unmountTape(taskId, &tapeInfo);
1753 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1760 if (code == TC_ABORTEDBYREQUEST) {
1761 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1762 clearStatus(taskId, ABORT_REQUEST);
1763 setStatus(taskId, ABORT_DONE);
1765 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1766 setStatus(taskId, TASK_ERROR);
1768 TLog(taskId, "Restore: Finished\n");
1771 if (centralLogIO && startTime) {
1773 afs_int32 hrs, min, sec, tmp;
1775 struct tm tmstart, tmend;
1777 localtime_r(&startTime, &tmstart);
1778 localtime_r(&endTime, &tmend);
1779 timediff = (int)endTime - (int)startTime;
1780 hrs = timediff / 3600;
1781 tmp = timediff % 3600;
1786 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1787 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1788 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1789 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1790 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1791 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1792 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1793 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1795 fwrite(line, strlen(line), 1, centralLogIO);
1796 fflush(centralLogIO);
1799 setStatus(taskId, TASK_DONE);
1802 LeaveDeviceQueue(deviceLatch);
1803 return (void *)(intptr_t)(code);
1806 /* this is just scaffolding, creates new tape label with name <tapeName> */
1809 GetNewLabel(struct butm_tapeInfo *tapeInfoPtr, char *pName, char *AFSName,
1810 struct butm_tapeLabel *tapeLabel)
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, NULL);
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)
1973 expiration = ExpirationDate(tapeLabelPtr->dumpid);
1975 expiration = tapeLabelPtr->expirationDate;
1977 gettimeofday(&tp, NULL);
1978 return ((expiration < tp.tv_sec) ? 1 : 0);
1982 * given the label on the tape, delete any old information from the
1985 * Deletes all entries that match the volset.dumpnode
1986 * and the dump path.
1990 updateTapeLabel(struct labelTapeIf *labelIfPtr,
1991 struct butm_tapeInfo *tapeInfoPtr,
1992 struct butm_tapeLabel *newLabelPtr)
1994 struct butm_tapeLabel oldLabel;
1995 afs_int32 i, code = 0;
1997 int tapeIsLabeled = 0;
1998 int interactiveFlag;
2001 interactiveFlag = autoQuery;
2002 taskId = labelIfPtr->taskId;
2005 if (interactiveFlag) {
2007 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2008 labelIfPtr->taskId, tapecount);
2012 interactiveFlag = 1;
2015 /* mount the tape */
2016 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2018 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2022 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2026 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2027 && (strcmp(oldLabel.pName, "") != 0)) {
2028 /* We are setting the AFS name, yet tape
2029 * has a permanent name (not allowed).
2031 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2036 if (!tapeExpired(&oldLabel)) {
2037 if (!queryoperator) {
2038 TLog(taskId, "This tape has not expired\n");
2041 if (Ask("This tape has not expired - proceed") == 0)
2045 /* Keep the permanent name */
2046 if (strcmp(newLabelPtr->pName, "") == 0) {
2047 strcpy(newLabelPtr->pName, oldLabel.pName);
2048 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2049 strcpy(newLabelPtr->pName, "");
2053 /* extract useful information from the old label */
2054 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2055 newLabelPtr->dumpid = 0;
2056 newLabelPtr->useCount = oldLabel.useCount + 1;
2059 /* now write the new label */
2060 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2062 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2063 "Can't label tape\n");
2070 unmountTape(taskId, tapeInfoPtr);
2073 /* delete obsolete information from the database */
2074 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2075 /* delete based on dump id */
2076 if (oldLabel.dumpid) {
2077 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2078 if (i && (i != BUDB_NOENT))
2079 ErrorLog(0, taskId, i, 0,
2080 "Warning: Can't delete old dump %u from database\n",
2086 unmountTape(taskId, tapeInfoPtr);
2091 * LWP created by the server stub. Labels the tape with name and size
2092 * specified by <label>
2096 Labeller(void *param)
2098 struct labelTapeIf *labelIfPtr = (struct labelTapeIf *)param;
2100 struct tc_tapeLabel *label = &labelIfPtr->label;
2102 struct butm_tapeLabel newTapeLabel;
2103 struct butm_tapeInfo tapeInfo;
2107 taskId = labelIfPtr->taskId;
2108 setStatus(taskId, DRIVE_WAIT);
2109 EnterDeviceQueue(deviceLatch);
2110 clearStatus(taskId, DRIVE_WAIT);
2113 TLog(taskId, "Labeltape\n");
2115 memset(&tapeInfo, 0, sizeof(tapeInfo));
2116 tapeInfo.structVersion = BUTM_MAJORVERSION;
2117 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2119 ErrorLog(0, taskId, code, tapeInfo.error,
2120 "Can't initialize the tape module\n");
2124 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2126 newTapeLabel.size = label->size;
2128 newTapeLabel.size = globalTapeConfig.capacity;
2130 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2135 if (code == TC_ABORTEDBYREQUEST) {
2136 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2137 clearStatus(taskId, ABORT_REQUEST);
2138 setStatus(taskId, ABORT_DONE);
2140 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2141 setStatus(taskId, TASK_ERROR);
2143 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2144 TNAME(&newTapeLabel), newTapeLabel.size);
2146 setStatus(labelIfPtr->taskId, TASK_DONE);
2149 LeaveDeviceQueue(deviceLatch);
2150 return (void *)(intptr_t)(code);
2154 * print out the tape label.
2158 PrintTapeLabel(struct butm_tapeLabel *labelptr)
2160 char tapeName[BU_MAXTAPELEN + 32];
2163 printf("Tape label\n");
2164 printf("----------\n");
2165 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2166 printf("permanent tape name = %s\n", tapeName);
2167 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2168 printf("AFS tape name = %s\n", tapeName);
2169 t = labelptr->creationTime;
2170 printf("creationTime = %s", ctime(&t));
2171 if (labelptr->expirationDate) {
2172 t = labelptr->expirationDate;
2173 printf("expirationDate = %s", cTIME(&t));
2175 printf("cell = %s\n", labelptr->cell);
2176 printf("size = %u Kbytes\n", labelptr->size);
2177 printf("dump path = %s\n", labelptr->dumpPath);
2179 if (labelptr->structVersion >= TAPE_VERSION_3) {
2180 printf("dump id = %u\n", labelptr->dumpid);
2181 printf("useCount = %d\n", labelptr->useCount);
2183 printf("-- End of tape label --\n\n");
2187 * Read the label from a tape.
2188 * Currently prints out a "detailed" summary of the label but passes
2189 * back only selected fields.
2193 ReadLabel(struct tc_tapeLabel *label)
2195 struct butm_tapeLabel newTapeLabel;
2196 struct butm_tapeInfo tapeInfo;
2200 int interactiveFlag;
2203 EnterDeviceQueue(deviceLatch);
2204 taskId = allocTaskId(); /* reqd for lower level rtns */
2207 TLog(taskId, "Readlabel\n");
2209 memset(&tapeInfo, 0, sizeof(tapeInfo));
2210 tapeInfo.structVersion = BUTM_MAJORVERSION;
2211 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2213 ErrorLog(0, taskId, code, tapeInfo.error,
2214 "Can't initialize the tape module\n");
2217 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2219 interactiveFlag = autoQuery;
2222 if (interactiveFlag) {
2223 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2227 interactiveFlag = 1;
2230 code = butm_Mount(&tapeInfo, "");
2232 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2238 unmountTape(taskId, &tapeInfo);
2241 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2243 if (code == BUTM_NOLABEL) {
2244 printf("Tape is unlabelled\n");
2247 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2251 /* copy the fields to be passed to the caller */
2252 label->size = newTapeLabel.size;
2253 label->tapeId = newTapeLabel.dumpid;
2254 strcpy(label->afsname, newTapeLabel.AFSName);
2255 strcpy(label->pname, newTapeLabel.pName);
2258 expir = ExpirationDate(newTapeLabel.dumpid);
2260 newTapeLabel.expirationDate = expir;
2262 PrintTapeLabel(&newTapeLabel);
2265 unmountTape(taskId, &tapeInfo);
2267 if (code == TC_ABORTEDBYREQUEST)
2268 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2269 else if (code && (code != BUTM_NOLABEL))
2270 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2272 TLog(taskId, "ReadLabel: Finished\n");
2274 LeaveDeviceQueue(deviceLatch);
2278 /* Function to read volume header and trailer structure from tape, taking
2279 into consideration, different word alignment rules.
2282 readVolumeHeader(char *buffer, /* in - buffer to read header from */
2283 afs_int32 bufloc, /* in - header's location in buffer */
2284 struct volumeHeader *header) /* out -header structure */
2286 struct volumeHeader vhptr, *tempvhptr;
2287 afs_int32 firstSplice = (afs_int32) ((char*)& vhptr.pad - (char*) & vhptr);
2288 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2289 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2291 /* Four cases are to be handled
2293 * Volume Header (byte alignment)
2294 * -----------------------
2301 * -----------------------
2303 * Case 2 and Case 3 are identical cases and handled the same way.
2304 * Case 1 and Case 4 are separate cases. In one case the pad needs
2305 * to be removed and in the other, it needs to be spliced in. The
2306 * four cases are handled as follows
2308 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2309 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2310 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2311 /* Handle Cases 2 & 3 */
2312 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2313 HEADER_CHECKS(vhptr, header);
2316 memset(&vhptr, 0, sizeof(struct volumeHeader));
2317 memcpy(&vhptr, buffer + bufloc, firstSplice);
2318 memset(&vhptr.pad, 0, padLen);
2319 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2320 HEADER_CHECKS(vhptr, header);
2323 memset(&vhptr, 0, sizeof(struct volumeHeader));
2324 memcpy(&vhptr, buffer + bufloc, firstSplice);
2325 /* probably GCC bug 37060; however, no guarantee on length of buffer */
2326 tempvhptr = (struct volumeHeader *)(buffer + firstSplice);
2327 memcpy(tempvhptr, buffer + bufloc + firstSplice + padLen,
2329 HEADER_CHECKS(vhptr, header);
2332 return (TC_BADVOLHEADER);