2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
13 #include <afs/procmgmt.h>
24 #include <afs/tcdata.h>
25 #include <afs/bubasics.h> /* PA */
26 #include <afs/budb_client.h>
27 #include <afs/bucoord_prototypes.h>
28 #include <afs/butm_prototypes.h>
29 #include <afs/volser.h>
30 #include <afs/volser_prototypes.h>
31 #include <afs/com_err.h>
32 #include <afs/afsutil.h>
34 #include "error_macros.h"
35 #include "butc_xbsa.h"
36 #include "butc_internal.h"
38 /* GLOBAL CONFIGURATION PARAMETERS */
39 extern int queryoperator;
40 extern int tapemounted;
41 extern char *opencallout;
42 extern char *closecallout;
44 extern char *extractDumpName(char *);
45 extern int BufferSize; /* Size in B stored for header info */
46 FILE *restoretofilefd;
48 extern char *restoretofile;
49 extern int forcemultiple;
52 /* XBSA Global Parameters */
55 struct butx_transactionInfo butxInfo;
58 static struct TapeBlock { /* A 16KB tapeblock */
59 char mark[BUTM_HDRSIZE]; /* Header info */
60 char data[BUTM_BLKSIZE]; /* data */
63 afs_int32 dataSize; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
64 afs_int32 tapeblocks; /* Number of tape datablocks in buffer (!CONF_XBSA) */
67 * Need to re-write to:
68 * 1) non-interactive tape handling (optional)
69 * 2) compute tape and volume sizes for the database
70 * 3) compute and use tape id's for tape tracking (put on tape label)
71 * 4) status management
74 /* All the relevant info shared between Restorer and restoreVolume */
75 struct restoreParams {
76 struct dumpNode *nodePtr;
78 char mntTapeName[BU_MAXTAPELEN];
80 struct butm_tapeInfo *tapeInfoPtr;
83 /* Abort checks are done after each BIGCHUNK of data transfer */
84 #define BIGCHUNK 102400
86 #define HEADER_CHECKS(vhptr, header) \
88 afs_int32 magic, versionflags; \
90 versionflags = ntohl(vhptr.versionflags); \
91 if ( versionflags == TAPE_VERSION_0 || \
92 versionflags == TAPE_VERSION_1 || \
93 versionflags == TAPE_VERSION_2 || \
94 versionflags == TAPE_VERSION_3 || \
95 versionflags == TAPE_VERSION_4 ) { \
97 magic = ntohl(vhptr.magic); /* another sanity check */ \
98 if (magic == TC_VOLBEGINMAGIC || \
99 magic == TC_VOLENDMAGIC || \
100 magic == TC_VOLCONTD ) { \
102 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
105 } /* versionflags */ \
109 extern FILE *ErrorlogIO;
110 extern FILE *centralLogIO;
111 extern FILE *lastLogIO;
112 extern afs_int32 lastPass; /* Set true during last pass of dump */
113 extern int debugLevel;
114 extern int autoQuery;
115 extern struct tapeConfig globalTapeConfig;
116 extern struct deviceSyncNode *deviceLatch;
117 extern char globalCellName[];
121 /* forward declaration */
122 afs_int32 readVolumeHeader(char *, afs_int32, struct volumeHeader *);
123 int FindVolTrailer(char *, afs_int32, afs_int32 *, struct volumeHeader *);
124 int FindVolTrailer2(char *, afs_int32, afs_int32 *, char *, afs_int32,
125 afs_int32 *, struct volumeHeader *);
126 int SkipVolume(struct tc_restoreDesc *, afs_int32, afs_int32, afs_int32,
131 /* The on-disk volume header or trailer can differ in size from platform to platform */
132 static struct TapeBlock tapeBlock;
133 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
136 PrintLogStr(FILE *log, afs_int32 error1, afs_int32 error2, char *str)
140 fprintf(log, "%s", str);
145 err1 = "Volume needs to be salvaged";
148 err1 = "Bad vnode number quoted";
151 err1 = "Volume not attached, does not exist, or not on line";
154 err1 = "Volume already exists";
157 err1 = "Volume is not in service";
160 err1 = "Volume is off line";
163 err1 = "Volume is already on line";
166 err1 = "Partition is full";
169 err1 = "Volume max quota exceeded";
172 err1 = "Volume temporarily unavailable";
175 err1 = "Volume has moved to another server";
178 err1 = (char *)afs_error_message(error1);
179 err2 = (char *)afs_error_table_name(error1);
183 fprintf(log, " Possible communication failure");
185 fprintf(log, " %s: %s", err2, err1);
187 fprintf(log, ": %s", afs_error_message(error2));
194 TapeLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
202 if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %T %Y",
203 localtime_r(&now, &tm)) != 0)
204 fprintf(logIO, "%s: ", tbuffer);
207 fprintf(logIO, "Task %u: ", task);
208 PrintLogStr(logIO, error1, error2, str);
210 if (lastPass && lastLogIO) {
211 fprintf(lastLogIO, "%s: ", tbuffer);
213 fprintf(lastLogIO, "Task %u: ", task);
214 PrintLogStr(lastLogIO, error1, error2, str);
217 /* Now print to the screen if debug level requires */
218 if (debug <= debugLevel)
219 PrintLogStr(stdout, error1, error2, str);
223 TapeLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
230 vsnprintf(tmp, sizeof(tmp), fmt, ap);
233 TapeLogStr(debug, task, error1, error2, tmp);
237 TLog(afs_int32 task, char *fmt, ...)
243 vsnprintf(tmp, sizeof(tmp), fmt, ap);
246 /* Sends message to TapeLog and stdout */
247 TapeLogStr(0, task, 0, 0, tmp);
251 ErrorLogStr(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
259 if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %T %Y",
260 localtime_r(&now, &tm)) != 0)
261 fprintf(ErrorlogIO, "%s: ", tbuffer);
263 /* Print the time and task number */
265 fprintf(ErrorlogIO, "Task %u: ", task);
267 PrintLogStr(ErrorlogIO, error1, error2, errStr);
268 TapeLogStr(debug, task, error1, error2, errStr);
272 ErrorLog(int debug, afs_int32 task, afs_int32 error1, afs_int32 error2,
279 vsnprintf(tmp, sizeof(tmp), fmt, ap);
282 ErrorLogStr(debug, task, error1, error2, tmp);
287 ELog(afs_int32 task, char *fmt, ...)
293 vsnprintf(tmp, sizeof(tmp), fmt, ap);
296 /* Sends message to ErrorLog, TapeLog and stdout */
297 ErrorLog(0, task, 0, 0, "%s", tmp);
300 /* first proc called by anybody who intends to use the device */
302 EnterDeviceQueue(struct deviceSyncNode *devLatch)
304 ObtainWriteLock(&(devLatch->lock));
305 devLatch->flags = TC_DEVICEINUSE;
308 /* last proc called by anybody finishing using the device */
310 LeaveDeviceQueue(struct deviceSyncNode *devLatch)
313 ReleaseWriteLock(&(devLatch->lock));
316 #define BELLTIME 60 /* 60 seconds before a bell rings */
317 #define BELLCHAR 7 /* ascii for bell */
323 * only external clients are in recoverDb.c. Was static. PA
333 w = LWP_WaitForKeystroke(0);
339 #endif /* AFS_NT40_ENV */
347 callOutRoutine(afs_int32 taskId, char *tapePath, int flag, char *name,
348 afs_uint32 dbDumpId, int tapecount)
364 callOut = opencallout;
367 strcpy(Sopcode, "restore");
370 strcpy(Sopcode, "appenddump");
373 strcpy(Sopcode, "dump");
376 strcpy(Sopcode, "labeltape");
378 case READLABELOPCODE:
379 strcpy(Sopcode, "readlabel");
382 strcpy(Sopcode, "scantape");
384 case RESTOREDBOPCODE:
385 strcpy(Sopcode, "restoredb");
388 strcpy(Sopcode, "savedb");
391 strcpy(Sopcode, "unmount");
392 callOut = closecallout;
395 strcpy(Sopcode, "unknown");
399 if (!callOut) /* no script to call */
402 strcpy(ScallOut, callOut);
403 CO_argv[0] = ScallOut;
405 strcpy(StapePath, tapePath);
406 CO_argv[1] = StapePath;
408 CO_argv[2] = Sopcode;
410 if (flag == CLOSEOPCODE) {
413 sprintf(Scount, "%d", tapecount);
416 /* The tape label name - special case labeltape */
417 if (!name || (strcmp(name, "") == 0)) /* no label */
418 strcpy(Stape, "none");
419 else { /* labeltape */
421 if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
422 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
431 strcpy(Sdumpid, "none");
433 sprintf(Sdumpid, "%u", dbDumpId);
434 CO_argv[5] = Sdumpid;
441 pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
443 ErrorLog(0, taskId, errno, 0,
444 "Call to %s outside routine %s failed\n", Sopcode, callOut);
453 * Unmounts a tape and prints a warning if it can't unmount it.
454 * Regardless of error, the closecallout routine will be called
455 * (unless a tape is not mounted in the first place).
458 unmountTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr)
461 int cpid, status, rcpid;
463 code = butm_Dismount(tapeInfoPtr);
464 if (code && (code != BUTM_NOMOUNT))
465 ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
466 "Warning: Can't close tape\n");
468 if (tapemounted && closecallout) {
469 setStatus(taskId, CALL_WAIT);
472 callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
474 while (cpid) { /* Wait until return */
476 rcpid = waitpid(cpid, &status, WNOHANG);
481 if (rcpid == -1 && errno != EINTR) {
483 afs_com_err(whoami, errno,
484 "Error waiting for callout script to terminate.");
487 #ifdef AFS_PTHREAD_ENV
493 if (checkAbortByTaskId(taskId)) {
494 TLog(taskId, "Callout routine has been aborted\n");
495 if (kill(cpid, SIGKILL)) /* Cancel callout */
496 ErrorLog(0, taskId, errno, 0,
497 "Kill of callout process %d failed\n", cpid);
502 clearStatus(taskId, CALL_WAIT);
506 * print out prompt to operator
508 * PromptForTape only.
512 PrintPrompt(int flag, char *name, int dumpid)
514 char tapename[BU_MAXTAPELEN + 32];
517 TAPENAME(tapename, name, dumpid);
519 printf("******* OPERATOR ATTENTION *******\n");
520 printf("Device : %s \n", globalTapeConfig.device);
523 case READOPCODE: /* mount for restore */
524 printf("Please put in tape %s for reading", tapename);
527 case APPENDOPCODE: /* mount for dump (appends) */
529 dn = extractDumpName(name);
532 printf("Please put in last tape of dump set for appending dump");
535 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
539 case WRITEOPCODE: /* mount for dump */
540 if (strcmp(name, "") == 0)
541 printf("Please put in tape for writing");
543 /* The name is what we are going to label the tape as */
545 printf("Please put in tape %s for writing", tapename);
548 case LABELOPCODE: /* mount for labeltape */
549 printf("Please put in tape to be labelled as %s", tapename);
552 case READLABELOPCODE: /* mount for readlabel */
553 printf("Please put in tape whose label is to be read");
556 case SCANOPCODE: /* mount for scantape */
557 if (strcmp(name, "") == 0)
558 printf("Please put in tape to be scanned");
560 printf("Please put in tape %s for scanning", tapename);
563 case RESTOREDBOPCODE: /* Mount for restoredb */
564 printf("Please insert a tape %s for the database restore", tapename);
567 case SAVEDBOPCODE: /* Mount for savedb */
568 printf("Please insert a writeable tape %s for the database dump",
575 printf(" and hit return when done\n");
579 * Prompt the operator to change the tape.
580 * Use to be a void routine but now returns an error. Some calls
581 * don't use the error code.
583 * only external clients are in recoverDb.c. Was static PA
586 PromptForTape(int flag, char *name, afs_uint32 dbDumpId, afs_uint32 taskId,
594 int cpid, status, rcpid;
596 if (checkAbortByTaskId(taskId))
597 ERROR_EXIT(TC_ABORTEDBYREQUEST);
600 TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
602 TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
604 CallOut = (opencallout ? 1 : 0);
606 setStatus(taskId, CALL_WAIT);
609 callOutRoutine(taskId, globalTapeConfig.device, flag, name,
610 dbDumpId, tapecount);
612 CallOut = 0; /* prompt at screen */
614 while (CallOut) { /* Check if callout routine finished */
616 rcpid = waitpid(cpid, &status, WNOHANG);
620 else if (WIFEXITED(status))
621 wcode = WEXITSTATUS(status);
626 break; /* All done */
627 } else if (wcode == 1) {
628 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort */
629 } else if ((flag == READOPCODE) && (wcode == 3)) {
630 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
633 "Callout routine has exited with code %d: will prompt\n",
635 CallOut = 0; /* Switch to keyboard input */
639 /* if waitpid experienced an error, we prompt */
640 if (rcpid == -1 && errno != EINTR) {
641 afs_com_err(whoami, errno,
642 "Error waiting for callout script to terminate.");
644 "Can't get exit status from callout script. will prompt\n");
648 #ifdef AFS_PTHREAD_ENV
654 if (checkAbortByTaskId(taskId)) {
656 ("This tape operation has been aborted by the coordinator.\n");
658 if (kill(cpid, SIGKILL)) /* Cancel callout */
659 ErrorLog(0, taskId, errno, 0,
660 "Kill of callout process %d failed\n", cpid);
662 ERROR_EXIT(TC_ABORTEDBYREQUEST);
668 clearStatus(taskId, CALL_WAIT);
669 setStatus(taskId, OPR_WAIT);
671 PrintPrompt(flag, name, dbDumpId);
673 /* Loop until we get ok to go ahead (or abort) */
675 if (time(0) > start + BELLTIME) {
681 wcode = LWP_GetResponseKey(5, &inchr); /* inchr stores key read */
682 if (wcode == 1) { /* keyboard input is available */
684 if ((inchr == 'a') || (inchr == 'A')) {
685 printf("This tape operation has been aborted.\n");
686 ERROR_EXIT(TC_ABORTEDBYREQUEST); /* Abort command */
687 } else if ((flag == READOPCODE)
688 && ((inchr == 's') || (inchr == 'S'))) {
689 printf("This tape will be skipped.\n");
690 ERROR_EXIT(TC_SKIPTAPE); /* Restore: skip the tape */
692 break; /* continue */
695 if (checkAbortByTaskId(taskId)) {
697 ("This tape operation has been aborted by the coordinator.\n");
698 ERROR_EXIT(TC_ABORTEDBYREQUEST);
704 printf("Thanks, now proceeding with tape ");
706 case RESTOREDBOPCODE:
712 printf("append writing");
724 case READLABELOPCODE:
725 printf("label reading");
737 printf(" operation.\n");
739 printf("**********************************\n");
741 TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
745 clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
751 * convert the fields in the tapeVolHeader into host byte order,
752 * placing the converted copy of the structure into the hostVolHeader
754 * tapeVolHeader - points to volume header read from tape
755 * hostVolHeader - pointer to struct for result
757 * hostVolHeader - information in host byte order
761 VolHeaderToHost(struct volumeHeader *hostVolHeader,
762 struct volumeHeader *tapeVolHeader)
764 switch (ntohl(tapeVolHeader->versionflags)) {
766 /* sizes in bytes and fields in host order */
767 memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
772 case TAPE_VERSION_3: /* for present */
774 /* sizes in K and fields in network order */
775 /* do the conversion field by field */
777 strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
778 strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
779 strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
780 strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
781 hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
782 hostVolHeader->server = ntohl(tapeVolHeader->server);
783 hostVolHeader->part = ntohl(tapeVolHeader->part);
784 hostVolHeader->from = ntohl(tapeVolHeader->from);
785 hostVolHeader->frag = ntohl(tapeVolHeader->frag);
786 hostVolHeader->magic = ntohl(tapeVolHeader->magic);
787 hostVolHeader->contd = ntohl(tapeVolHeader->contd);
788 hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
789 hostVolHeader->level = ntohl(tapeVolHeader->level);
790 hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
791 hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
792 hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
793 hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
797 return (TC_BADVOLHEADER);
803 ReadVolHeader(afs_int32 taskId,
804 struct butm_tapeInfo *tapeInfoPtr,
805 struct volumeHeader *volHeaderPtr)
809 struct volumeHeader volHead;
811 /* Read the volume header */
813 butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
816 ErrorLog(0, taskId, code, tapeInfoPtr->error,
817 "Can't read volume header on tape\n");
821 code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
823 ErrorLog(0, taskId, code, 0,
824 "Can't find volume header on tape block\n");
828 code = VolHeaderToHost(volHeaderPtr, &volHead);
830 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
839 GetVolumeHead(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
840 afs_int32 position, char *volName, afs_int32 volId)
843 struct volumeHeader tapeVolHeader;
845 /* Position directly to the volume and read the header */
847 code = butm_Seek(tapeInfoPtr, position);
849 ErrorLog(0, taskId, code, tapeInfoPtr->error,
850 "Can't seek to position %u on tape\n", position);
854 code = butm_ReadFileBegin(tapeInfoPtr);
856 ErrorLog(0, taskId, code, tapeInfoPtr->error,
857 "Can't read FileBegin on tape\n");
861 /* Read the volume header */
862 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
866 /* Check if volume header matches */
867 if (strcmp(tapeVolHeader.volumeName, volName))
868 ERROR_EXIT(TC_BADVOLHEADER);
869 if (volId && (tapeVolHeader.volumeID != volId))
870 ERROR_EXIT(TC_BADVOLHEADER);
871 if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
872 ERROR_EXIT(TC_BADVOLHEADER);
875 /* Do a sequential search for the volume */
878 code = butm_ReadFileBegin(tapeInfoPtr);
880 ErrorLog(0, taskId, code, tapeInfoPtr->error,
881 "Can't read FileBegin on tape\n");
885 code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
887 ERROR_EXIT(TC_VOLUMENOTONTAPE);
889 /* Test if we found the volume */
890 if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
891 && (!volId || (volId == tapeVolHeader.volumeID)))
894 /* skip to the next HW EOF marker */
895 code = SeekFile(tapeInfoPtr, 1);
897 ErrorLog(0, taskId, code, tapeInfoPtr->error,
898 "Can't seek to next EOF on tape\n");
909 GetRestoreTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr,
910 char *tname, afs_int32 tapeID, int prompt)
912 struct butm_tapeLabel tapeLabel;
913 afs_int32 code = 0, rc;
915 struct budb_dumpEntry dumpEntry;
917 /* Make sure that the dump/tape is not a XBSA dump */
918 rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
919 if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
920 ErrorLog(0, taskId, 0, 0,
921 "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
922 ERROR_EXIT(TC_SKIPTAPE);
928 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
935 code = butm_Mount(tapeInfoPtr, tname);
937 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
941 code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
943 ErrorLog(0, taskId, code, tapeInfoPtr->error,
944 "Can't read tape label\n");
948 /* Now check the label to see if the tapename matches or tapeids match */
949 if (strcmp(TNAME(&tapeLabel), tname)
950 || ((tapeLabel.structVersion >= TAPE_VERSION_3)
951 && (tapeLabel.dumpid != tapeID))) {
952 char expectedName[BU_MAXTAPELEN + 32],
953 gotName[BU_MAXTAPELEN + 32];
955 TAPENAME(expectedName, tname, tapeID);
956 LABELNAME(gotName, &tapeLabel);
958 TapeLog(0, taskId, 0, 0,
959 "Tape label expected %s, label seen %s\n", expectedName,
967 unmountTape(taskId, tapeInfoPtr);
975 xbsaRestoreVolumeData(struct rx_call *call, void *rock)
979 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
980 afs_int32 curChunk, rc;
981 afs_uint32 totalWritten;
982 afs_int32 headBytes, tailBytes, w;
984 struct volumeHeader volTrailer;
985 afs_int32 vtsize = 0;
987 struct dumpNode *nodePtr;
988 struct tc_restoreDesc *Restore;
989 afs_int32 bytesRead, tbuffersize, endData = 0;
990 char *buffer = (char *)bufferBlock, tbuffer[256];
992 nodePtr = rparamsPtr->nodePtr;
993 Restore = nodePtr->restores;
994 taskId = nodePtr->taskID;
996 /* Read the volume fragment one block at a time until
997 * find a volume trailer
999 curChunk = BIGCHUNK + 1;
1004 rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1006 if (restoretofile && (bytesRead > 0)) {
1007 fwrite(buffer, bytesRead, 1, restoretofilefd); /* Save to a file */
1009 if (rc != XBSA_SUCCESS) {
1010 ErrorLog(0, taskId, rc, 0,
1011 "Unable to read volume data from the server\n");
1015 /* Periodically update status structure and check if should abort */
1016 curChunk += bytesRead;
1017 if (curChunk > BIGCHUNK) {
1020 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1023 if (checkAbortByTaskId(taskId))
1024 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1027 if (!endData && (bytesRead > 0)) {
1028 /* Fill tbuffer up with data from end of buffer and write
1029 * the remainder of buffer out.
1031 if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1032 /* Write out contents of tbuffer */
1034 w = rx_Write(call, tbuffer, tbuffersize);
1035 if (w != tbuffersize) {
1036 ErrorLog(0, taskId, -1, 0,
1037 "Error in RX write: Wrote %d bytes\n", w);
1042 /* fill tbuffer with end of buffer */
1043 bytesRead -= sizeof(tbuffer);
1044 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1045 tbuffersize = sizeof(tbuffer);
1046 /* Write out whatever is left over in buffer */
1048 w = rx_Write(call, buffer, bytesRead);
1049 if (w != bytesRead) {
1050 ErrorLog(0, taskId, -1, 0,
1051 "Error in RX data write: Wrote %d bytes\n",
1058 } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1059 /* Copy all of buffer into tbuffer (it will fit) */
1060 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1061 tbuffersize += bytesRead;
1064 /* We need to write some of tbuffer out and fill it with buffer */
1065 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1066 w = rx_Write(call, tbuffer, towrite);
1068 ErrorLog(0, taskId, -1, 0,
1069 "Error in RX write: Wrote %d bytes\n", w);
1075 /* Move the data in tbuffer up */
1076 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1078 /* Now copy buffer in */
1079 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1080 tbuffersize += bytesRead;
1086 /* Pull the volume trailer from the last two buffers */
1088 FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1089 &tailBytes, &volTrailer);
1092 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1093 ERROR_EXIT(TC_MISSINGTRAILER);
1096 /* Now rx_write the data in the last two blocks */
1098 w = rx_Write(call, tbuffer, headBytes);
1099 if (w != headBytes) {
1100 ErrorLog(0, taskId, -1, 0,
1101 "Error in RX trail1 write: Wrote %d bytes\n", w);
1107 w = rx_Write(call, buffer, tailBytes);
1108 if (w != tailBytes) {
1109 ErrorLog(0, taskId, -1, 0,
1110 "Error in RX trail2 write: Wrote %d bytes\n", w);
1122 * sends the contents of volume dump to Rx Stream associated
1127 restoreVolumeData(struct rx_call *call, void *rock)
1129 struct restoreParams *rparamsPtr = (struct restoreParams *)rock;
1131 afs_uint32 totalWritten = 0;
1133 afs_int32 headBytes, tailBytes, w;
1135 afs_int32 nbytes; /* # bytes data in last tape block read */
1136 struct volumeHeader tapeVolTrailer;
1139 afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1140 struct tc_restoreDesc *Restore;
1141 struct dumpNode *nodePtr;
1142 struct butm_tapeInfo *tapeInfoPtr;
1144 afs_int32 origVolID;
1146 nodePtr = rparamsPtr->nodePtr;
1147 taskId = nodePtr->taskID;
1148 Restore = nodePtr->restores;
1149 tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1150 origVolName = Restore[rparamsPtr->frag].oldName;
1151 origVolID = Restore[rparamsPtr->frag].origVid;
1153 /* Read the volume one fragment at a time */
1154 while (rparamsPtr->frag < nodePtr->arraySize) {
1156 curChunk = BIGCHUNK + 1; /* Check if should abort */
1158 /* Read the volume fragment one block at a time until
1159 * find a volume trailer
1165 while (moretoread) {
1166 /* Fill the circular buffer with tape blocks
1167 * Search for volume trailer in the process.
1172 butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1173 BUTM_BLKSIZE, &nbytes);
1175 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1176 "Can't read FileData on tape %s\n",
1177 rparamsPtr->mntTapeName);
1180 curChunk += BUTM_BLKSIZE;
1182 /* Periodically update status structure and check if should abort */
1183 if (curChunk > BIGCHUNK) {
1187 nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1190 if (checkAbortByTaskId(taskId))
1191 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1194 /* step to next block in buffer */
1196 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1198 /* If this is the end of the volume, the exit the loop */
1199 if ((nbytes != BUTM_BLKSIZE)
1202 (bufferBlock[pbuf].data, nbytes, &tailBytes,
1206 } while (moretoread && (buf != endRbuf));
1208 /* Write the buffer upto (but not including) the last read block
1209 * If volume is completely read, then leave the last two blocks.
1211 lastbuf = endWbuf = pbuf;
1212 if (!moretoread && (endWbuf != startWbuf))
1213 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1215 for (buf = startWbuf; buf != endWbuf;
1216 buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1217 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1218 if (w != BUTM_BLKSIZE) {
1219 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1222 totalWritten += BUTM_BLKSIZE;
1225 /* Setup pointers to refill buffer */
1226 startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1228 startWbuf = endWbuf;
1231 /* lastbuf is last block read and it has nbytes of data
1232 * startWbuf is the 2nd to last block read
1233 * Seach for the volume trailer in these two blocks.
1235 if (lastbuf == startWbuf)
1237 FindVolTrailer2(NULL, 0, &headBytes,
1238 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1242 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1243 &headBytes, bufferBlock[lastbuf].data, nbytes,
1244 &tailBytes, &tapeVolTrailer);
1246 ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1247 "Missing volume trailer on tape %s\n",
1248 rparamsPtr->mntTapeName);
1249 ERROR_EXIT(TC_MISSINGTRAILER);
1252 /* Now rx_write the data in the last two blocks */
1254 w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1255 if (w != headBytes) {
1256 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1259 totalWritten += headBytes;
1262 w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1263 if (w != tailBytes) {
1264 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1267 totalWritten += tailBytes;
1270 /* Exit the loop if the volume is not continued on next tape */
1271 if (!tapeVolTrailer.contd)
1272 break; /* We've read the entire volume */
1274 /* Volume is continued on next tape.
1275 * Step to the next volume fragment and prompt for its tape.
1276 * When a volume has multiple frags, those frags are on different
1277 * tapes. So we know that we need to prompt for a tape.
1280 if (rparamsPtr->frag >= nodePtr->arraySize)
1283 unmountTape(taskId, tapeInfoPtr);
1284 strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1285 rparamsPtr->tapeID =
1286 (Restore[rparamsPtr->frag].
1287 initialDumpId ? Restore[rparamsPtr->frag].
1288 initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1290 GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1291 rparamsPtr->tapeID, 1);
1295 /* Position to the frag and read the volume header */
1297 GetVolumeHead(taskId, tapeInfoPtr,
1298 Restore[rparamsPtr->frag].position, origVolName,
1301 ErrorLog(0, taskId, code, 0,
1302 "Can't find volume %s (%u) on tape %s\n", origVolName,
1303 origVolID, rparamsPtr->mntTapeName);
1304 ERROR_EXIT(TC_VOLUMENOTONTAPE);
1313 * Find all the volumes on a specific tape and mark them to skip.
1316 SkipTape(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1317 char *tapename, afs_int32 tapeid, afs_int32 taskid)
1321 for (i = index; i < size; i++) {
1322 if (Restore[i].flags & RDFLAG_SKIP)
1325 (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1327 if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1328 SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1335 * Find all the entries for a volume and mark them to skip.
1338 SkipVolume(struct tc_restoreDesc *Restore, afs_int32 size, afs_int32 index,
1339 afs_int32 volid, afs_int32 taskid)
1344 for (i = index; i < size; i++) {
1345 if (Restore[i].flags & RDFLAG_SKIP)
1347 if (Restore[i].origVid == volid) {
1348 Restore[i].flags |= RDFLAG_SKIP;
1350 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1351 ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1352 Restore[i].oldName, volid);
1361 xbsaRestoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1362 struct restoreParams *rparamsPtr)
1367 afs_int32 newServer, newPart, newVolId;
1369 int restoreflags, havetrans = 0, startread = 0;
1370 afs_int32 bytesRead, endData = 0;
1372 struct budb_dumpEntry dumpEntry;
1373 char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1374 struct volumeHeader volHeader, hostVolHeader;
1376 if (restoretofile) {
1377 restoretofilefd = fopen(restoretofile, "w+");
1380 dumpID = restoreInfo->dbDumpId;
1382 rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1384 ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1389 /* ADSM servers restore ADSM and BUTA dumps */
1390 if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1391 && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1393 "The dump requested by this restore operation for the "
1394 "volumeset is incompatible with this instance of butc\n");
1395 /* Skip the entire dump (one dump per tape) */
1396 ERROR_EXIT(TC_SKIPTAPE);
1399 /* make sure we are connected to the correct server. */
1400 if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1401 && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1403 if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1404 && !forcemultiple) {
1406 "Dump %d is on server %s but butc is connected "
1407 "to server %s (attempting to restore)\n", dumpID,
1408 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1411 "Dump %d is on server %s but butc is connected "
1412 "to server %s (switching servers)\n", dumpID,
1413 (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1415 rc = InitToServer(taskId, &butxInfo,
1416 (char *)dumpEntry.tapes.tapeServer);
1417 if (rc != XBSA_SUCCESS)
1418 ERROR_EXIT(TC_SKIPTAPE);
1422 /* Start a transaction and query the server for the correct fileset dump */
1423 rc = xbsa_BeginTrans(&butxInfo);
1424 if (rc != XBSA_SUCCESS) {
1425 ELog(taskId, "Unable to create a new transaction\n");
1426 ERROR_EXIT(TC_SKIPTAPE);
1430 if (dumpEntry.flags & BUDB_DUMP_BUTA) { /* old buta style names */
1431 sprintf(dumpIdStr, "/%d", dumpID);
1432 strcpy(volumeNameStr, "/");
1433 strcat(volumeNameStr, restoreInfo->oldName);
1434 } else { /* new butc names */
1435 extern char *butcdumpIdStr;
1436 strcpy(dumpIdStr, butcdumpIdStr);
1437 sprintf(volumeNameStr, "/%d", dumpID);
1438 strcat(volumeNameStr, "/");
1439 strcat(volumeNameStr, restoreInfo->oldName);
1442 rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1443 if (rc != XBSA_SUCCESS) {
1445 "Unable to locate object (%s) of dump (%s) on the server\n",
1446 volumeNameStr, dumpIdStr);
1450 rc = xbsa_EndTrans(&butxInfo);
1452 if (rc != XBSA_SUCCESS) {
1453 ELog(taskId, "Unable to terminate the current transaction\n");
1457 if (checkAbortByTaskId(taskId))
1458 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1460 /* Now start a transaction on the volume to restore and read the
1461 * volumeheader. We do this before starting a transaction on
1462 * volserver to restore the volume because the XBSA server may take
1463 * a while to mount and seek to the volume causing the volserver to
1466 rc = xbsa_BeginTrans(&butxInfo);
1467 if (rc != XBSA_SUCCESS) {
1468 ELog(taskId, "Unable to create a new transaction\n");
1469 ERROR_EXIT(TC_SKIPTAPE);
1473 rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1474 sizeof(volHeader), &bytesRead, &endData);
1475 if (restoretofile && (bytesRead > 0)) {
1476 fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd); /* Save to a file */
1478 if (rc != XBSA_SUCCESS) {
1480 "Unable to begin reading of the volume from the server\n");
1485 if ((bytesRead != sizeof(volHeader)) || endData) {
1487 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1488 bytesRead, sizeof(volHeader));
1489 ERROR_EXIT(TC_BADVOLHEADER);
1492 /* convert and check the volume header */
1493 rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1495 ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1499 if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1500 || (restoreInfo->origVid
1501 && (hostVolHeader.volumeID != restoreInfo->origVid))
1502 || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1503 ERROR_EXIT(TC_BADVOLHEADER);
1505 /* Set up prior restoring volume data */
1506 newVolName = restoreInfo->newName;
1507 newVolId = restoreInfo->vid;
1508 newServer = restoreInfo->hostAddr;
1509 newPart = restoreInfo->partition;
1511 if ((restoreInfo->dumpLevel == 0)
1512 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1513 restoreflags |= RV_FULLRST;
1514 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1515 restoreflags |= RV_OFFLINE;
1517 if (checkAbortByTaskId(taskId))
1518 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1520 /* Start the restore of the volume data. This is the code we want to return */
1522 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1523 restoreflags, xbsaRestoreVolumeData,
1524 (char *)rparamsPtr);
1527 rc = xbsa_ReadObjectEnd(&butxInfo);
1528 if (rc != XBSA_SUCCESS) {
1530 "Unable to terminate reading of the volume from the server\n");
1536 rc = xbsa_EndTrans(&butxInfo);
1537 if (rc != XBSA_SUCCESS) {
1538 ELog(taskId, "Unable to terminate the current transaction\n");
1544 if (restoretofile && restoretofilefd) {
1545 fclose(restoretofilefd);
1552 restoreVolume(afs_uint32 taskId, struct tc_restoreDesc *restoreInfo,
1553 struct restoreParams *rparamsPtr)
1555 afs_int32 code = 0, rc;
1556 afs_int32 newServer, newPart, newVolId;
1560 struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1562 /* Check if we need a tape and prompt for one if so */
1564 (restoreInfo->initialDumpId ? restoreInfo->
1565 initialDumpId : restoreInfo->dbDumpId);
1566 if ((rparamsPtr->frag == 0)
1567 || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1568 || (tapeID != rparamsPtr->tapeID)) {
1569 /* Unmount the previous tape */
1570 unmountTape(taskId, tapeInfoPtr);
1572 /* Remember this new tape */
1573 strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1574 rparamsPtr->tapeID = tapeID;
1576 /* Mount a new tape */
1577 rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1579 ((rparamsPtr->frag == 0) ? autoQuery : 1));
1584 /* Seek to the correct spot and read the header information */
1585 rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1586 restoreInfo->oldName, restoreInfo->origVid);
1590 /* Set up prior restoring volume data */
1591 newVolName = restoreInfo->newName;
1592 newVolId = restoreInfo->vid;
1593 newServer = restoreInfo->hostAddr;
1594 newPart = restoreInfo->partition;
1596 if ((restoreInfo->dumpLevel == 0)
1597 || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1598 restoreflags |= RV_FULLRST;
1599 if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1600 restoreflags |= RV_OFFLINE;
1602 if (checkAbortByTaskId(taskId))
1603 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1605 /* Start the restore of the volume data. This is the code we
1609 UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1610 restoreflags, restoreVolumeData, (char *)rparamsPtr);
1612 /* Read the FileEnd marker for the volume and step to next FM */
1613 rc = butm_ReadFileEnd(tapeInfoPtr);
1615 ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1616 "Can't read EOF on tape\n");
1624 * created as a LWP by the server stub, <newNode> is a pointer to all
1625 * the parameters Restorer needs
1628 Restorer(void *param) {
1629 struct dumpNode *newNode = (struct dumpNode *) param;
1631 afs_int32 code = 0, tcode;
1634 struct butm_tapeInfo tapeInfo;
1635 struct tc_restoreDesc *Restore;
1636 struct tc_restoreDesc *RestoreDesc;
1637 struct restoreParams rparams;
1638 afs_int32 allocbufferSize;
1639 time_t startTime, endTime;
1640 afs_int32 goodrestore = 0;
1642 taskId = newNode->taskID;
1643 setStatus(taskId, DRIVE_WAIT);
1644 EnterDeviceQueue(deviceLatch);
1645 clearStatus(taskId, DRIVE_WAIT);
1648 TLog(taskId, "Restore\n");
1650 memset(&tapeInfo, 0, sizeof(tapeInfo));
1652 tapeInfo.structVersion = BUTM_MAJORVERSION;
1653 tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1655 ErrorLog(0, taskId, tcode, tapeInfo.error,
1656 "Can't initialize the tape module\n");
1661 if (checkAbortByTaskId(taskId))
1662 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1664 memset(&rparams, 0, sizeof(rparams));
1665 rparams.nodePtr = newNode;
1666 rparams.tapeInfoPtr = &tapeInfo;
1667 Restore = newNode->restores; /* Array of vol fragments to restore */
1669 /* Allocate memory in which to restore the volumes data into */
1671 allocbufferSize = dataSize = BufferSize;
1673 /* Must have at least two tape blocks */
1674 tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1677 allocbufferSize = tapeblocks * BUTM_BLOCKSIZE; /* This many full tapeblocks */
1680 bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1682 ERROR_EXIT(TC_NOMEMORY);
1683 memset(bufferBlock, 0, allocbufferSize);
1685 startTime = time(0);
1686 for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1688 RestoreDesc = &Restore[rparams.frag];
1690 /* Skip the volume if it was requested to */
1691 if (RestoreDesc->flags & RDFLAG_SKIP) {
1692 if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1693 /* If the volume was restored, should bring it online */
1698 newVolName = RestoreDesc->newName;
1700 /* Make sure the server to restore to is good */
1701 if (!RestoreDesc->hostAddr) {
1702 ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1704 ERROR_EXIT(TC_INTERNALERROR);
1707 if (checkAbortByTaskId(taskId))
1708 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1710 TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1712 strncpy(newNode->statusNodePtr->volumeName, newVolName,
1716 /* restoreVolume function takes care of all the related fragments
1717 * spanning various tapes. On return the complete volume has been
1721 tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1723 tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1726 if (tcode == TC_ABORTEDBYREQUEST) {
1728 } else if (tcode == TC_SKIPTAPE) {
1731 (RestoreDesc->initialDumpId ? RestoreDesc->
1732 initialDumpId : RestoreDesc->dbDumpId);
1733 SkipTape(Restore, newNode->arraySize, rparams.frag,
1734 RestoreDesc->tapeName, tapeID, taskId);
1736 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1738 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1739 RestoreDesc->origVid, taskId);
1751 unmountTape(taskId, &tapeInfo);
1754 code = InitToServer(taskId, &butxInfo, 0); /* Return to original server */
1761 if (code == TC_ABORTEDBYREQUEST) {
1762 ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1763 clearStatus(taskId, ABORT_REQUEST);
1764 setStatus(taskId, ABORT_DONE);
1766 TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1767 setStatus(taskId, TASK_ERROR);
1769 TLog(taskId, "Restore: Finished\n");
1772 if (centralLogIO && startTime) {
1774 afs_int32 hrs, min, sec, tmp;
1776 struct tm tmstart, tmend;
1778 localtime_r(&startTime, &tmstart);
1779 localtime_r(&endTime, &tmend);
1780 timediff = (int)endTime - (int)startTime;
1781 hrs = timediff / 3600;
1782 tmp = timediff % 3600;
1787 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1788 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1789 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1790 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1791 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1792 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1793 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1794 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1796 fwrite(line, strlen(line), 1, centralLogIO);
1797 fflush(centralLogIO);
1800 setStatus(taskId, TASK_DONE);
1803 LeaveDeviceQueue(deviceLatch);
1804 return (void *)(intptr_t)(code);
1807 /* this is just scaffolding, creates new tape label with name <tapeName> */
1810 GetNewLabel(struct butm_tapeInfo *tapeInfoPtr, char *pName, char *AFSName,
1811 struct butm_tapeLabel *tapeLabel)
1814 struct timezone tzp;
1817 memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1820 butm_GetSize(tapeInfoPtr, &size);
1822 size = globalTapeConfig.capacity;
1824 size = 0; /* no tape size */
1826 gettimeofday(&tp, &tzp);
1828 tapeLabel->structVersion = CUR_TAPE_VERSION;
1829 tapeLabel->creationTime = tp.tv_sec;
1830 tapeLabel->size = size;
1831 tapeLabel->expirationDate = 0; /* 1970 sometime */
1832 tapeLabel->dumpPath[0] = 0; /* no path name */
1833 tapeLabel->useCount = 0;
1834 strcpy(tapeLabel->AFSName, AFSName);
1835 strcpy(tapeLabel->pName, pName);
1836 strcpy(tapeLabel->cell, globalCellName);
1837 strcpy(tapeLabel->comment, "AFS Backup Software");
1838 strcpy(tapeLabel->creator.name, "AFS 3.6");
1839 strcpy(tapeLabel->creator.instance, "");
1840 strcpy(tapeLabel->creator.cell, globalCellName);
1843 /* extracts trailer out of buffer, nbytes is set to total data in
1844 * buffer - trailer size */
1846 ExtractTrailer(char *buffer, afs_int32 size, afs_int32 *nbytes,
1847 struct volumeHeader *volTrailerPtr)
1851 struct volumeHeader tempTrailer;
1855 (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1857 code = readVolumeHeader(buffer, startPos, &tempTrailer);
1859 code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1865 return 1; /* saw the trailer */
1871 return 0; /* did not see the trailer */
1875 FindVolTrailer(char *buffer, afs_int32 size, afs_int32 *dSize,
1876 struct volumeHeader *volTrailerPtr)
1878 afs_int32 offset, s;
1885 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1889 found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
1891 *dSize -= (s - offset);
1896 FindVolTrailer2(char *buffera, afs_int32 sizea, afs_int32 *dataSizea,
1897 char *bufferb, afs_int32 sizeb, afs_int32 *dataSizeb,
1898 struct volumeHeader *volTrailerPtr)
1900 afs_int32 offset, s;
1901 afs_int32 headB, tailB;
1911 s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
1913 found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
1916 headB = (s - sizeb); /*(s > sizeb) */
1917 if (headB > sizea) {
1924 memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
1926 memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
1928 memcpy(tapeVolumeHT + headB, bufferb, tailB);
1929 if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
1931 if (offset > headB) {
1932 /* *dataSizea remains unchanged */
1933 *dataSizeb = offset - headB;
1935 *dataSizea -= (headB - offset); /*(headB >= offset) */
1945 ExpirationDate(afs_int32 dumpid)
1948 Date expiration = 0;
1949 struct budb_dumpEntry dumpEntry;
1950 struct budb_tapeEntry tapeEntry;
1951 struct budb_volumeEntry volEntry;
1955 * Get the expiration date from DB if its there. The expiration of
1956 * any tape will be the most future expiration of any dump in the
1957 * set. Can't use bcdb_FindTape because dumpid here pertains to the
1960 code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
1962 expiration = tapeEntry.expires;
1964 return (expiration);
1967 /* Returns true or false depending on whether the tape is expired or not */
1970 tapeExpired(struct butm_tapeLabel *tapeLabelPtr)
1974 struct timezone tzp;
1976 expiration = ExpirationDate(tapeLabelPtr->dumpid);
1978 expiration = tapeLabelPtr->expirationDate;
1980 gettimeofday(&tp, &tzp);
1981 return ((expiration < tp.tv_sec) ? 1 : 0);
1985 * given the label on the tape, delete any old information from the
1988 * Deletes all entries that match the volset.dumpnode
1989 * and the dump path.
1993 updateTapeLabel(struct labelTapeIf *labelIfPtr,
1994 struct butm_tapeInfo *tapeInfoPtr,
1995 struct butm_tapeLabel *newLabelPtr)
1997 struct butm_tapeLabel oldLabel;
1998 afs_int32 i, code = 0;
2000 int tapeIsLabeled = 0;
2001 int interactiveFlag;
2004 interactiveFlag = autoQuery;
2005 taskId = labelIfPtr->taskId;
2008 if (interactiveFlag) {
2010 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2011 labelIfPtr->taskId, tapecount);
2015 interactiveFlag = 1;
2018 /* mount the tape */
2019 code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2021 TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2025 code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1); /* will rewind the tape */
2029 if ((strcmp(newLabelPtr->AFSName, "") != 0)
2030 && (strcmp(oldLabel.pName, "") != 0)) {
2031 /* We are setting the AFS name, yet tape
2032 * has a permanent name (not allowed).
2034 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2039 if (!tapeExpired(&oldLabel)) {
2040 if (!queryoperator) {
2041 TLog(taskId, "This tape has not expired\n");
2044 if (Ask("This tape has not expired - proceed") == 0)
2048 /* Keep the permanent name */
2049 if (strcmp(newLabelPtr->pName, "") == 0) {
2050 strcpy(newLabelPtr->pName, oldLabel.pName);
2051 } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2052 strcpy(newLabelPtr->pName, "");
2056 /* extract useful information from the old label */
2057 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2058 newLabelPtr->dumpid = 0;
2059 newLabelPtr->useCount = oldLabel.useCount + 1;
2062 /* now write the new label */
2063 code = butm_Create(tapeInfoPtr, newLabelPtr, 1); /* will rewind the tape */
2065 ErrorLog(0, taskId, code, tapeInfoPtr->error,
2066 "Can't label tape\n");
2073 unmountTape(taskId, tapeInfoPtr);
2076 /* delete obsolete information from the database */
2077 if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2078 /* delete based on dump id */
2079 if (oldLabel.dumpid) {
2080 i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2081 if (i && (i != BUDB_NOENT))
2082 ErrorLog(0, taskId, i, 0,
2083 "Warning: Can't delete old dump %u from database\n",
2089 unmountTape(taskId, tapeInfoPtr);
2094 * LWP created by the server stub. Labels the tape with name and size
2095 * specified by <label>
2099 Labeller(void *param)
2101 struct labelTapeIf *labelIfPtr = (struct labelTapeIf *)param;
2103 struct tc_tapeLabel *label = &labelIfPtr->label;
2105 struct butm_tapeLabel newTapeLabel;
2106 struct butm_tapeInfo tapeInfo;
2110 taskId = labelIfPtr->taskId;
2111 setStatus(taskId, DRIVE_WAIT);
2112 EnterDeviceQueue(deviceLatch);
2113 clearStatus(taskId, DRIVE_WAIT);
2116 TLog(taskId, "Labeltape\n");
2118 memset(&tapeInfo, 0, sizeof(tapeInfo));
2119 tapeInfo.structVersion = BUTM_MAJORVERSION;
2120 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2122 ErrorLog(0, taskId, code, tapeInfo.error,
2123 "Can't initialize the tape module\n");
2127 GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2129 newTapeLabel.size = label->size;
2131 newTapeLabel.size = globalTapeConfig.capacity;
2133 code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2138 if (code == TC_ABORTEDBYREQUEST) {
2139 ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2140 clearStatus(taskId, ABORT_REQUEST);
2141 setStatus(taskId, ABORT_DONE);
2143 ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2144 setStatus(taskId, TASK_ERROR);
2146 TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2147 TNAME(&newTapeLabel), newTapeLabel.size);
2149 setStatus(labelIfPtr->taskId, TASK_DONE);
2152 LeaveDeviceQueue(deviceLatch);
2153 return (void *)(intptr_t)(code);
2157 * print out the tape label.
2161 PrintTapeLabel(struct butm_tapeLabel *labelptr)
2163 char tapeName[BU_MAXTAPELEN + 32];
2166 printf("Tape label\n");
2167 printf("----------\n");
2168 TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2169 printf("permanent tape name = %s\n", tapeName);
2170 TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2171 printf("AFS tape name = %s\n", tapeName);
2172 t = labelptr->creationTime;
2173 printf("creationTime = %s", ctime(&t));
2174 if (labelptr->expirationDate) {
2175 t = labelptr->expirationDate;
2176 printf("expirationDate = %s", cTIME(&t));
2178 printf("cell = %s\n", labelptr->cell);
2179 printf("size = %u Kbytes\n", labelptr->size);
2180 printf("dump path = %s\n", labelptr->dumpPath);
2182 if (labelptr->structVersion >= TAPE_VERSION_3) {
2183 printf("dump id = %u\n", labelptr->dumpid);
2184 printf("useCount = %d\n", labelptr->useCount);
2186 printf("-- End of tape label --\n\n");
2190 * Read the label from a tape.
2191 * Currently prints out a "detailed" summary of the label but passes
2192 * back only selected fields.
2196 ReadLabel(struct tc_tapeLabel *label)
2198 struct butm_tapeLabel newTapeLabel;
2199 struct butm_tapeInfo tapeInfo;
2203 int interactiveFlag;
2206 EnterDeviceQueue(deviceLatch);
2207 taskId = allocTaskId(); /* reqd for lower level rtns */
2210 TLog(taskId, "Readlabel\n");
2212 memset(&tapeInfo, 0, sizeof(tapeInfo));
2213 tapeInfo.structVersion = BUTM_MAJORVERSION;
2214 code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2216 ErrorLog(0, taskId, code, tapeInfo.error,
2217 "Can't initialize the tape module\n");
2220 memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2222 interactiveFlag = autoQuery;
2225 if (interactiveFlag) {
2226 code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2230 interactiveFlag = 1;
2233 code = butm_Mount(&tapeInfo, "");
2235 TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2241 unmountTape(taskId, &tapeInfo);
2244 code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2246 if (code == BUTM_NOLABEL) {
2247 printf("Tape is unlabelled\n");
2250 ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2254 /* copy the fields to be passed to the caller */
2255 label->size = newTapeLabel.size;
2256 label->tapeId = newTapeLabel.dumpid;
2257 strcpy(label->afsname, newTapeLabel.AFSName);
2258 strcpy(label->pname, newTapeLabel.pName);
2261 expir = ExpirationDate(newTapeLabel.dumpid);
2263 newTapeLabel.expirationDate = expir;
2265 PrintTapeLabel(&newTapeLabel);
2268 unmountTape(taskId, &tapeInfo);
2270 if (code == TC_ABORTEDBYREQUEST)
2271 ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2272 else if (code && (code != BUTM_NOLABEL))
2273 ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2275 TLog(taskId, "ReadLabel: Finished\n");
2277 LeaveDeviceQueue(deviceLatch);
2281 /* Function to read volume header and trailer structure from tape, taking
2282 into consideration, different word alignment rules.
2285 readVolumeHeader(char *buffer, /* in - buffer to read header from */
2286 afs_int32 bufloc, /* in - header's location in buffer */
2287 struct volumeHeader *header) /* out -header structure */
2289 struct volumeHeader vhptr, *tempvhptr;
2290 afs_int32 firstSplice = (afs_int32) ((char*)& vhptr.pad - (char*) & vhptr);
2291 int padLen = sizeof(vhptr.pad); /* pad to achieve 4 byte alignment */
2292 int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2294 /* Four cases are to be handled
2296 * Volume Header (byte alignment)
2297 * -----------------------
2304 * -----------------------
2306 * Case 2 and Case 3 are identical cases and handled the same way.
2307 * Case 1 and Case 4 are separate cases. In one case the pad needs
2308 * to be removed and in the other, it needs to be spliced in. The
2309 * four cases are handled as follows
2311 tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2312 if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2313 && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2314 /* Handle Cases 2 & 3 */
2315 memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2316 HEADER_CHECKS(vhptr, header);
2319 memset(&vhptr, 0, sizeof(struct volumeHeader));
2320 memcpy(&vhptr, buffer + bufloc, firstSplice);
2321 memset(&vhptr.pad, 0, padLen);
2322 memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2323 HEADER_CHECKS(vhptr, header);
2326 memset(&vhptr, 0, sizeof(struct volumeHeader));
2327 memcpy(&vhptr, buffer + bufloc, firstSplice);
2328 /* probably GCC bug 37060; however, no guarantee on length of buffer */
2329 tempvhptr = (struct volumeHeader *)(buffer + firstSplice);
2330 memcpy(tempvhptr, buffer + bufloc + firstSplice + padLen,
2332 HEADER_CHECKS(vhptr, header);
2335 return (TC_BADVOLHEADER);