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/afsint.h>
30 #include <afs/volser.h>
31 #include <afs/volser_prototypes.h>
32 #include <afs/com_err.h>
33 #include <afs/afsutil.h>
35 #include "error_macros.h"
36 #include "butc_xbsa.h"
37 #include "butc_internal.h"
39 /* GLOBAL CONFIGURATION PARAMETERS */
40 extern int queryoperator
;
41 extern int tapemounted
;
42 extern char *opencallout
;
43 extern char *closecallout
;
45 extern char *extractDumpName(char *);
46 extern int BufferSize
; /* Size in B stored for header info */
47 FILE *restoretofilefd
;
49 extern char *restoretofile
;
50 extern int forcemultiple
;
53 /* XBSA Global Parameters */
56 struct butx_transactionInfo butxInfo
;
59 static struct TapeBlock
{ /* A 16KB tapeblock */
60 char mark
[BUTM_HDRSIZE
]; /* Header info */
61 char data
[BUTM_BLKSIZE
]; /* data */
64 afs_int32 dataSize
; /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
65 afs_int32 tapeblocks
; /* Number of tape datablocks in buffer (!CONF_XBSA) */
68 * Need to re-write to:
69 * 1) non-interactive tape handling (optional)
70 * 2) compute tape and volume sizes for the database
71 * 3) compute and use tape id's for tape tracking (put on tape label)
72 * 4) status management
75 /* All the relevant info shared between Restorer and restoreVolume */
76 struct restoreParams
{
77 struct dumpNode
*nodePtr
;
79 char mntTapeName
[BU_MAXTAPELEN
];
81 struct butm_tapeInfo
*tapeInfoPtr
;
84 /* Abort checks are done after each BIGCHUNK of data transfer */
85 #define BIGCHUNK 102400
87 #define HEADER_CHECKS(vhptr, header) \
89 afs_int32 magic, versionflags; \
91 versionflags = ntohl(vhptr.versionflags); \
92 if ( versionflags == TAPE_VERSION_0 || \
93 versionflags == TAPE_VERSION_1 || \
94 versionflags == TAPE_VERSION_2 || \
95 versionflags == TAPE_VERSION_3 || \
96 versionflags == TAPE_VERSION_4 ) { \
98 magic = ntohl(vhptr.magic); /* another sanity check */ \
99 if (magic == TC_VOLBEGINMAGIC || \
100 magic == TC_VOLENDMAGIC || \
101 magic == TC_VOLCONTD ) { \
103 memcpy(header, &vhptr, sizeof(struct volumeHeader)); \
106 } /* versionflags */ \
110 extern FILE *ErrorlogIO
;
111 extern FILE *centralLogIO
;
112 extern FILE *lastLogIO
;
113 extern afs_int32 lastPass
; /* Set true during last pass of dump */
114 extern int debugLevel
;
115 extern int autoQuery
;
116 extern struct tapeConfig globalTapeConfig
;
117 extern struct deviceSyncNode
*deviceLatch
;
118 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 %H:%M:%S %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 %H:%M:%S %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 writable 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
;
986 struct dumpNode
*nodePtr
;
987 afs_int32 bytesRead
, tbuffersize
, endData
= 0;
988 char *buffer
= (char *)bufferBlock
, tbuffer
[256];
990 nodePtr
= rparamsPtr
->nodePtr
;
991 taskId
= nodePtr
->taskID
;
993 /* Read the volume fragment one block at a time until
994 * find a volume trailer
996 curChunk
= BIGCHUNK
+ 1;
1001 rc
= xbsa_ReadObjectData(&butxInfo
, buffer
, dataSize
, &bytesRead
,
1003 if (restoretofile
&& (bytesRead
> 0)) {
1004 fwrite(buffer
, bytesRead
, 1, restoretofilefd
); /* Save to a file */
1006 if (rc
!= XBSA_SUCCESS
) {
1007 ErrorLog(0, taskId
, rc
, 0,
1008 "Unable to read volume data from the server\n");
1012 /* Periodically update status structure and check if should abort */
1013 curChunk
+= bytesRead
;
1014 if (curChunk
> BIGCHUNK
) {
1017 nodePtr
->statusNodePtr
->nKBytes
= totalWritten
/ 1024;
1020 if (checkAbortByTaskId(taskId
))
1021 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1024 if (!endData
&& (bytesRead
> 0)) {
1025 /* Fill tbuffer up with data from end of buffer and write
1026 * the remainder of buffer out.
1028 if ((tbuffersize
== 0) || (bytesRead
>= sizeof(tbuffer
))) {
1029 /* Write out contents of tbuffer */
1031 w
= rx_Write(call
, tbuffer
, tbuffersize
);
1032 if (w
!= tbuffersize
) {
1033 ErrorLog(0, taskId
, -1, 0,
1034 "Error in RX write: Wrote %d bytes\n", w
);
1039 /* fill tbuffer with end of buffer */
1040 bytesRead
-= sizeof(tbuffer
);
1041 memcpy(tbuffer
, buffer
+ bytesRead
, sizeof(tbuffer
));
1042 tbuffersize
= sizeof(tbuffer
);
1043 /* Write out whatever is left over in buffer */
1045 w
= rx_Write(call
, buffer
, bytesRead
);
1046 if (w
!= bytesRead
) {
1047 ErrorLog(0, taskId
, -1, 0,
1048 "Error in RX data write: Wrote %d bytes\n",
1055 } else if ((tbuffersize
+ bytesRead
) <= sizeof(tbuffer
)) {
1056 /* Copy all of buffer into tbuffer (it will fit) */
1057 memcpy(tbuffer
+ tbuffersize
, buffer
, bytesRead
);
1058 tbuffersize
+= bytesRead
;
1061 /* We need to write some of tbuffer out and fill it with buffer */
1062 int towrite
= bytesRead
- (sizeof(tbuffer
) - tbuffersize
);
1063 w
= rx_Write(call
, tbuffer
, towrite
);
1065 ErrorLog(0, taskId
, -1, 0,
1066 "Error in RX write: Wrote %d bytes\n", w
);
1072 /* Move the data in tbuffer up */
1073 memcpy(tbuffer
, tbuffer
+ towrite
, tbuffersize
);
1075 /* Now copy buffer in */
1076 memcpy(tbuffer
+ tbuffersize
, buffer
, bytesRead
);
1077 tbuffersize
+= bytesRead
;
1083 /* Pull the volume trailer from the last two buffers */
1085 FindVolTrailer2(tbuffer
, tbuffersize
, &headBytes
, buffer
, bytesRead
,
1086 &tailBytes
, &volTrailer
);
1089 ErrorLog(0, taskId
, TC_MISSINGTRAILER
, 0, "Missing volume trailer\n");
1090 ERROR_EXIT(TC_MISSINGTRAILER
);
1093 /* Now rx_write the data in the last two blocks */
1095 w
= rx_Write(call
, tbuffer
, headBytes
);
1096 if (w
!= headBytes
) {
1097 ErrorLog(0, taskId
, -1, 0,
1098 "Error in RX trail1 write: Wrote %d bytes\n", w
);
1104 w
= rx_Write(call
, buffer
, tailBytes
);
1105 if (w
!= tailBytes
) {
1106 ErrorLog(0, taskId
, -1, 0,
1107 "Error in RX trail2 write: Wrote %d bytes\n", w
);
1119 * sends the contents of volume dump to Rx Stream associated
1124 restoreVolumeData(struct rx_call
*call
, void *rock
)
1126 struct restoreParams
*rparamsPtr
= (struct restoreParams
*)rock
;
1128 afs_uint32 totalWritten
= 0;
1130 afs_int32 headBytes
, tailBytes
, w
;
1132 afs_int32 nbytes
; /* # bytes data in last tape block read */
1133 struct volumeHeader tapeVolTrailer
;
1136 afs_int32 startRbuf
, endRbuf
, startWbuf
, endWbuf
, buf
, pbuf
, lastbuf
;
1137 struct tc_restoreDesc
*Restore
;
1138 struct dumpNode
*nodePtr
;
1139 struct butm_tapeInfo
*tapeInfoPtr
;
1141 afs_int32 origVolID
;
1143 nodePtr
= rparamsPtr
->nodePtr
;
1144 taskId
= nodePtr
->taskID
;
1145 Restore
= nodePtr
->restores
;
1146 tapeInfoPtr
= rparamsPtr
->tapeInfoPtr
;
1147 origVolName
= Restore
[rparamsPtr
->frag
].oldName
;
1148 origVolID
= Restore
[rparamsPtr
->frag
].origVid
;
1150 /* Read the volume one fragment at a time */
1151 while (rparamsPtr
->frag
< nodePtr
->arraySize
) {
1153 curChunk
= BIGCHUNK
+ 1; /* Check if should abort */
1155 /* Read the volume fragment one block at a time until
1156 * find a volume trailer
1162 while (moretoread
) {
1163 /* Fill the circular buffer with tape blocks
1164 * Search for volume trailer in the process.
1169 butm_ReadFileData(tapeInfoPtr
, bufferBlock
[buf
].data
,
1170 BUTM_BLKSIZE
, &nbytes
);
1172 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
1173 "Can't read FileData on tape %s\n",
1174 rparamsPtr
->mntTapeName
);
1177 curChunk
+= BUTM_BLKSIZE
;
1179 /* Periodically update status structure and check if should abort */
1180 if (curChunk
> BIGCHUNK
) {
1184 nodePtr
->statusNodePtr
->nKBytes
= totalWritten
/ 1024;
1187 if (checkAbortByTaskId(taskId
))
1188 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1191 /* step to next block in buffer */
1193 buf
= ((buf
+ 1) == tapeblocks
) ? 0 : (buf
+ 1);
1195 /* If this is the end of the volume, the exit the loop */
1196 if ((nbytes
!= BUTM_BLKSIZE
)
1199 (bufferBlock
[pbuf
].data
, nbytes
, &tailBytes
,
1203 } while (moretoread
&& (buf
!= endRbuf
));
1205 /* Write the buffer upto (but not including) the last read block
1206 * If volume is completely read, then leave the last two blocks.
1208 lastbuf
= endWbuf
= pbuf
;
1209 if (!moretoread
&& (endWbuf
!= startWbuf
))
1210 endWbuf
= (endWbuf
== 0) ? (tapeblocks
- 1) : (endWbuf
- 1);
1212 for (buf
= startWbuf
; buf
!= endWbuf
;
1213 buf
= (((buf
+ 1) == tapeblocks
) ? 0 : (buf
+ 1))) {
1214 w
= rx_Write(call
, bufferBlock
[buf
].data
, BUTM_BLKSIZE
);
1215 if (w
!= BUTM_BLKSIZE
) {
1216 ErrorLog(0, taskId
, -1, 0, "Error in RX write\n");
1219 totalWritten
+= BUTM_BLKSIZE
;
1222 /* Setup pointers to refill buffer */
1223 startRbuf
= ((lastbuf
+ 1) == tapeblocks
) ? 0 : (lastbuf
+ 1);
1225 startWbuf
= endWbuf
;
1228 /* lastbuf is last block read and it has nbytes of data
1229 * startWbuf is the 2nd to last block read
1230 * Seach for the volume trailer in these two blocks.
1232 if (lastbuf
== startWbuf
)
1234 FindVolTrailer2(NULL
, 0, &headBytes
,
1235 bufferBlock
[lastbuf
].data
, nbytes
, &tailBytes
,
1239 FindVolTrailer2(bufferBlock
[startWbuf
].data
, BUTM_BLKSIZE
,
1240 &headBytes
, bufferBlock
[lastbuf
].data
, nbytes
,
1241 &tailBytes
, &tapeVolTrailer
);
1243 ErrorLog(0, taskId
, TC_MISSINGTRAILER
, 0,
1244 "Missing volume trailer on tape %s\n",
1245 rparamsPtr
->mntTapeName
);
1246 ERROR_EXIT(TC_MISSINGTRAILER
);
1249 /* Now rx_write the data in the last two blocks */
1251 w
= rx_Write(call
, bufferBlock
[startWbuf
].data
, headBytes
);
1252 if (w
!= headBytes
) {
1253 ErrorLog(0, taskId
, -1, 0, "Error in RX write\n");
1256 totalWritten
+= headBytes
;
1259 w
= rx_Write(call
, bufferBlock
[lastbuf
].data
, tailBytes
);
1260 if (w
!= tailBytes
) {
1261 ErrorLog(0, taskId
, -1, 0, "Error in RX write\n");
1264 totalWritten
+= tailBytes
;
1267 /* Exit the loop if the volume is not continued on next tape */
1268 if (!tapeVolTrailer
.contd
)
1269 break; /* We've read the entire volume */
1271 /* Volume is continued on next tape.
1272 * Step to the next volume fragment and prompt for its tape.
1273 * When a volume has multiple frags, those frags are on different
1274 * tapes. So we know that we need to prompt for a tape.
1277 if (rparamsPtr
->frag
>= nodePtr
->arraySize
)
1280 unmountTape(taskId
, tapeInfoPtr
);
1281 strcpy(rparamsPtr
->mntTapeName
, Restore
[rparamsPtr
->frag
].tapeName
);
1282 rparamsPtr
->tapeID
=
1283 (Restore
[rparamsPtr
->frag
].
1284 initialDumpId
? Restore
[rparamsPtr
->frag
].
1285 initialDumpId
: Restore
[rparamsPtr
->frag
].dbDumpId
);
1287 GetRestoreTape(taskId
, tapeInfoPtr
, rparamsPtr
->mntTapeName
,
1288 rparamsPtr
->tapeID
, 1);
1292 /* Position to the frag and read the volume header */
1294 GetVolumeHead(taskId
, tapeInfoPtr
,
1295 Restore
[rparamsPtr
->frag
].position
, origVolName
,
1298 ErrorLog(0, taskId
, code
, 0,
1299 "Can't find volume %s (%u) on tape %s\n", origVolName
,
1300 origVolID
, rparamsPtr
->mntTapeName
);
1301 ERROR_EXIT(TC_VOLUMENOTONTAPE
);
1310 * Find all the volumes on a specific tape and mark them to skip.
1313 SkipTape(struct tc_restoreDesc
*Restore
, afs_int32 size
, afs_int32 index
,
1314 char *tapename
, afs_int32 tapeid
, afs_int32 taskid
)
1318 for (i
= index
; i
< size
; i
++) {
1319 if (Restore
[i
].flags
& RDFLAG_SKIP
)
1322 (Restore
[i
].initialDumpId
? Restore
[i
].initialDumpId
: Restore
[i
].
1324 if ((strcmp(Restore
[i
].tapeName
, tapename
) == 0) && (tid
== tapeid
)) {
1325 SkipVolume(Restore
, size
, i
, Restore
[i
].origVid
, taskid
);
1332 * Find all the entries for a volume and mark them to skip.
1335 SkipVolume(struct tc_restoreDesc
*Restore
, afs_int32 size
, afs_int32 index
,
1336 afs_int32 volid
, afs_int32 taskid
)
1341 for (i
= index
; i
< size
; i
++) {
1342 if (Restore
[i
].flags
& RDFLAG_SKIP
)
1344 if (Restore
[i
].origVid
== volid
) {
1345 Restore
[i
].flags
|= RDFLAG_SKIP
;
1347 TLog(taskid
, "Restore: Skipping %svolume %s (%u)\n",
1348 ((Restore
[i
].dumpLevel
== 0) ? "" : "remainder of "),
1349 Restore
[i
].oldName
, volid
);
1358 xbsaRestoreVolume(afs_uint32 taskId
, struct tc_restoreDesc
*restoreInfo
,
1359 struct restoreParams
*rparamsPtr
)
1364 afs_int32 newServer
, newPart
, newVolId
;
1366 int restoreflags
, havetrans
= 0, startread
= 0;
1367 afs_int32 bytesRead
, endData
= 0;
1369 struct budb_dumpEntry dumpEntry
;
1370 char volumeNameStr
[XBSA_MAX_PATHNAME
], dumpIdStr
[XBSA_MAX_OSNAME
];
1371 struct volumeHeader volHeader
, hostVolHeader
;
1373 if (restoretofile
) {
1374 restoretofilefd
= fopen(restoretofile
, "w+");
1377 dumpID
= restoreInfo
->dbDumpId
;
1379 rc
= bcdb_FindDumpByID(dumpID
, &dumpEntry
);
1381 ErrorLog(0, taskId
, rc
, 0, "Can't read database for dump %u\n",
1386 /* ADSM servers restore ADSM and BUTA dumps */
1387 if ((xbsaType
== XBSA_SERVER_TYPE_ADSM
)
1388 && !(dumpEntry
.flags
& (BUDB_DUMP_ADSM
| BUDB_DUMP_BUTA
))) {
1390 "The dump requested by this restore operation for the "
1391 "volumeset is incompatible with this instance of butc\n");
1392 /* Skip the entire dump (one dump per tape) */
1393 ERROR_EXIT(TC_SKIPTAPE
);
1396 /* make sure we are connected to the correct server. */
1397 if ((strlen((char *)dumpEntry
.tapes
.tapeServer
) != 0)
1398 && (strcmp((char *)dumpEntry
.tapes
.tapeServer
, butxInfo
.serverName
) !=
1400 if ((dumpEntry
.flags
& (BUDB_DUMP_XBSA_NSS
| BUDB_DUMP_BUTA
))
1401 && !forcemultiple
) {
1403 "Dump %d is on server %s but butc is connected "
1404 "to server %s (attempting to restore)\n", dumpID
,
1405 (char *)dumpEntry
.tapes
.tapeServer
, butxInfo
.serverName
);
1408 "Dump %d is on server %s but butc is connected "
1409 "to server %s (switching servers)\n", dumpID
,
1410 (char *)dumpEntry
.tapes
.tapeServer
, butxInfo
.serverName
);
1412 rc
= InitToServer(taskId
, &butxInfo
,
1413 (char *)dumpEntry
.tapes
.tapeServer
);
1414 if (rc
!= XBSA_SUCCESS
)
1415 ERROR_EXIT(TC_SKIPTAPE
);
1419 /* Start a transaction and query the server for the correct fileset dump */
1420 rc
= xbsa_BeginTrans(&butxInfo
);
1421 if (rc
!= XBSA_SUCCESS
) {
1422 ELog(taskId
, "Unable to create a new transaction\n");
1423 ERROR_EXIT(TC_SKIPTAPE
);
1427 if (dumpEntry
.flags
& BUDB_DUMP_BUTA
) { /* old buta style names */
1428 sprintf(dumpIdStr
, "/%d", dumpID
);
1429 strcpy(volumeNameStr
, "/");
1430 strcat(volumeNameStr
, restoreInfo
->oldName
);
1431 } else { /* new butc names */
1432 extern char *butcdumpIdStr
;
1433 strcpy(dumpIdStr
, butcdumpIdStr
);
1434 sprintf(volumeNameStr
, "/%d", dumpID
);
1435 strcat(volumeNameStr
, "/");
1436 strcat(volumeNameStr
, restoreInfo
->oldName
);
1439 rc
= xbsa_QueryObject(&butxInfo
, dumpIdStr
, volumeNameStr
);
1440 if (rc
!= XBSA_SUCCESS
) {
1442 "Unable to locate object (%s) of dump (%s) on the server\n",
1443 volumeNameStr
, dumpIdStr
);
1447 rc
= xbsa_EndTrans(&butxInfo
);
1449 if (rc
!= XBSA_SUCCESS
) {
1450 ELog(taskId
, "Unable to terminate the current transaction\n");
1454 if (checkAbortByTaskId(taskId
))
1455 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1457 /* Now start a transaction on the volume to restore and read the
1458 * volumeheader. We do this before starting a transaction on
1459 * volserver to restore the volume because the XBSA server may take
1460 * a while to mount and seek to the volume causing the volserver to
1463 rc
= xbsa_BeginTrans(&butxInfo
);
1464 if (rc
!= XBSA_SUCCESS
) {
1465 ELog(taskId
, "Unable to create a new transaction\n");
1466 ERROR_EXIT(TC_SKIPTAPE
);
1470 rc
= xbsa_ReadObjectBegin(&butxInfo
, (char *)&volHeader
,
1471 sizeof(volHeader
), &bytesRead
, &endData
);
1472 if (restoretofile
&& (bytesRead
> 0)) {
1473 fwrite((char *)&volHeader
, bytesRead
, 1, restoretofilefd
); /* Save to a file */
1475 if (rc
!= XBSA_SUCCESS
) {
1477 "Unable to begin reading of the volume from the server\n");
1482 if ((bytesRead
!= sizeof(volHeader
)) || endData
) {
1484 "The size of data read (%d) does not equal the size of data requested (%d)\n",
1485 bytesRead
, sizeof(volHeader
));
1486 ERROR_EXIT(TC_BADVOLHEADER
);
1489 /* convert and check the volume header */
1490 rc
= VolHeaderToHost(&hostVolHeader
, &volHeader
);
1492 ErrorLog(0, taskId
, code
, 0, "Can't convert volume header\n");
1496 if ((strcmp(hostVolHeader
.volumeName
, restoreInfo
->oldName
) != 0)
1497 || (restoreInfo
->origVid
1498 && (hostVolHeader
.volumeID
!= restoreInfo
->origVid
))
1499 || (hostVolHeader
.magic
!= TC_VOLBEGINMAGIC
))
1500 ERROR_EXIT(TC_BADVOLHEADER
);
1502 /* Set up prior restoring volume data */
1503 newVolName
= restoreInfo
->newName
;
1504 newVolId
= restoreInfo
->vid
;
1505 newServer
= restoreInfo
->hostAddr
;
1506 newPart
= restoreInfo
->partition
;
1508 if ((restoreInfo
->dumpLevel
== 0)
1509 || (restoreInfo
->flags
& RDFLAG_FIRSTDUMP
))
1510 restoreflags
|= RV_FULLRST
;
1511 if (!(restoreInfo
->flags
& RDFLAG_LASTDUMP
))
1512 restoreflags
|= RV_OFFLINE
;
1514 if (checkAbortByTaskId(taskId
))
1515 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1517 /* Start the restore of the volume data. This is the code we want to return */
1519 UV_RestoreVolume(htonl(newServer
), newPart
, newVolId
, newVolName
,
1520 restoreflags
, xbsaRestoreVolumeData
,
1521 (char *)rparamsPtr
);
1524 rc
= xbsa_ReadObjectEnd(&butxInfo
);
1525 if (rc
!= XBSA_SUCCESS
) {
1527 "Unable to terminate reading of the volume from the server\n");
1533 rc
= xbsa_EndTrans(&butxInfo
);
1534 if (rc
!= XBSA_SUCCESS
) {
1535 ELog(taskId
, "Unable to terminate the current transaction\n");
1541 if (restoretofile
&& restoretofilefd
) {
1542 fclose(restoretofilefd
);
1549 restoreVolume(afs_uint32 taskId
, struct tc_restoreDesc
*restoreInfo
,
1550 struct restoreParams
*rparamsPtr
)
1552 afs_int32 code
= 0, rc
;
1553 afs_int32 newServer
, newPart
, newVolId
;
1557 struct butm_tapeInfo
*tapeInfoPtr
= rparamsPtr
->tapeInfoPtr
;
1559 /* Check if we need a tape and prompt for one if so */
1561 (restoreInfo
->initialDumpId
? restoreInfo
->
1562 initialDumpId
: restoreInfo
->dbDumpId
);
1563 if ((rparamsPtr
->frag
== 0)
1564 || (strcmp(restoreInfo
->tapeName
, rparamsPtr
->mntTapeName
) != 0)
1565 || (tapeID
!= rparamsPtr
->tapeID
)) {
1566 /* Unmount the previous tape */
1567 unmountTape(taskId
, tapeInfoPtr
);
1569 /* Remember this new tape */
1570 strcpy(rparamsPtr
->mntTapeName
, restoreInfo
->tapeName
);
1571 rparamsPtr
->tapeID
= tapeID
;
1573 /* Mount a new tape */
1574 rc
= GetRestoreTape(taskId
, tapeInfoPtr
, rparamsPtr
->mntTapeName
,
1576 ((rparamsPtr
->frag
== 0) ? autoQuery
: 1));
1581 /* Seek to the correct spot and read the header information */
1582 rc
= GetVolumeHead(taskId
, tapeInfoPtr
, restoreInfo
->position
,
1583 restoreInfo
->oldName
, restoreInfo
->origVid
);
1587 /* Set up prior restoring volume data */
1588 newVolName
= restoreInfo
->newName
;
1589 newVolId
= restoreInfo
->vid
;
1590 newServer
= restoreInfo
->hostAddr
;
1591 newPart
= restoreInfo
->partition
;
1593 if ((restoreInfo
->dumpLevel
== 0)
1594 || (restoreInfo
->flags
& RDFLAG_FIRSTDUMP
))
1595 restoreflags
|= RV_FULLRST
;
1596 if (!(restoreInfo
->flags
& RDFLAG_LASTDUMP
))
1597 restoreflags
|= RV_OFFLINE
;
1599 if (checkAbortByTaskId(taskId
))
1600 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1602 /* Start the restore of the volume data. This is the code we
1606 UV_RestoreVolume(htonl(newServer
), newPart
, newVolId
, newVolName
,
1607 restoreflags
, restoreVolumeData
, (char *)rparamsPtr
);
1609 /* Read the FileEnd marker for the volume and step to next FM */
1610 rc
= butm_ReadFileEnd(tapeInfoPtr
);
1612 ErrorLog(0, taskId
, rc
, tapeInfoPtr
->error
,
1613 "Can't read EOF on tape\n");
1621 * created as a LWP by the server stub, <newNode> is a pointer to all
1622 * the parameters Restorer needs
1625 Restorer(void *param
) {
1626 struct dumpNode
*newNode
= (struct dumpNode
*) param
;
1628 afs_int32 code
= 0, tcode
;
1631 struct butm_tapeInfo tapeInfo
;
1632 struct tc_restoreDesc
*Restore
;
1633 struct tc_restoreDesc
*RestoreDesc
;
1634 struct restoreParams rparams
;
1635 afs_int32 allocbufferSize
;
1636 time_t startTime
, endTime
;
1637 afs_int32 goodrestore
= 0;
1639 afs_pthread_setname_self("restorer");
1640 taskId
= newNode
->taskID
;
1641 setStatus(taskId
, DRIVE_WAIT
);
1642 EnterDeviceQueue(deviceLatch
);
1643 clearStatus(taskId
, DRIVE_WAIT
);
1646 TLog(taskId
, "Restore\n");
1648 startTime
= time(0);
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
= calloc(1, allocbufferSize
);
1681 ERROR_EXIT(TC_NOMEMORY
);
1683 for (rparams
.frag
= 0; (rparams
.frag
< newNode
->arraySize
);
1685 RestoreDesc
= &Restore
[rparams
.frag
];
1687 /* Skip the volume if it was requested to */
1688 if (RestoreDesc
->flags
& RDFLAG_SKIP
) {
1689 if (RestoreDesc
->flags
& RDFLAG_LASTDUMP
) {
1690 /* If the volume was restored, should bring it online */
1695 newVolName
= RestoreDesc
->newName
;
1697 /* Make sure the server to restore to is good */
1698 if (!RestoreDesc
->hostAddr
) {
1699 ErrorLog(0, taskId
, 0, 0, "Illegal host ID 0 for volume %s\n",
1701 ERROR_EXIT(TC_INTERNALERROR
);
1704 if (checkAbortByTaskId(taskId
))
1705 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1707 TapeLog(1, taskId
, 0, 0, "Restoring volume %s\n", newVolName
);
1709 strncpy(newNode
->statusNodePtr
->volumeName
, newVolName
,
1713 /* restoreVolume function takes care of all the related fragments
1714 * spanning various tapes. On return the complete volume has been
1718 tcode
= xbsaRestoreVolume(taskId
, RestoreDesc
, &rparams
);
1720 tcode
= restoreVolume(taskId
, RestoreDesc
, &rparams
);
1723 if (tcode
== TC_ABORTEDBYREQUEST
) {
1725 } else if (tcode
== TC_SKIPTAPE
) {
1728 (RestoreDesc
->initialDumpId
? RestoreDesc
->
1729 initialDumpId
: RestoreDesc
->dbDumpId
);
1730 SkipTape(Restore
, newNode
->arraySize
, rparams
.frag
,
1731 RestoreDesc
->tapeName
, tapeID
, taskId
);
1733 ErrorLog(0, taskId
, tcode
, 0, "Can't restore volume %s\n",
1735 SkipVolume(Restore
, newNode
->arraySize
, rparams
.frag
,
1736 RestoreDesc
->origVid
, taskId
);
1748 unmountTape(taskId
, &tapeInfo
);
1751 code
= InitToServer(taskId
, &butxInfo
, 0); /* Return to original server */
1758 if (code
== TC_ABORTEDBYREQUEST
) {
1759 ErrorLog(0, taskId
, 0, 0, "Restore: Aborted by request\n");
1760 clearStatus(taskId
, ABORT_REQUEST
);
1761 setStatus(taskId
, ABORT_DONE
);
1763 TapeLog(0, taskId
, code
, 0, "Restore: Finished with errors\n");
1764 setStatus(taskId
, TASK_ERROR
);
1766 TLog(taskId
, "Restore: Finished\n");
1769 if (centralLogIO
&& startTime
) {
1771 afs_int32 hrs
, min
, sec
, tmp
;
1773 struct tm tmstart
, tmend
;
1775 localtime_r(&startTime
, &tmstart
);
1776 localtime_r(&endTime
, &tmend
);
1777 timediff
= (int)endTime
- (int)startTime
;
1778 hrs
= timediff
/ 3600;
1779 tmp
= timediff
% 3600;
1784 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1785 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1786 "%d of %d volume%s restored\n", taskId
, tmstart
.tm_mon
+ 1,
1787 tmstart
.tm_mday
, tmstart
.tm_year
+ 1900, tmstart
.tm_hour
,
1788 tmstart
.tm_min
, tmstart
.tm_sec
, tmend
.tm_mon
+ 1,
1789 tmend
.tm_mday
, tmend
.tm_year
+ 1900, tmend
.tm_hour
,
1790 tmend
.tm_min
, tmend
.tm_sec
, hrs
, min
, sec
, goodrestore
,
1791 newNode
->arraySize
, ((newNode
->arraySize
> 1) ? "s" : ""));
1793 fwrite(line
, strlen(line
), 1, centralLogIO
);
1794 fflush(centralLogIO
);
1797 setStatus(taskId
, TASK_DONE
);
1800 LeaveDeviceQueue(deviceLatch
);
1801 return (void *)(intptr_t)(code
);
1804 /* this is just scaffolding, creates new tape label with name <tapeName> */
1807 GetNewLabel(struct butm_tapeInfo
*tapeInfoPtr
, char *pName
, char *AFSName
,
1808 struct butm_tapeLabel
*tapeLabel
)
1813 memset(tapeLabel
, 0, sizeof(struct butm_tapeLabel
));
1816 butm_GetSize(tapeInfoPtr
, &size
);
1818 size
= globalTapeConfig
.capacity
;
1820 size
= 0; /* no tape size */
1822 gettimeofday(&tp
, NULL
);
1824 tapeLabel
->structVersion
= CUR_TAPE_VERSION
;
1825 tapeLabel
->creationTime
= tp
.tv_sec
;
1826 tapeLabel
->size
= size
;
1827 tapeLabel
->expirationDate
= 0; /* 1970 sometime */
1828 tapeLabel
->dumpPath
[0] = 0; /* no path name */
1829 tapeLabel
->useCount
= 0;
1830 strcpy(tapeLabel
->AFSName
, AFSName
);
1831 strcpy(tapeLabel
->pName
, pName
);
1832 strcpy(tapeLabel
->cell
, globalCellName
);
1833 strcpy(tapeLabel
->comment
, "AFS Backup Software");
1834 strcpy(tapeLabel
->creator
.name
, "AFS 3.6");
1835 strcpy(tapeLabel
->creator
.instance
, "");
1836 strcpy(tapeLabel
->creator
.cell
, globalCellName
);
1839 /* extracts trailer out of buffer, nbytes is set to total data in
1840 * buffer - trailer size */
1842 ExtractTrailer(char *buffer
, afs_int32 size
, afs_int32
*nbytes
,
1843 struct volumeHeader
*volTrailerPtr
)
1847 struct volumeHeader tempTrailer
;
1851 (size
- sizeof(struct volumeHeader
) + sizeof(tempTrailer
.pad
));
1853 code
= readVolumeHeader(buffer
, startPos
, &tempTrailer
);
1855 code
= VolHeaderToHost(volTrailerPtr
, &tempTrailer
);
1861 return 1; /* saw the trailer */
1867 return 0; /* did not see the trailer */
1871 FindVolTrailer(char *buffer
, afs_int32 size
, afs_int32
*dSize
,
1872 struct volumeHeader
*volTrailerPtr
)
1874 afs_int32 offset
, s
;
1881 s
= sizeof(struct volumeHeader
) + sizeof(volTrailerPtr
->pad
);
1885 found
= ExtractTrailer((buffer
+ size
- s
), s
, &offset
, volTrailerPtr
);
1887 *dSize
-= (s
- offset
);
1892 FindVolTrailer2(char *buffera
, afs_int32 sizea
, afs_int32
*dataSizea
,
1893 char *bufferb
, afs_int32 sizeb
, afs_int32
*dataSizeb
,
1894 struct volumeHeader
*volTrailerPtr
)
1896 afs_int32 offset
, s
;
1897 afs_int32 headB
, tailB
;
1907 s
= sizeof(struct volumeHeader
) + sizeof(volTrailerPtr
->pad
);
1909 found
= FindVolTrailer(bufferb
, sizeb
, dataSizeb
, volTrailerPtr
);
1912 headB
= (s
- sizeb
); /*(s > sizeb) */
1913 if (headB
> sizea
) {
1920 memset(tapeVolumeHT
, 0, sizeof(tapeVolumeHT
));
1922 memcpy(tapeVolumeHT
, buffera
+ sizea
- headB
, headB
);
1924 memcpy(tapeVolumeHT
+ headB
, bufferb
, tailB
);
1925 if (ExtractTrailer(tapeVolumeHT
, s
, &offset
, volTrailerPtr
)) {
1927 if (offset
> headB
) {
1928 /* *dataSizea remains unchanged */
1929 *dataSizeb
= offset
- headB
;
1931 *dataSizea
-= (headB
- offset
); /*(headB >= offset) */
1941 ExpirationDate(afs_int32 dumpid
)
1944 Date expiration
= 0;
1945 struct budb_dumpEntry dumpEntry
;
1946 struct budb_tapeEntry tapeEntry
;
1947 struct budb_volumeEntry volEntry
;
1951 * Get the expiration date from DB if its there. The expiration of
1952 * any tape will be the most future expiration of any dump in the
1953 * set. Can't use bcdb_FindTape because dumpid here pertains to the
1956 code
= bcdb_FindLastTape(dumpid
, &dumpEntry
, &tapeEntry
, &volEntry
);
1958 expiration
= tapeEntry
.expires
;
1960 return (expiration
);
1963 /* Returns true or false depending on whether the tape is expired or not */
1966 tapeExpired(struct butm_tapeLabel
*tapeLabelPtr
)
1971 expiration
= ExpirationDate(tapeLabelPtr
->dumpid
);
1973 expiration
= tapeLabelPtr
->expirationDate
;
1975 gettimeofday(&tp
, NULL
);
1976 return ((expiration
< tp
.tv_sec
) ? 1 : 0);
1980 * given the label on the tape, delete any old information from the
1983 * Deletes all entries that match the volset.dumpnode
1984 * and the dump path.
1988 updateTapeLabel(struct labelTapeIf
*labelIfPtr
,
1989 struct butm_tapeInfo
*tapeInfoPtr
,
1990 struct butm_tapeLabel
*newLabelPtr
)
1992 struct butm_tapeLabel oldLabel
;
1993 afs_int32 i
, code
= 0;
1995 int tapeIsLabeled
= 0;
1996 int interactiveFlag
;
1999 interactiveFlag
= autoQuery
;
2000 taskId
= labelIfPtr
->taskId
;
2003 if (interactiveFlag
) {
2005 PromptForTape(LABELOPCODE
, TNAME(newLabelPtr
), 0,
2006 labelIfPtr
->taskId
, tapecount
);
2010 interactiveFlag
= 1;
2013 /* mount the tape */
2014 code
= butm_Mount(tapeInfoPtr
, newLabelPtr
->AFSName
);
2016 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
, "Can't open tape\n");
2020 code
= butm_ReadLabel(tapeInfoPtr
, &oldLabel
, 1); /* will rewind the tape */
2024 if ((strcmp(newLabelPtr
->AFSName
, "") != 0)
2025 && (strcmp(oldLabel
.pName
, "") != 0)) {
2026 /* We are setting the AFS name, yet tape
2027 * has a permanent name (not allowed).
2029 TLog(taskId
, "Can't label. Tape has permanent label '%s'\n",
2034 if (!tapeExpired(&oldLabel
)) {
2035 if (!queryoperator
) {
2036 TLog(taskId
, "This tape has not expired\n");
2039 if (Ask("This tape has not expired - proceed") == 0)
2043 /* Keep the permanent name */
2044 if (strcmp(newLabelPtr
->pName
, "") == 0) {
2045 strcpy(newLabelPtr
->pName
, oldLabel
.pName
);
2046 } else if (strcmp(newLabelPtr
->pName
, TC_NULLTAPENAME
) == 0) {
2047 strcpy(newLabelPtr
->pName
, "");
2051 /* extract useful information from the old label */
2052 if (tapeIsLabeled
&& oldLabel
.structVersion
>= TAPE_VERSION_3
) {
2053 newLabelPtr
->dumpid
= 0;
2054 newLabelPtr
->useCount
= oldLabel
.useCount
+ 1;
2057 /* now write the new label */
2058 code
= butm_Create(tapeInfoPtr
, newLabelPtr
, 1); /* will rewind the tape */
2060 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
2061 "Can't label tape\n");
2068 unmountTape(taskId
, tapeInfoPtr
);
2071 /* delete obsolete information from the database */
2072 if (tapeIsLabeled
&& oldLabel
.structVersion
>= TAPE_VERSION_3
) {
2073 /* delete based on dump id */
2074 if (oldLabel
.dumpid
) {
2075 i
= bcdb_deleteDump(oldLabel
.dumpid
, 0, 0, 0);
2076 if (i
&& (i
!= BUDB_NOENT
))
2077 ErrorLog(0, taskId
, i
, 0,
2078 "Warning: Can't delete old dump %u from database\n",
2084 unmountTape(taskId
, tapeInfoPtr
);
2089 * LWP created by the server stub. Labels the tape with name and size
2090 * specified by <label>
2094 Labeller(void *param
)
2096 struct labelTapeIf
*labelIfPtr
= (struct labelTapeIf
*)param
;
2098 struct tc_tapeLabel
*label
= &labelIfPtr
->label
;
2100 struct butm_tapeLabel newTapeLabel
;
2101 struct butm_tapeInfo tapeInfo
;
2105 afs_pthread_setname_self("labeller");
2106 taskId
= labelIfPtr
->taskId
;
2107 setStatus(taskId
, DRIVE_WAIT
);
2108 EnterDeviceQueue(deviceLatch
);
2109 clearStatus(taskId
, DRIVE_WAIT
);
2112 TLog(taskId
, "Labeltape\n");
2114 memset(&tapeInfo
, 0, sizeof(tapeInfo
));
2115 tapeInfo
.structVersion
= BUTM_MAJORVERSION
;
2116 code
= butm_file_Instantiate(&tapeInfo
, &globalTapeConfig
);
2118 ErrorLog(0, taskId
, code
, tapeInfo
.error
,
2119 "Can't initialize the tape module\n");
2123 GetNewLabel(&tapeInfo
, label
->pname
, label
->afsname
, &newTapeLabel
);
2125 newTapeLabel
.size
= label
->size
;
2127 newTapeLabel
.size
= globalTapeConfig
.capacity
;
2129 code
= updateTapeLabel(labelIfPtr
, &tapeInfo
, &newTapeLabel
);
2134 if (code
== TC_ABORTEDBYREQUEST
) {
2135 ErrorLog(0, taskId
, 0, 0, "Labeltape: Aborted by request\n");
2136 clearStatus(taskId
, ABORT_REQUEST
);
2137 setStatus(taskId
, ABORT_DONE
);
2139 ErrorLog(0, taskId
, code
, 0, "Labeltape: Finished with errors\n");
2140 setStatus(taskId
, TASK_ERROR
);
2142 TLog(taskId
, "Labelled tape %s size %u Kbytes\n",
2143 TNAME(&newTapeLabel
), newTapeLabel
.size
);
2145 setStatus(labelIfPtr
->taskId
, TASK_DONE
);
2148 LeaveDeviceQueue(deviceLatch
);
2149 return (void *)(intptr_t)(code
);
2153 * print out the tape label.
2157 PrintTapeLabel(struct butm_tapeLabel
*labelptr
)
2159 char tapeName
[BU_MAXTAPELEN
+ 32];
2162 printf("Tape label\n");
2163 printf("----------\n");
2164 TAPENAME(tapeName
, labelptr
->pName
, labelptr
->dumpid
);
2165 printf("permanent tape name = %s\n", tapeName
);
2166 TAPENAME(tapeName
, labelptr
->AFSName
, labelptr
->dumpid
);
2167 printf("AFS tape name = %s\n", tapeName
);
2168 t
= labelptr
->creationTime
;
2169 printf("creationTime = %s", ctime(&t
));
2170 if (labelptr
->expirationDate
) {
2171 t
= labelptr
->expirationDate
;
2172 printf("expirationDate = %s", cTIME(&t
));
2174 printf("cell = %s\n", labelptr
->cell
);
2175 printf("size = %u Kbytes\n", labelptr
->size
);
2176 printf("dump path = %s\n", labelptr
->dumpPath
);
2178 if (labelptr
->structVersion
>= TAPE_VERSION_3
) {
2179 printf("dump id = %u\n", labelptr
->dumpid
);
2180 printf("useCount = %d\n", labelptr
->useCount
);
2182 printf("-- End of tape label --\n\n");
2186 * Read the label from a tape.
2187 * Currently prints out a "detailed" summary of the label but passes
2188 * back only selected fields.
2192 ReadLabel(struct tc_tapeLabel
*label
)
2194 struct butm_tapeLabel newTapeLabel
;
2195 struct butm_tapeInfo tapeInfo
;
2199 int interactiveFlag
;
2202 EnterDeviceQueue(deviceLatch
);
2203 taskId
= allocTaskId(); /* reqd for lower level rtns */
2206 TLog(taskId
, "Readlabel\n");
2208 memset(&tapeInfo
, 0, sizeof(tapeInfo
));
2209 tapeInfo
.structVersion
= BUTM_MAJORVERSION
;
2210 code
= butm_file_Instantiate(&tapeInfo
, &globalTapeConfig
);
2212 ErrorLog(0, taskId
, code
, tapeInfo
.error
,
2213 "Can't initialize the tape module\n");
2216 memset(&newTapeLabel
, 0, sizeof(newTapeLabel
));
2218 interactiveFlag
= autoQuery
;
2221 if (interactiveFlag
) {
2222 code
= PromptForTape(READLABELOPCODE
, "", 0, taskId
, tapecount
);
2226 interactiveFlag
= 1;
2229 code
= butm_Mount(&tapeInfo
, "");
2231 TapeLog(0, taskId
, code
, tapeInfo
.error
, "Can't open tape\n");
2237 unmountTape(taskId
, &tapeInfo
);
2240 code
= butm_ReadLabel(&tapeInfo
, &newTapeLabel
, 1); /* will rewind the tape */
2242 if (code
== BUTM_NOLABEL
) {
2243 printf("Tape is unlabelled\n");
2246 ErrorLog(1, taskId
, code
, tapeInfo
.error
, "Can't read tape label\n");
2250 /* copy the fields to be passed to the caller */
2251 label
->size
= newTapeLabel
.size
;
2252 label
->tapeId
= newTapeLabel
.dumpid
;
2253 strcpy(label
->afsname
, newTapeLabel
.AFSName
);
2254 strcpy(label
->pname
, newTapeLabel
.pName
);
2257 expir
= ExpirationDate(newTapeLabel
.dumpid
);
2259 newTapeLabel
.expirationDate
= expir
;
2261 PrintTapeLabel(&newTapeLabel
);
2264 unmountTape(taskId
, &tapeInfo
);
2266 if (code
== TC_ABORTEDBYREQUEST
)
2267 ErrorLog(0, taskId
, 0, 0, "ReadLabel: Aborted by request\n");
2268 else if (code
&& (code
!= BUTM_NOLABEL
))
2269 ErrorLog(0, taskId
, code
, 0, "ReadLabel: Finished with errors\n");
2271 TLog(taskId
, "ReadLabel: Finished\n");
2273 LeaveDeviceQueue(deviceLatch
);
2277 /* Function to read volume header and trailer structure from tape, taking
2278 into consideration, different word alignment rules.
2281 readVolumeHeader(char *buffer
, /* in - buffer to read header from */
2282 afs_int32 bufloc
, /* in - header's location in buffer */
2283 struct volumeHeader
*header
) /* out -header structure */
2285 struct volumeHeader vhptr
, *tempvhptr
;
2286 afs_int32 firstSplice
= (afs_int32
) ((char*)& vhptr
.pad
- (char*) & vhptr
);
2287 int padLen
= sizeof(vhptr
.pad
); /* pad to achieve 4 byte alignment */
2288 int nextSplice
= sizeof(struct volumeHeader
) - firstSplice
- padLen
;
2290 /* Four cases are to be handled
2292 * Volume Header (byte alignment)
2293 * -----------------------
2300 * -----------------------
2302 * Case 2 and Case 3 are identical cases and handled the same way.
2303 * Case 1 and Case 4 are separate cases. In one case the pad needs
2304 * to be removed and in the other, it needs to be spliced in. The
2305 * four cases are handled as follows
2307 tempvhptr
= (struct volumeHeader
*)(buffer
+ bufloc
);
2308 if ((strncmp(tempvhptr
->preamble
, "H++NAME#", 8) == 0)
2309 && (strncmp(tempvhptr
->postamble
, "T--NAME#", 8) == 0)) {
2310 /* Handle Cases 2 & 3 */
2311 memcpy(&vhptr
, buffer
+ bufloc
, sizeof(struct volumeHeader
));
2312 HEADER_CHECKS(vhptr
, header
);
2315 memset(&vhptr
, 0, sizeof(struct volumeHeader
));
2316 memcpy(&vhptr
, buffer
+ bufloc
, firstSplice
);
2317 memset(&vhptr
.pad
, 0, padLen
);
2318 memcpy(&vhptr
.volumeID
, buffer
+ bufloc
+ firstSplice
, nextSplice
);
2319 HEADER_CHECKS(vhptr
, header
);
2322 memset(&vhptr
, 0, sizeof(struct volumeHeader
));
2323 memcpy(&vhptr
, buffer
+ bufloc
, firstSplice
);
2324 /* probably GCC bug 37060; however, no guarantee on length of buffer */
2325 tempvhptr
= (struct volumeHeader
*)(buffer
+ firstSplice
);
2326 memcpy(tempvhptr
, buffer
+ bufloc
+ firstSplice
+ padLen
,
2328 HEADER_CHECKS(vhptr
, header
);
2331 return (TC_BADVOLHEADER
);