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>
19 #include <afs/tcdata.h>
20 #include <afs/bubasics.h>
21 #include <afs/budb_client.h>
22 #include <afs/butm_prototypes.h>
23 #include <afs/vldbint.h>
24 #include <afs/ktime.h>
25 #include <afs/vlserver.h>
26 #include <afs/afsint.h>
27 #include <afs/volser.h>
28 #include <afs/volser_prototypes.h>
29 #include <afs/volint.h>
30 #include <afs/cellconfig.h>
31 #include <afs/bucoord_prototypes.h>
33 #include "butc_internal.h"
34 #include "error_macros.h"
35 #include "butc_xbsa.h"
38 /* GLOBAL CONFIGURATION PARAMETERS */
39 extern int dump_namecheck
;
40 extern int queryoperator
;
42 extern int forcemultiple
;
44 extern struct ubik_client
*cstruct
;
45 dlqlinkT savedEntries
;
46 dlqlinkT entries_to_flush
;
48 extern afs_int32 groupId
;
49 extern afs_int32 BufferSize
;
50 extern afs_int32 statusSize
;
51 extern FILE *centralLogIO
;
52 afs_int32 lastPass
= 0;
54 extern afs_int32 xbsaType
;
55 char *butcdumpIdStr
= "/backup_afs_volume_dumps";
56 extern struct butx_transactionInfo butxInfo
;
57 extern char *xbsaObjectOwner
;
58 extern char *appObjectOwner
;
59 extern char *xbsaSecToken
;
60 extern char *xbsalGName
;
61 extern char *globalButcLog
;
64 afs_int32 dataSize
; /* Size of data to read on each rx_Read() call */
65 afs_int32 tapeblocks
; /* Number of 16K tape datablocks in buffer (!CONF_XBSA) */
69 * Done 1) dump id generation
70 * Done xx) volume fragment number accounting !! I think.
71 * 2) check abort - check after subroutine calls
72 * Done 3) trailer anomaly
73 * 4) trailer damage indicator after partial dumps ( affects scandump )
74 * Done 5) Ensure mount failure logged
75 * 6) Ensure bucoord status calls work
79 * keep token timeout. If no user reponse (idle time > some period)
80 * and tokens about to time out, terminate dump. This provides at
81 * least something usable.
87 int curVolume
; /* index in dumpNode of volume */
88 int curVolumeStatus
; /* more explicit dump state */
89 afs_uint32 curVolStartPos
; /* Starting position of the current volume */
90 afs_uint32 databaseDumpId
; /* real dump id, for db */
91 afs_uint32 initialDumpId
; /* the initial dump, for appended dumps */
92 afs_int32 volumesDumped
; /* # volumes successfully dumped */
93 afs_int32 volumesFailed
; /* # volumes that failed to dump */
94 afs_int32 volumesNotDumped
; /* # volumes that were not dumped (didn't fail) */
97 char tapeName
[TC_MAXTAPENAMELEN
];
98 struct butm_tapeInfo
*tapeInfoPtr
;
99 struct butm_tapeLabel tapeLabel
;
100 int wroteLabel
; /* If the tape label is written */
102 /* database information */
103 struct budb_dumpEntry lastDump
; /* the last dump of this volset */
104 struct budb_dumpEntry dump
; /* current dump */
105 struct budb_tapeEntry tape
; /* current tape, not used -VA */
107 /* links to existing info */
108 struct dumpNode
*node
;
111 /* Forward declarations */
113 int makeVolumeHeader(struct volumeHeader
*, struct dumpRock
*, int);
114 int volumeHeader_hton(struct volumeHeader
*, struct volumeHeader
*);
115 char retryPrompt(char *, afs_int32
, afs_uint32
);
116 int getDumpTape(struct dumpRock
*, int, afs_int32
);
117 int getXBSATape(struct dumpRock
*);
118 afs_int32
createDump(struct dumpRock
*);
120 /* configuration variables */
121 #define HITEOT(code) ((code == BUTM_IO) || (code == BUTM_EOT) || (code == BUTM_IOCTL))
122 extern int autoQuery
;
125 afs_int32 tc_EndMargin
;
126 afs_int32 tc_KEndMargin
;
127 static char *bufferBlock
;
129 /* compute the absolute expiration date */
131 calcExpirationDate(afs_int32 expType
, afs_int32 expDate
, afs_int32 createTime
)
133 struct ktime_date kd
;
137 /* expiration date is relative to the creation time of the dump.
138 * This is the only case that requires any work
140 Int32To_ktimeRelDate(expDate
, &kd
);
141 return (Add_RelDate_to_Time(&kd
, createTime
));
152 afs_uint32 curr_bserver
= 0;
153 struct rx_connection
*curr_fromconn
= (struct rx_connection
*)0;
155 struct rx_connection
*
156 Bind(afs_uint32 server
)
159 if (curr_bserver
== server
) /* Keep connection if have it */
160 return (curr_fromconn
);
162 rx_DestroyConnection(curr_fromconn
); /* Otherwise get rid of it */
163 curr_fromconn
= (struct rx_connection
*)0;
168 curr_fromconn
= UV_Bind(server
, AFSCONF_VOLUMEPORT
); /* Establish new connection */
170 curr_bserver
= server
;
173 return (curr_fromconn
);
177 * 1) save the chunksize or otherwise ensure tape space remaining is
178 * check frequently enough
179 * 2) This is called once. For partial dumps, need to
180 * ensure that the tape device is left in the correct state for
184 #define BIGCHUNK 102400
187 dumpVolume(struct tc_dumpDesc
* curDump
, struct dumpRock
* dparamsPtr
)
189 struct butm_tapeInfo
*tapeInfoPtr
= dparamsPtr
->tapeInfoPtr
;
190 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
191 afs_int32 taskId
= nodePtr
->taskID
;
194 afs_int32 volumeFlags
;
195 afs_int32 kRemaining
;
196 afs_int32 rc
, code
= 0;
198 afs_uint32 volBytesRead
;
199 afs_uint32 chunkSize
;
200 afs_int32 bytesread
; /* rx reads */
201 int endofvolume
= 0; /* Have we read all volume data */
204 struct volumeHeader hostVolumeHeader
;
206 struct rx_call
*fromcall
= (struct rx_call
*)0;
207 struct rx_connection
*fromconn
;
208 afs_int32 updatedate
, fromtid
= 0;
209 volEntries volumeInfo
;
210 afs_int32 bytesWritten
;
211 afs_uint32 statuscount
= statusSize
, tsize
= 0;
213 dparamsPtr
->curVolumeStatus
= DUMP_NOTHING
;
215 fromconn
= Bind(htonl(curDump
->hostAddr
)); /* get connection to the server */
217 /* Determine when the volume was last cloned and updated */
218 volumeInfo
.volEntries_val
= (volintInfo
*) 0;
219 volumeInfo
.volEntries_len
= 0;
220 rc
= AFSVolListOneVolume(fromconn
, curDump
->partition
, curDump
->vid
,
224 updatedate
= volumeInfo
.volEntries_val
[0].updateDate
;
227 RWVOL
) ? time(0) : volumeInfo
.volEntries_val
[0].creationDate
);
229 if (curDump
->date
>= curDump
->cloneDate
)
230 ERROR_EXIT(0); /* not recloned since last dump */
231 if (curDump
->date
> updatedate
) {
232 dparamsPtr
->curVolumeStatus
= DUMP_NODUMP
; /* not modified since last dump */
236 /* Start the volserver transaction and dump */
237 rc
= AFSVolTransCreate(fromconn
, curDump
->vid
, curDump
->partition
, ITBusy
,
241 fromcall
= rx_NewCall(fromconn
);
243 rc
= StartAFSVolDump(fromcall
, fromtid
, curDump
->date
);
247 dparamsPtr
->curVolumeStatus
= DUMP_PARTIAL
;
248 dparamsPtr
->curVolStartPos
= tapeInfoPtr
->position
;
250 /* buffer is place in bufferBlock to write volume data.
251 * butm_writeFileData() assumes the previous BUTM_HDRSIZE bytes
252 * is available to write the tape block header.
254 buffer
= bufferBlock
+ BUTM_HDRSIZE
;
256 /* Dump one volume fragment at a time until we dump the full volume.
257 * A volume with more than 1 fragment means the volume will 'span'
260 for (fragmentNumber
= 1; !endofvolume
; fragmentNumber
++) { /*frag */
261 rc
= butm_WriteFileBegin(tapeInfoPtr
);
263 ErrorLog(1, taskId
, rc
, tapeInfoPtr
->error
,
264 "Can't write FileBegin on tape\n");
267 indump
= 1; /* first write to tape */
269 /* Create and Write the volume header */
270 makeVolumeHeader(&hostVolumeHeader
, dparamsPtr
, fragmentNumber
);
271 hostVolumeHeader
.contd
= ((fragmentNumber
== 1) ? 0 : TC_VOLCONTD
);
272 volumeHeader_hton(&hostVolumeHeader
, (struct volumeHeader
*)buffer
);
274 rc
= butm_WriteFileData(tapeInfoPtr
, buffer
, 1,
275 sizeof(hostVolumeHeader
));
277 ErrorLog(1, taskId
, rc
, tapeInfoPtr
->error
,
278 "Can't write VolumeHeader on tape\n");
282 bytesWritten
= BUTM_BLOCKSIZE
; /* Wrote one tapeblock */
283 tsize
+= bytesWritten
;
285 /* Start reading volume data, rx_Read(), and dumping to the tape
286 * until we've dumped the entire volume (endofvolume == 1). We can
287 * exit this loop early if we find we are close to the end of the
288 * tape; in which case we dump the next fragment on the next tape.
293 while (!endofvolume
&& !fragmentvolume
) { /*w */
294 /* Check for abort in the middle of writing data */
295 if (volBytesRead
>= chunkSize
) {
296 chunkSize
+= BIGCHUNK
;
297 if (checkAbortByTaskId(taskId
))
298 ABORT_EXIT(TC_ABORTEDBYREQUEST
);
300 /* set bytes dumped for backup */
302 nodePtr
->statusNodePtr
->nKBytes
= tapeInfoPtr
->kBytes
;
306 /* Determine how much data to read in upcoming RX_Read() call */
308 /* Check if we are close to the EOT. There should at least be some
309 * data on the tape before it is switched. HACK: we have to split a
310 * volume across tapes because the volume trailer says the dump
311 * continues on the next tape (and not the filemark). This could
312 * result in a volume starting on one tape (no volume data dumped) and
313 * continued on the next tape. It'll work, just requires restore to
314 * switch tapes. This allows many small volumes (<16K) to be dumped.
316 kRemaining
= butm_remainingKSpace(tapeInfoPtr
);
317 if ((kRemaining
< tc_KEndMargin
)
319 || (tapeInfoPtr
->position
> (isafile
? 3 : 2)))) {
324 /* Guess at how much data to read. So we don't write off end of tape */
325 if (kRemaining
< (tapeblocks
* 16)) {
326 if (kRemaining
< 0) {
327 toread
= BUTM_BLKSIZE
;
329 toread
= ((kRemaining
/ 16) + 1) * BUTM_BLKSIZE
;
330 if (toread
> dataSize
)
336 /* Set aside space for the trailing volume header when using large buffers. */
337 if (XBSAMAXBUFFER
< toread
+ sizeof(hostVolumeHeader
)) {
338 toread
= XBSAMAXBUFFER
- sizeof(hostVolumeHeader
);
342 /* Read some volume data. */
343 if (fragmentvolume
) {
346 bytesread
= rx_Read(fromcall
, buffer
, toread
);
347 volBytesRead
+= bytesread
;
348 if (bytesread
!= toread
) {
349 /* Make sure were at end of volume and not a communication error */
350 rc
= rx_Error(fromcall
);
357 if (fragmentvolume
|| endofvolume
) {
358 /* Create a volume trailer appending it to this data block */
359 makeVolumeHeader(&hostVolumeHeader
, dparamsPtr
,
361 hostVolumeHeader
.contd
= (endofvolume
? 0 : TC_VOLCONTD
);
362 hostVolumeHeader
.magic
= TC_VOLENDMAGIC
;
363 hostVolumeHeader
.endTime
= (endofvolume
? time(0) : 0);
364 volumeHeader_hton(&hostVolumeHeader
, (struct volumeHeader
*)&buffer
[bytesread
]);
365 bytesread
+= sizeof(hostVolumeHeader
);
368 /* Write the datablock out */
369 /* full data buffer - write it to tape */
370 rc
= butm_WriteFileData(tapeInfoPtr
, buffer
, tapeblocks
,
373 ErrorLog(1, taskId
, rc
, tapeInfoPtr
->error
,
374 "Can't write VolumeData on tape\n");
377 bytesWritten
= tapeblocks
* BUTM_BLOCKSIZE
;
378 tsize
+= bytesWritten
;
380 /* Display a status line every statusSize or at end of volume */
382 && ((tsize
>= statuscount
) || endofvolume
383 || fragmentvolume
)) {
386 localtime_r(&t
, &tm
);
387 printf("%02d:%02d:%02d: Task %u: %u KB: %s: %u B\n",
388 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, taskId
,
389 tapeInfoPtr
->kBytes
, hostVolumeHeader
.volumeName
,
391 statuscount
= tsize
+ statusSize
;
395 /* End the dump before recording it in BUDB as successfully dumped */
396 rc
= butm_WriteFileEnd(tapeInfoPtr
);
399 ErrorLog(1, taskId
, rc
, tapeInfoPtr
->error
,
400 "Can't write FileEnd on tape\n");
404 /* Record in BUDB the volume fragment as succcessfully dumped */
405 volumeFlags
= ((fragmentNumber
== 1) ? BUDB_VOL_FIRSTFRAG
: 0);
407 volumeFlags
|= BUDB_VOL_LASTFRAG
;
408 rc
= addVolume(0, dparamsPtr
->databaseDumpId
, dparamsPtr
->tapeName
,
409 nodePtr
->dumps
[dparamsPtr
->curVolume
].name
,
410 nodePtr
->dumps
[dparamsPtr
->curVolume
].vid
,
411 nodePtr
->dumps
[dparamsPtr
->curVolume
].cloneDate
,
412 dparamsPtr
->curVolStartPos
, volBytesRead
,
413 (fragmentNumber
- 1), volumeFlags
);
417 /* If haven't finished dumping the volume, end this
418 * tape and get the next tape.
421 /* Write an EOT marker.
422 * Log the error but ignore it since the dump is effectively done.
423 * Scantape will detect continued volume and not read the EOT.
425 rc
= butm_WriteEOT(tapeInfoPtr
);
427 TapeLog(1, taskId
, rc
, tapeInfoPtr
->error
,
428 "Warning: Can't write End-Of-Dump on tape\n");
430 /* Unmount the tape */
431 unmountTape(taskId
, tapeInfoPtr
);
433 /* Tell the database the tape is complete (and ok) */
434 rc
= finishTape(&dparamsPtr
->tape
,
435 dparamsPtr
->tapeInfoPtr
->kBytes
+
436 (dparamsPtr
->tapeInfoPtr
->nBytes
? 1 : 0));
440 /* get the next tape. Prompt, mount, and add it into the database */
441 dparamsPtr
->tapeSeq
++;
442 rc
= getDumpTape(dparamsPtr
, 1, 0); /* interactive - no append */
446 dparamsPtr
->curVolStartPos
= tapeInfoPtr
->position
;
450 dparamsPtr
->curVolumeStatus
= DUMP_SUCCESS
;
454 * If we hit the end, see if this is the first volume on the tape or not.
455 * Also, mark the tape as finished if the tape contains other dumps.
460 ErrorLog(2, taskId
, code
, tapeInfoPtr
->error
,
461 "Warning: Dump (%s) hit end-of-tape inferred\n",
462 nodePtr
->dumpSetName
);
464 if (tapeInfoPtr
->position
== 2) {
465 dparamsPtr
->curVolumeStatus
= DUMP_NORETRYEOT
;
467 dparamsPtr
->curVolumeStatus
= DUMP_RETRY
;
468 rc
= finishTape(&dparamsPtr
->tape
,
469 dparamsPtr
->tapeInfoPtr
->kBytes
+
470 (dparamsPtr
->tapeInfoPtr
->nBytes
? 1 : 0));
477 * This is used when an error occurs part way into a volume dump. Clean
478 * the tape state by writing an FileEnd mark. Forgo this action if we hit
482 rc
= butm_WriteFileEnd(tapeInfoPtr
);
485 ErrorLog(1, taskId
, rc
, tapeInfoPtr
->error
,
486 "Can't write FileEnd on tape\n");
491 rc
= rx_EndCall(fromcall
, 0);
498 rc
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
500 code
= (rc
? rc
: rcode
);
506 dparamsPtr
->curVolumeStatus
= DUMP_FAILED
;
511 xbsaDumpVolume(struct tc_dumpDesc
* curDump
, struct dumpRock
* dparamsPtr
)
514 struct butm_tapeInfo
*tapeInfoPtr
= dparamsPtr
->tapeInfoPtr
;
515 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
516 char *buffer
= bufferBlock
;
517 afs_int32 taskId
= nodePtr
->taskID
;
518 afs_int32 rc
, code
= 0;
520 afs_uint32 volBytesRead
;
521 afs_uint32 chunkSize
;
522 afs_int32 bytesread
; /* rx reads */
523 int endofvolume
= 0; /* Have we read all volume data */
524 int begindump
= 0, indump
= 0; /* if dump transaction started; if dumping data */
525 struct volumeHeader hostVolumeHeader
;
527 struct rx_call
*fromcall
= (struct rx_call
*)0;
528 struct rx_connection
*fromconn
;
529 afs_int32 updatedate
, fromtid
= 0;
530 volEntries volumeInfo
;
531 afs_int32 bytesWritten
;
532 afs_uint32 statuscount
= statusSize
, tsize
= 0, esize
;
535 char volumeNameStr
[XBSA_MAX_PATHNAME
];
536 static char *dumpDescription
= "AFS volume dump";
537 static char *objectDescription
= "XBSA - butc";
539 dparamsPtr
->curVolumeStatus
= DUMP_NOTHING
;
541 fromconn
= Bind(htonl(curDump
->hostAddr
)); /* get connection to the server */
543 /* Determine when the volume was last cloned and updated */
544 volumeInfo
.volEntries_val
= (volintInfo
*) 0;
545 volumeInfo
.volEntries_len
= 0;
546 rc
= AFSVolListOneVolume(fromconn
, curDump
->partition
, curDump
->vid
,
550 updatedate
= volumeInfo
.volEntries_val
[0].updateDate
;
553 RWVOL
) ? time(0) : volumeInfo
.volEntries_val
[0].creationDate
);
555 /* Get the volume size (in KB) and increase by 25%. Then set as a hyper */
556 esize
= volumeInfo
.volEntries_val
[0].size
;
557 esize
+= (esize
/ 4) + 1;
559 if (curDump
->date
>= curDump
->cloneDate
)
560 ERROR_EXIT(0); /* not recloned since last dump */
561 if (curDump
->date
> updatedate
) {
562 dparamsPtr
->curVolumeStatus
= DUMP_NODUMP
; /* not modified since last dump */
566 /* Start a new XBSA Transaction */
567 rc
= xbsa_BeginTrans(&butxInfo
);
568 if (rc
!= XBSA_SUCCESS
) {
569 ErrorLog(1, taskId
, rc
, 0, "Unable to create a new transaction\n");
572 begindump
= 1; /* Will need to do an xbsa_EndTrans */
574 /* Start the volserver transaction and dump. Once started, the
575 * volume status is "partial dump". Also, the transaction with
576 * the volserver is idle until the first read. An idle transaction
577 * will time out in 600 seconds. After the first rx_Read,
578 * the transaction is not idle. See GCTrans().
580 rc
= AFSVolTransCreate(fromconn
, curDump
->vid
, curDump
->partition
, ITBusy
,
584 fromcall
= rx_NewCall(fromconn
);
586 rc
= StartAFSVolDump(fromcall
, fromtid
, curDump
->date
);
590 dparamsPtr
->curVolumeStatus
= DUMP_PARTIAL
;
591 dparamsPtr
->curVolStartPos
= tapeInfoPtr
->position
;
593 /* Tell XBSA what the name and size of volume to write */
594 snprintf(volumeNameStr
, sizeof(volumeNameStr
), "/%d/%s",
595 dparamsPtr
->databaseDumpId
, curDump
->name
);
596 hset32(estSize
, esize
);
597 hshlft(estSize
, 10); /* Multiply by 1024 so its in KB */
599 rc
= xbsa_WriteObjectBegin(&butxInfo
, butcdumpIdStr
, volumeNameStr
,
600 xbsalGName
, estSize
, dumpDescription
,
602 if (rc
!= XBSA_SUCCESS
) {
603 ErrorLog(1, taskId
, rc
, 0,
604 "Unable to begin writing of the fileset data to the server\n");
607 indump
= 1; /* Will need to do an xbsa_WriteObjectEnd */
609 /* Create and Write the volume header */
610 makeVolumeHeader(&hostVolumeHeader
, dparamsPtr
, 1);
611 hostVolumeHeader
.contd
= 0;
612 volumeHeader_hton(&hostVolumeHeader
, (struct volumeHeader
*)buffer
);
614 rc
= xbsa_WriteObjectData(&butxInfo
, buffer
,
615 sizeof(struct volumeHeader
), &bytesWritten
);
616 if (rc
!= XBSA_SUCCESS
) {
617 ErrorLog(1, taskId
, rc
, 0,
618 "Unable to write VolumeHeader data to the server\n");
621 /* There is a bug in the ADSM library where the bytesWritten is
622 * not filled in, so we set it as correct anyway.
624 bytesWritten
= sizeof(struct volumeHeader
);
625 if (bytesWritten
!= sizeof(struct volumeHeader
)) {
626 ErrorLog(1, taskId
, rc
, 0,
627 "The size of VolumeHeader written (%d) does not equal its actual size (%" AFS_SIZET_FMT
")\n",
628 bytesWritten
, sizeof(struct volumeHeader
));
629 ERROR_EXIT(TC_INTERNALERROR
);
632 incSize(tapeInfoPtr
, sizeof(struct volumeHeader
)); /* Increment amount we've written */
633 tsize
+= bytesWritten
;
635 /* Start reading volume data, rx_Read(), and dumping to the tape
636 * until we've dumped the entire volume (endofvolume == 1).
640 while (!endofvolume
) { /*w */
641 /* Check for abort in the middle of writing data */
642 if (volBytesRead
>= chunkSize
) {
643 chunkSize
+= BIGCHUNK
;
644 if (checkAbortByTaskId(taskId
))
645 ABORT_EXIT(TC_ABORTEDBYREQUEST
);
647 /* set bytes dumped for backup */
649 nodePtr
->statusNodePtr
->nKBytes
= tapeInfoPtr
->kBytes
;
653 /* Determine how much data to read in upcoming RX_Read() call */
656 /* Read some volume data. */
657 bytesread
= rx_Read(fromcall
, buffer
, toread
);
658 volBytesRead
+= bytesread
;
659 if (bytesread
!= toread
) {
662 /* Make sure were at end of volume and not a communication error */
663 rc
= rx_Error(fromcall
);
669 /* Create a volume trailer appending it to this data block (if not XBSA) */
670 makeVolumeHeader(&hostVolumeHeader
, dparamsPtr
, 1);
671 hostVolumeHeader
.contd
= 0;
672 hostVolumeHeader
.magic
= TC_VOLENDMAGIC
;
673 hostVolumeHeader
.endTime
= time(0);
674 volumeHeader_hton(&hostVolumeHeader
, (struct volumeHeader
*)&buffer
[bytesread
]);
675 bytesread
+= sizeof(hostVolumeHeader
);
677 /* End the dump and transaction with the volserver. We end it now, before
678 * we make the XBSA call because if XBSA blocks, we could time out on the
679 * volserver (After last read, the transaction with the volserver is idle).
681 rc
= rx_EndCall(fromcall
, 0);
686 rc
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
692 /* Write the datablock out */
693 rc
= xbsa_WriteObjectData(&butxInfo
, buffer
, bytesread
,
695 if (rc
!= XBSA_SUCCESS
) {
696 ErrorLog(1, taskId
, rc
, 0,
697 "Unable to write data to the server\n");
700 /* There is a bug in the ADSM library where the bytesWritten is
701 * not filled in, so we set it as correct anyway.
703 bytesWritten
= bytesread
;
704 if (bytesWritten
!= bytesread
) {
705 ErrorLog(1, taskId
, rc
, 0,
706 "The size of data written (%d) does not equal size read (%d)\n",
707 bytesWritten
, bytesread
);
708 ERROR_EXIT(TC_INTERNALERROR
);
711 incSize(tapeInfoPtr
, bytesread
); /* Increment amount we've written */
712 tsize
+= bytesWritten
;
714 /* Display a status line every statusSize or at end of volume */
715 if (statusSize
&& ((tsize
>= statuscount
) || endofvolume
)) {
718 localtime_r(&t
, &tm
);
719 printf("%02d:%02d:%02d: Task %u: %u KB: %s: %u B\n", tm
.tm_hour
,
720 tm
.tm_min
, tm
.tm_sec
, taskId
, tapeInfoPtr
->kBytes
,
721 hostVolumeHeader
.volumeName
, tsize
);
722 statuscount
= tsize
+ statusSize
;
726 /* End the XBSA transaction before recording it in BUDB as successfully dumped */
727 rc
= xbsa_WriteObjectEnd(&butxInfo
);
729 if (rc
!= XBSA_SUCCESS
) {
730 ErrorLog(1, taskId
, rc
, 0,
731 "Unable to terminate writing of the volume data to the server");
734 rc
= xbsa_EndTrans(&butxInfo
);
736 tapeInfoPtr
->position
++;
737 if (rc
!= XBSA_SUCCESS
) {
738 ErrorLog(1, taskId
, rc
, 0,
739 "Unable to terminate the current transaction");
743 /* Record in BUDB the volume fragment as succcessfully dumped */
744 rc
= addVolume(0, dparamsPtr
->databaseDumpId
, dparamsPtr
->tapeName
,
745 nodePtr
->dumps
[dparamsPtr
->curVolume
].name
,
746 nodePtr
->dumps
[dparamsPtr
->curVolume
].vid
,
747 nodePtr
->dumps
[dparamsPtr
->curVolume
].cloneDate
,
748 dparamsPtr
->curVolStartPos
, volBytesRead
, 0 /*frag0 */ ,
749 (BUDB_VOL_FIRSTFRAG
| BUDB_VOL_LASTFRAG
));
753 dparamsPtr
->curVolumeStatus
= DUMP_SUCCESS
;
756 /* Cleanup after an error occurs part way into a volume dump */
758 rc
= rx_EndCall(fromcall
, 0);
765 rc
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
767 code
= (rc
? rc
: rcode
);
770 /* If this dump failed, what happens to successive retries
771 * of the volume? How do they get recorded in the XBSA database
772 * (overwritten)? If not, we don't record this in the BUDB database
773 * so it will not be removed when we delete the dump. What to do?
774 * Also if the volume was never recorded in the DB (partial dump).
778 rc
= xbsa_WriteObjectEnd(&butxInfo
);
780 if (rc
!= XBSA_SUCCESS
) {
781 ErrorLog(1, taskId
, rc
, 0,
782 "Unable to terminate writing of the volume data to the server");
784 tapeInfoPtr
->position
++;
788 /* End the XBSA Transaction */
789 rc
= xbsa_EndTrans(&butxInfo
);
791 if (rc
!= XBSA_SUCCESS
) {
792 ErrorLog(1, taskId
, rc
, 0,
793 "Unable to terminate the current transaction");
800 dparamsPtr
->curVolumeStatus
= DUMP_FAILED
;
807 #define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr
810 * Go through the list of volumes to dump, dumping each one. The action
811 * taken when a volume dump fails, depends on the passNumber. At minimum,
812 * the failed volume is remembered.
814 * flushSavedEntries - inconsistent treatment for errors. What should
815 * be done for user aborts?
819 dumpPass(struct dumpRock
* dparamsPtr
, int passNumber
)
821 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
822 struct butm_tapeInfo
*tapeInfoPtr
= dparamsPtr
->tapeInfoPtr
;
823 afs_int32 taskId
= nodePtr
->taskID
;
824 struct tc_dumpDesc
*curDump
;
826 afs_int32 code
= 0, tcode
, dvcode
;
828 struct vldbentry vldbEntry
;
829 struct sockaddr_in server
;
832 TapeLog(2, taskId
, 0, 0, "Starting pass %d\n", passNumber
);
834 /* while there are more volumes to dump */
835 for (dparamsPtr
->curVolume
= 0; dparamsPtr
->curVolume
< nodePtr
->arraySize
; dparamsPtr
->curVolume
++) { /*w */
836 curDump
= &nodePtr
->dumps
[dparamsPtr
->curVolume
];
837 if (curDump
->hostAddr
== 0)
840 /* set name of current volume being dumped */
842 strcpy(nodePtr
->statusNodePtr
->volumeName
, curDump
->name
);
845 /* Determine location of the volume.
846 * In case the volume moved has moved.
848 if (passNumber
> 1) { /*pass */
850 bc_GetEntryByID(cstruct
, curDump
->vid
, curDump
->vtype
,
853 ErrorLog(0, taskId
, tcode
, 0,
854 "Volume %s (%u) failed - Can't find volume in VLDB\n",
855 curDump
->name
, curDump
->vid
);
856 curDump
->hostAddr
= 0;
857 dparamsPtr
->volumesFailed
++;
861 switch (curDump
->vtype
) {
863 if (!(vldbEntry
.flags
& VLF_BACKEXISTS
)) {
864 ErrorLog(0, taskId
, 0, 0,
865 "Volume %s (%u) failed - Backup volume no longer exists\n",
866 curDump
->name
, curDump
->vid
);
867 curDump
->hostAddr
= 0;
868 dparamsPtr
->volumesFailed
++;
871 /* Fall into RWVOL case */
874 for (e
= 0; e
< vldbEntry
.nServers
; e
++) { /* Find the RW volume */
875 if (vldbEntry
.serverFlags
[e
] & VLSF_RWVOL
)
881 /* Try to use the server and partition we found the volume on
882 * Otherwise, use the first RO volume.
884 for (e
= 0; e
< vldbEntry
.nServers
; e
++) { /* Find the RO volume */
885 if ((curDump
->hostAddr
== vldbEntry
.serverNumber
[e
])
886 && (curDump
->partition
==
887 vldbEntry
.serverPartition
[e
]))
891 if (e
>= vldbEntry
.nServers
) { /* Didn't find RO volume */
892 for (e
= 0; e
< vldbEntry
.nServers
; e
++) { /* Find the first RO volume */
893 if (vldbEntry
.serverFlags
[e
] & VLSF_ROVOL
)
900 ErrorLog(0, taskId
, 0, 0,
901 "Volume %s (%u) failed - Unknown volume type\n",
902 curDump
->name
, curDump
->vid
);
903 curDump
->hostAddr
= 0;
907 if (e
>= vldbEntry
.nServers
) {
908 ErrorLog(0, taskId
, 0, 0,
909 "Volume %s (%u) failed - Can't find volume entry in VLDB\n",
910 curDump
->name
, curDump
->vid
);
911 curDump
->hostAddr
= 0;
912 dparamsPtr
->volumesFailed
++;
916 /* Remember the server and partition the volume exists on */
917 memset(&server
, 0, sizeof(server
));
918 server
.sin_addr
.s_addr
= vldbEntry
.serverNumber
[e
];
920 server
.sin_family
= AF_INET
;
921 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
922 server
.sin_len
= sizeof(struct sockaddr_in
);
924 curDump
->hostAddr
= HOSTADDR(&server
);
925 curDump
->partition
= vldbEntry
.serverPartition
[e
];
927 /* Determine date from which to do an incremental dump
929 if (nodePtr
->parent
) {
931 bcdb_FindClone(nodePtr
->parent
, curDump
->name
,
936 curDump
->date
= 0; /* do a full dump */
940 if (checkAbortByTaskId(taskId
))
941 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
943 /* Establish connection to volume - UV_ routine expects
944 * host address in network order
947 dvcode
= xbsaDumpVolume(curDump
, dparamsPtr
);
949 dvcode
= dumpVolume(curDump
, dparamsPtr
);
951 action
= dparamsPtr
->curVolumeStatus
;
953 /* Flush volume and tape entries to the database */
954 tcode
= flushSavedEntries(action
);
960 TapeLog(1, taskId
, 0, 0, "Volume %s (%u) successfully dumped\n",
961 curDump
->name
, curDump
->vid
);
963 ErrorLog(1, taskId
, dvcode
, 0,
964 "Warning: Termination processing error on volume %s (%u)\n",
965 curDump
->name
, curDump
->vid
);
967 curDump
->hostAddr
= 0;
968 dparamsPtr
->volumesDumped
++;
973 if (action
== DUMP_PARTIAL
) {
974 ErrorLog(1, taskId
, dvcode
, 0,
975 "Volume %s (%u) failed - partially dumped\n",
976 curDump
->name
, curDump
->vid
);
978 ErrorLog(0, taskId
, dvcode
, 0, "Volume %s (%u) failed\n",
979 curDump
->name
, curDump
->vid
);
981 ErrorLog(0, taskId
, dvcode
, 0,
982 "Volume %s (%u) not dumped - has not been re-cloned since last dump\n",
983 curDump
->name
, curDump
->vid
);
986 if (passNumber
== maxpass
) {
990 ch
= retryPrompt(curDump
->name
, curDump
->vid
, taskId
);
993 case 'r': /* retry */
994 dparamsPtr
->curVolume
--; /* redump this volume */
997 ErrorLog(1, taskId
, 0, 0, "Volume %s (%u) omitted\n",
998 curDump
->name
, curDump
->vid
);
999 dparamsPtr
->volumesFailed
++;
1001 case 'a': /* abort */
1002 TapeLog(1, taskId
, 0, 0, "Dump aborted\n");
1003 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1006 ERROR_EXIT(TC_INTERNALERROR
);
1013 TapeLog(1, taskId
, dvcode
, 0,
1014 "Volume %s (%u) hit end-of-tape inferred - will retry on next tape\n",
1015 curDump
->name
, curDump
->vid
);
1017 /* Get the next tape */
1018 unmountTape(taskId
, tapeInfoPtr
);
1020 dparamsPtr
->tapeSeq
++;
1021 tcode
= getDumpTape(dparamsPtr
, 1, 0); /* interactive - no appends */
1025 dparamsPtr
->curVolume
--; /* redump this volume */
1028 case DUMP_NORETRYEOT
:
1029 ErrorLog(1, taskId
, 0, 0,
1030 "Volume %s (%u) failed - volume larger than tape\n",
1031 curDump
->name
, curDump
->vid
);
1033 /* rewrite the label on the tape - rewind - no need to switch tapes */
1034 tcode
= butm_Create(tapeInfoPtr
, &dparamsPtr
->tapeLabel
, 1);
1036 ErrorLog(0, taskId
, tcode
, tapeInfoPtr
->error
,
1037 "Can't relabel tape\n");
1039 unmountTape(taskId
, tapeInfoPtr
);
1040 tcode
= getDumpTape(dparamsPtr
, 1, 0); /* interactive - no appends */
1043 } else { /* Record the tape in database */
1044 tapepos
= tapeInfoPtr
->position
;
1046 useTape(&dparamsPtr
->tape
, dparamsPtr
->databaseDumpId
,
1047 dparamsPtr
->tapeName
,
1048 (dparamsPtr
->tapeSeq
+ dparamsPtr
->dump
.tapes
.b
),
1049 dparamsPtr
->tapeLabel
.useCount
,
1050 dparamsPtr
->tapeLabel
.creationTime
,
1051 dparamsPtr
->tapeLabel
.expirationDate
, tapepos
);
1054 curDump
->hostAddr
= 0;
1055 dparamsPtr
->volumesFailed
++;
1059 TapeLog(1, taskId
, dvcode
, 0,
1060 "Volume %s (%u) not dumped - has not been modified since last dump\n",
1061 curDump
->name
, curDump
->vid
);
1063 curDump
->hostAddr
= 0;
1064 dparamsPtr
->volumesNotDumped
++;
1068 ErrorLog(1, taskId
, dvcode
, 0, "Volume %s (%u) failed\n",
1069 curDump
->name
, curDump
->vid
);
1076 /* check if we terminated while processing a volume */
1077 if (dparamsPtr
->curVolume
< nodePtr
->arraySize
) {
1078 TapeLog(2, taskId
, 0, 0,
1079 "Terminated while processing Volume %s (%u)\n", curDump
->name
,
1083 /* print a summary of this pass */
1084 TapeLog(2, taskId
, 0, 0, "End of pass %d: Volumes remaining = %d\n",
1086 nodePtr
->arraySize
- (dparamsPtr
->volumesDumped
+
1087 dparamsPtr
->volumesFailed
+
1088 dparamsPtr
->volumesNotDumped
));
1095 struct dumpNode
*nodePtr
= (struct dumpNode
*)param
;
1096 struct dumpRock dparams
;
1097 struct butm_tapeInfo tapeInfo
;
1103 /* for volume setup */
1105 int failedvolumes
= 0;
1106 int dumpedvolumes
= 0;
1107 int nodumpvolumes
= 0;
1110 char finishedMsg1
[128];
1111 char finishedMsg2
[128];
1112 time_t startTime
= 0;
1114 afs_int32 allocbufferSize
;
1116 extern struct deviceSyncNode
*deviceLatch
;
1117 extern struct tapeConfig globalTapeConfig
;
1119 afs_pthread_setname_self("dumper");
1120 taskId
= nodePtr
->taskID
; /* Get task Id */
1121 setStatus(taskId
, DRIVE_WAIT
);
1122 EnterDeviceQueue(deviceLatch
);
1123 clearStatus(taskId
, DRIVE_WAIT
);
1126 TapeLog(2, taskId
, 0, 0, "Dump %s\n", nodePtr
->dumpSetName
);
1128 /* setup the dump parameters */
1129 memset(&dparams
, 0, sizeof(dparams
));
1130 dparams
.node
= nodePtr
;
1131 dparams
.tapeInfoPtr
= &tapeInfo
;
1132 dlqInit(&savedEntries
);
1135 /* Instantiate the tape module */
1136 tapeInfo
.structVersion
= BUTM_MAJORVERSION
;
1137 code
= butm_file_Instantiate(&tapeInfo
, &globalTapeConfig
);
1139 ErrorLog(0, taskId
, code
, tapeInfo
.error
,
1140 "Can't initialize the tape module\n");
1145 /* check if abort requested while waiting on device latch */
1146 if (checkAbortByTaskId(taskId
))
1147 ERROR_EXIT(TC_ABORTEDBYREQUEST
);
1149 /* Are there volumes to dump */
1150 if (nodePtr
->arraySize
== 0) {
1151 TLog(taskId
, "Dump (%s), no volumes to dump\n", nodePtr
->dumpSetName
);
1155 /* Allocate a buffer for the dumps. Leave room for header and vol-trailer.
1156 * dataSize is amount of data to read in each rx_Read() call.
1159 /* XBSA dumps have not header */
1160 dataSize
= BufferSize
;
1161 allocbufferSize
= dataSize
+ sizeof(struct volumeHeader
);
1163 tapeblocks
= BufferSize
/ BUTM_BLOCKSIZE
; /* # of 16K tapeblocks */
1164 dataSize
= (tapeblocks
* BUTM_BLKSIZE
);
1166 BUTM_HDRSIZE
+ dataSize
+ sizeof(struct volumeHeader
);
1169 bufferBlock
= malloc(allocbufferSize
);
1171 ErrorLog(0, taskId
, TC_NOMEMORY
, 0,
1172 "Can't allocate BUFFERSIZE for dumps\n");
1173 ERROR_EXIT(TC_NOMEMORY
);
1176 /* Determine the dumpid of the most recent dump of this volumeset and dumplevel
1177 * Used when requesting a tape. Done now because once we create the dump, the
1178 * routine will then find the newly created dump.
1180 snprintf(strlevel
, sizeof(strlevel
), "%d", nodePtr
->level
);
1182 bcdb_FindLatestDump(nodePtr
->volumeSetName
, strlevel
,
1185 if (code
!= BUDB_NODUMPNAME
) {
1186 ErrorLog(0, taskId
, code
, 0, "Can't read backup database\n");
1189 memset(&dparams
.lastDump
, 0, sizeof(dparams
.lastDump
));
1192 code
= createDump(&dparams
); /* enter dump into database */
1194 ErrorLog(0, taskId
, code
, 0, "Can't create dump in database\n");
1198 TLog(taskId
, "Dump %s (DumpID %u)\n", nodePtr
->dumpSetName
,
1199 dparams
.databaseDumpId
);
1202 /* mount the tape and write its label */
1203 code
= getDumpTape(&dparams
, autoQuery
, nodePtr
->doAppend
);
1205 /* Create a dummy tape to satisfy backup databae */
1206 code
= getXBSATape(&dparams
);
1207 tapeInfo
.position
= 1;
1210 /* If didn't write the label, remove dump from the database */
1211 if (!dparams
.wroteLabel
) {
1212 i
= bcdb_deleteDump(dparams
.databaseDumpId
, 0, 0, 0);
1213 if (i
&& (i
!= BUDB_NOENT
))
1214 ErrorLog(1, taskId
, i
, 0,
1215 "Warning: Can't delete dump %u from database\n",
1216 dparams
.databaseDumpId
);
1218 dparams
.databaseDumpId
= 0;
1220 ERROR_EXIT(code
); /* exit with code from getTape */
1223 startTime
= time(0);
1224 for (pass
= 1; pass
<= maxpass
; pass
++) {
1225 lastPass
= (pass
== maxpass
);
1226 code
= dumpPass(&dparams
, pass
);
1230 /* if no failed volumes, we're done */
1231 if ((dparams
.volumesDumped
+ dparams
.volumesFailed
+
1232 dparams
.volumesNotDumped
) == nodePtr
->arraySize
)
1237 * Log the error but ignore it since the dump is effectively done.
1238 * Scantape may assume another volume and ask for next tape.
1241 code
= butm_WriteEOT(&tapeInfo
);
1243 TapeLog(0, taskId
, code
, tapeInfo
.error
,
1244 "Warning: Can't write end-of-dump on tape\n");
1248 finishTape(&dparams
.tape
,
1249 dparams
.tapeInfoPtr
->kBytes
+
1250 (dparams
.tapeInfoPtr
->nBytes
? 1 : 0));
1254 code
= finishDump(&dparams
.dump
);
1258 action
= dparams
.curVolumeStatus
;
1259 code
= flushSavedEntries(action
);
1270 unmountTape(taskId
, &tapeInfo
);
1274 dumpedvolumes
= dparams
.volumesDumped
;
1275 nodumpvolumes
= dparams
.volumesNotDumped
;
1276 failedvolumes
= nodePtr
->arraySize
- (dumpedvolumes
+ nodumpvolumes
);
1278 /* pass back the number of volumes we failed to dump */
1280 nodePtr
->statusNodePtr
->volsFailed
= failedvolumes
;
1283 lastPass
= 1; /* In case we aborted */
1285 /* Format and log finished message. */
1286 snprintf(finishedMsg1
, sizeof(finishedMsg1
), "%s", nodePtr
->dumpSetName
);
1287 if (dparams
.databaseDumpId
!= 0) {
1288 snprintf(msg
, sizeof(msg
), " (DumpId %u)", dparams
.databaseDumpId
);
1289 strlcat(finishedMsg1
, msg
, sizeof(finishedMsg1
));
1291 snprintf(finishedMsg2
, sizeof(finishedMsg2
),
1292 "%d volumes dumped", dumpedvolumes
);
1293 if (failedvolumes
) {
1294 snprintf(msg
, sizeof(msg
), ", %d failed", failedvolumes
);
1295 strlcat(finishedMsg2
, msg
, sizeof(finishedMsg2
));
1297 if (nodumpvolumes
) {
1298 snprintf(msg
, sizeof(msg
), ", %d unchanged", nodumpvolumes
);
1299 strlcat(finishedMsg2
, msg
, sizeof(finishedMsg2
));
1302 if (code
== TC_ABORTEDBYREQUEST
) {
1303 ErrorLog(0, taskId
, 0, 0, "%s: Aborted by request. %s\n",
1304 finishedMsg1
, finishedMsg2
);
1305 clearStatus(taskId
, ABORT_REQUEST
);
1306 setStatus(taskId
, ABORT_DONE
);
1308 ErrorLog(0, taskId
, code
, 0, "%s: Finished with errors. %s\n",
1309 finishedMsg1
, finishedMsg2
);
1310 setStatus(taskId
, TASK_ERROR
);
1312 TLog(taskId
, "%s: Finished. %s\n", finishedMsg1
, finishedMsg2
);
1316 /* Record how long the dump took */
1317 if (centralLogIO
&& startTime
) {
1319 afs_int32 hrs
, min
, sec
, tmp
;
1321 struct tm tmstart
, tmend
;
1323 localtime_r(&startTime
, &tmstart
);
1324 localtime_r(&endTime
, &tmend
);
1325 timediff
= (int)endTime
- (int)startTime
;
1326 hrs
= timediff
/ 3600;
1327 tmp
= timediff
% 3600;
1331 code
= asprintf(&line
,
1332 "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1333 "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d "
1334 "%s %d of %d volumes dumped (%lu KB)\n", taskId
,
1335 tmstart
.tm_mon
+ 1, tmstart
.tm_mday
, tmstart
.tm_year
+ 1900,
1336 tmstart
.tm_hour
, tmstart
.tm_min
, tmstart
.tm_sec
,
1337 tmend
.tm_mon
+ 1, tmend
.tm_mday
, tmend
.tm_year
+ 1900,
1338 tmend
.tm_hour
, tmend
.tm_min
, tmend
.tm_sec
, hrs
, min
, sec
,
1339 nodePtr
->volumeSetName
, dumpedvolumes
,
1340 dumpedvolumes
+ failedvolumes
,
1341 afs_printable_uint32_lu(dparams
.tapeInfoPtr
->kBytes
+ 1));
1345 fwrite(line
, strlen(line
), 1, centralLogIO
);
1346 fflush(centralLogIO
);
1351 setStatus(taskId
, TASK_DONE
);
1353 FreeNode(taskId
); /* free the dump node */
1354 LeaveDeviceQueue(deviceLatch
);
1355 return (void *)(intptr_t)(code
);
1358 #define BELLTIME 60 /* 60 seconds before a bell rings */
1359 #define BELLCHAR 7 /* ascii for bell */
1362 * prompt the user to decide how to handle a failed volume dump. The
1363 * volume parameters describe the volume that failed
1365 * volumeName - name of volume
1366 * volumeId - volume id
1367 * taskId - for job contrl
1369 * character typed by user, one of r, o or a
1373 retryPrompt(char *volumeName
, afs_int32 volumeId
, afs_uint32 taskId
)
1379 setStatus(taskId
, OPR_WAIT
);
1380 printf("\nDump of volume %s (%u) failed\n\n", volumeName
, volumeId
);
1382 printf("Please select action to be taken for this volume\n");
1385 printf("r - retry, try dumping this volume again\n");
1386 printf("o - omit, this volume from this dump\n");
1387 printf("a - abort, the entire dump\n");
1396 code
= LWP_GetResponseKey(5, &ch
); /* ch stores key pressed */
1398 break; /* input is available */
1400 if (checkAbortByTaskId(taskId
)) {
1401 clearStatus(taskId
, OPR_WAIT
);
1403 ("This tape operation has been aborted by the coordinator\n");
1407 if (time(0) > start
+ BELLTIME
)
1410 /* otherwise, we should beep again, check for abort and go back,
1411 * since the GetResponseKey() timed out.
1414 break; /* input is available */
1416 clearStatus(taskId
, OPR_WAIT
);
1417 if (ch
!= 'r' && ch
!= 'o' && ch
!= 'a') {
1418 printf("Please select one of the 3 options, r, o or a\n");
1425 /* For testing: it prints the tape label */
1427 printTapeLabel(struct butm_tapeLabel
*tl
)
1429 printf("Tape Label\n");
1430 printf(" structVersion = %d\n", tl
->structVersion
);
1431 printf(" creationTime = %u\n", tl
->creationTime
);
1432 printf(" expirationDate = %u\n", tl
->expirationDate
);
1433 printf(" AFSName = %s\n", tl
->AFSName
);
1434 printf(" cell = %s\n", tl
->cell
);
1435 printf(" dumpid = %d\n", tl
->dumpid
);
1436 printf(" useCount = %d\n", tl
->useCount
);
1437 printf(" comment = %s\n", tl
->comment
);
1438 printf(" pName = %s\n", tl
->pName
);
1439 printf(" size = %u\n", tl
->size
);
1440 printf(" dumpPath = %s\n", tl
->dumpPath
);
1445 * Create a tape structure to be satisfy the backup database
1446 * even though we don't really use a tape with XBSA.
1449 getXBSATape(struct dumpRock
*dparamsPtr
)
1451 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
1452 struct butm_tapeInfo
*tapeInfoPtr
= dparamsPtr
->tapeInfoPtr
;
1453 struct butm_tapeLabel
*tapeLabelPtr
= &dparamsPtr
->tapeLabel
;
1456 tc_MakeTapeName(dparamsPtr
->tapeName
, &nodePtr
->tapeSetDesc
,
1457 dparamsPtr
->tapeSeq
);
1459 GetNewLabel(tapeInfoPtr
, "" /*pName */ , dparamsPtr
->tapeName
,
1461 strcpy(tapeLabelPtr
->dumpPath
, nodePtr
->dumpName
);
1462 tapeLabelPtr
->dumpid
= dparamsPtr
->databaseDumpId
;
1463 tapeLabelPtr
->expirationDate
=
1464 calcExpirationDate(nodePtr
->tapeSetDesc
.expType
,
1465 nodePtr
->tapeSetDesc
.expDate
, time(0));
1467 /* printTapeLabel(tapeLabelPtr); For testing */
1470 useTape(&dparamsPtr
->tape
, dparamsPtr
->databaseDumpId
,
1471 dparamsPtr
->tapeName
,
1472 (dparamsPtr
->tapeSeq
+ dparamsPtr
->dump
.tapes
.b
),
1473 tapeLabelPtr
->useCount
, tapeLabelPtr
->creationTime
,
1474 tapeLabelPtr
->expirationDate
, 0 /*tape position */ );
1479 * iterate until the desired tape (as specified by the dump structures)
1483 * 0 - assume the tape is there. Prompt if assumption false
1484 * 1 - prompt regardless
1488 getDumpTape(struct dumpRock
*dparamsPtr
, int interactiveFlag
,
1491 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
1492 struct butm_tapeInfo
*tapeInfoPtr
= dparamsPtr
->tapeInfoPtr
;
1493 struct butm_tapeLabel
*newTapeLabelPtr
= &dparamsPtr
->tapeLabel
;
1494 char AFSTapeName
[TC_MAXTAPENAMELEN
];
1495 afs_int32 taskId
= nodePtr
->taskID
;
1496 struct butm_tapeLabel oldTapeLabel
;
1497 struct budb_dumpEntry dumpEntry
;
1498 struct budb_tapeEntry tapeEntry
;
1499 struct budb_volumeEntry volEntry
;
1506 afs_int32 tapepos
, lastpos
;
1508 extern struct tapeConfig globalTapeConfig
;
1510 askForTape
= interactiveFlag
;
1511 dparamsPtr
->wroteLabel
= 0;
1513 /* Keep prompting for a tape until we get it right */
1515 /* What the name of the tape would be if not appending to it */
1516 tc_MakeTapeName(AFSTapeName
, &nodePtr
->tapeSetDesc
,
1517 dparamsPtr
->tapeSeq
);
1523 PromptForTape((doAppend
? APPENDOPCODE
: WRITEOPCODE
),
1524 AFSTapeName
, dparamsPtr
->databaseDumpId
, taskId
,
1532 /* open the tape device */
1533 code
= butm_Mount(tapeInfoPtr
, AFSTapeName
);
1535 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
, "Can't open tape\n");
1539 /* Read the tape label */
1540 code
= butm_ReadLabel(tapeInfoPtr
, &oldTapeLabel
, 1); /* rewind */
1542 if (tapeInfoPtr
->error
) {
1543 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
1544 "Warning: Tape error while reading label (will proceed with dump)\n");
1546 memset(&oldTapeLabel
, 0, sizeof(oldTapeLabel
));
1549 /* Check if null tape. Prior 3.3, backup tapes have no dump id */
1550 if ((strcmp(oldTapeLabel
.AFSName
, "") == 0)
1551 && (oldTapeLabel
.dumpid
== 0)) {
1554 "Dump not found on tape. Proceeding with initial dump\n");
1557 } else if (doAppend
) { /* appending */
1558 /* Check that we don't have a database dump tape */
1559 if (databaseTape(oldTapeLabel
.AFSName
)) {
1560 char gotName
[BU_MAXTAPELEN
+ 32];
1562 /* label does not match */
1563 LABELNAME(gotName
, &oldTapeLabel
);
1564 TLog(taskId
, "Can't append to database tape %s\n", gotName
);
1568 /* Verify that the tape is of version 4 (AFS 3.3) or greater */
1569 if (oldTapeLabel
.structVersion
< TAPE_VERSION_4
) {
1571 "Can't append: requires tape version %d or greater\n",
1576 /* Verify that the last tape of the dump set is in the drive.
1577 * volEntry will be zeroed if last dump has no volume entries.
1580 bcdb_FindLastTape(oldTapeLabel
.dumpid
, &dumpEntry
, &tapeEntry
,
1583 ErrorLog(0, taskId
, code
, 0,
1584 "Can't append: Can't find last volume of dumpId %u in database\n",
1585 oldTapeLabel
.dumpid
);
1586 printf("Please scan the dump in or choose another tape\n");
1590 (volEntry
.position
? volEntry
.position
: tapeEntry
.labelpos
);
1592 if (strcmp(TNAME(&oldTapeLabel
), tapeEntry
.name
)) {
1593 char expName
[BU_MAXTAPELEN
+ 32], gotName
[BU_MAXTAPELEN
+ 32];
1595 TAPENAME(expName
, tapeEntry
.name
, oldTapeLabel
.dumpid
);
1596 LABELNAME(gotName
, &oldTapeLabel
);
1599 "Can't append: Last tape in dump-set is %s, label seen %s\n",
1604 /* After reading the tape label, we now know what it is */
1605 strcpy(AFSTapeName
, oldTapeLabel
.AFSName
); /* the real name */
1606 strcpy(tapeInfoPtr
->name
, oldTapeLabel
.AFSName
); /* the real name */
1608 /* Position after last volume on the tape */
1609 code
= butm_SeekEODump(tapeInfoPtr
, lastpos
);
1611 ErrorLog(0, taskId
, code
, tapeInfoPtr
->error
,
1612 "Can't append: Can't position to end of dump on tape %s\n",
1617 /* Track size of tape - set after seek since seek changes the value */
1618 tapeInfoPtr
->kBytes
= tapeEntry
.useKBytes
;
1619 } else { /* not appending */
1623 struct budb_dumpEntry de
, de2
;
1625 /* Check if tape name is not what expected - null tapes are acceptable
1626 * Don't do check if the tape has a user defined label.
1628 if (dump_namecheck
&& (strcmp(oldTapeLabel
.pName
, "") == 0)) {
1629 if (strcmp(oldTapeLabel
.AFSName
, "") && /* not null tape */
1630 strcmp(oldTapeLabel
.AFSName
, AFSTapeName
)) { /* not expected name */
1631 TLog(taskId
, "Tape label expected %s, label seen %s\n",
1632 AFSTapeName
, oldTapeLabel
.AFSName
);
1636 /* Check that we don't have a database dump tape */
1637 if (databaseTape(oldTapeLabel
.AFSName
)) {
1638 /* label does not match */
1640 "Tape label expected %s, can't dump to database tape %s\n",
1641 AFSTapeName
, oldTapeLabel
.AFSName
);
1646 /* Verify the tape has not expired - only check if not appending */
1647 if (!tapeExpired(&oldTapeLabel
)) {
1648 TLog(taskId
, "This tape has not expired\n");
1652 /* Given a tape dump with good data, verify we don't overwrite recent dumps
1653 * and also verify that the volume will be restorable - if not print warnings
1655 if (oldTapeLabel
.dumpid
) {
1656 /* Do not overwrite a tape that belongs to the dump's dumpset */
1658 (dparamsPtr
->initialDumpId
? dparamsPtr
->
1659 initialDumpId
: dparamsPtr
->databaseDumpId
);
1660 if (oldTapeLabel
.dumpid
== tapeid
) {
1661 ErrorLog(0, taskId
, 0, 0,
1662 "Can't overwrite tape containing the dump in progress\n");
1666 /* Since the dumpset on this tape will be deleted from database, check if
1667 * any of the dump's parent-dumps are on this tape.
1669 for (dmp
= nodePtr
->parent
; dmp
; dmp
= de
.parent
) {
1670 code
= bcdb_FindDumpByID(dmp
, &de
);
1672 ErrorLog(0, taskId
, 0, 0,
1673 "Warning: Can't find parent dump %u in backup database\n",
1678 tapeid
= (de
.initialDumpID
? de
.initialDumpID
: de
.id
);
1679 if (oldTapeLabel
.dumpid
== tapeid
) {
1680 ErrorLog(0, taskId
, 0, 0,
1681 "Can't overwrite the parent dump %s (DumpID %u)\n",
1687 /* Since the dumpset on this tape will be deleted from database, check if
1688 * any of the dumps in this dumpset are most-recent-dumps.
1690 for (dmp
= oldTapeLabel
.dumpid
; dmp
; dmp
= de
.appendedDumpID
) {
1691 if (dmp
== dparamsPtr
->lastDump
.id
) {
1692 memcpy(&de
, &dparamsPtr
->lastDump
, sizeof(de
));
1693 memcpy(&de2
, &dparamsPtr
->lastDump
, sizeof(de2
));
1695 code
= bcdb_FindDumpByID(dmp
, &de
);
1698 snprintf(strlevel
, sizeof(strlevel
), "%d", de
.level
);
1700 bcdb_FindLatestDump(de
.volumeSetName
, strlevel
,
1706 /* If dump on the tape is the latest dump at this level */
1707 if (de
.id
== de2
.id
) {
1708 if (strcmp(DUMP_TAPE_NAME
, de2
.name
) == 0) {
1709 ErrorLog(0, taskId
, 0, 0,
1710 "Warning: Overwriting most recent dump %s (DumpID %u)\n",
1713 ErrorLog(0, taskId
, 0, 0,
1714 "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
1715 de
.volumeSetName
, de
.name
, de
.id
);
1719 } /* if (oldTapeLabel.dumpid) */
1720 } /* else not appending */
1723 * Now have the right tape. Create a new label for the tape
1724 * Appended labels have the dump's dumpId - labels at beginnings of
1725 * tape have the initial dump's dumpId.
1726 * Appended labels do not increment the useCount.
1727 * Labels at beginnings of tape use the most future expiration of the dump set.
1729 GetNewLabel(tapeInfoPtr
, oldTapeLabel
.pName
, AFSTapeName
,
1731 strcpy(newTapeLabelPtr
->dumpPath
, nodePtr
->dumpName
);
1732 newTapeLabelPtr
->expirationDate
=
1733 calcExpirationDate(nodePtr
->tapeSetDesc
.expType
,
1734 nodePtr
->tapeSetDesc
.expDate
, time(0));
1735 newTapeLabelPtr
->dumpid
= dparamsPtr
->databaseDumpId
;
1736 newTapeLabelPtr
->useCount
= oldTapeLabel
.useCount
;
1739 newTapeLabelPtr
->useCount
++;
1740 if (dparamsPtr
->initialDumpId
) {
1741 newTapeLabelPtr
->dumpid
= dparamsPtr
->initialDumpId
;
1742 expir
= ExpirationDate(dparamsPtr
->initialDumpId
);
1743 if (expir
> newTapeLabelPtr
->expirationDate
)
1744 newTapeLabelPtr
->expirationDate
= expir
;
1748 /* write the label on the tape - rewind if not appending and vice-versa */
1749 code
= butm_Create(tapeInfoPtr
, newTapeLabelPtr
, !doAppend
);
1751 char gotName
[BU_MAXTAPELEN
+ 32];
1753 LABELNAME(gotName
, newTapeLabelPtr
);
1754 TapeLog(0, taskId
, code
, tapeInfoPtr
->error
,
1755 "Can't label tape as %s\n", gotName
);
1758 dparamsPtr
->wroteLabel
= 1; /* Remember we wrote the label */
1759 tapepos
= tapeInfoPtr
->position
- 1;
1761 strcpy(dparamsPtr
->tapeName
, TNAME(newTapeLabelPtr
));
1763 /* If appending, set dumpentry in the database as appended. */
1765 char gotName
[BU_MAXTAPELEN
+ 32];
1767 nodePtr
->tapeSetDesc
.b
= extractTapeSeq(AFSTapeName
);
1768 dparamsPtr
->dump
.tapes
.b
= nodePtr
->tapeSetDesc
.b
;
1769 dparamsPtr
->initialDumpId
= oldTapeLabel
.dumpid
;
1770 strcpy(nodePtr
->tapeSetDesc
.format
, dumpEntry
.tapes
.format
);
1773 bcdb_MakeDumpAppended(dparamsPtr
->databaseDumpId
,
1774 dparamsPtr
->initialDumpId
,
1775 nodePtr
->tapeSetDesc
.b
);
1777 ErrorLog(2, taskId
, code
, 0,
1778 "Warning: Can't append dump %u to dump %u in database\n",
1779 dparamsPtr
->databaseDumpId
,
1780 dparamsPtr
->initialDumpId
);
1782 LABELNAME(gotName
, &oldTapeLabel
);
1783 TLog(taskId
, "Appending dump %s (DumpID %u) to tape %s\n",
1784 nodePtr
->dumpSetName
, dparamsPtr
->databaseDumpId
, gotName
);
1787 /* If not appending, delete overwritten dump from the database */
1789 if ((oldTapeLabel
.structVersion
>= TAPE_VERSION_3
)
1790 && oldTapeLabel
.dumpid
) {
1791 code
= bcdb_deleteDump(oldTapeLabel
.dumpid
, 0, 0, 0);
1792 if (code
&& (code
!= BUDB_NOENT
))
1793 ErrorLog(0, taskId
, code
, 0,
1794 "Warning: Can't delete old dump %u from database\n",
1795 oldTapeLabel
.dumpid
);
1800 useTape(&dparamsPtr
->tape
, dparamsPtr
->databaseDumpId
,
1801 dparamsPtr
->tapeName
,
1802 (dparamsPtr
->tapeSeq
+ dparamsPtr
->dump
.tapes
.b
),
1803 newTapeLabelPtr
->useCount
, newTapeLabelPtr
->creationTime
,
1804 newTapeLabelPtr
->expirationDate
, tapepos
);
1807 * The margin of space to check for end of tape is set to the
1808 * amount of space used to write an end-of-tape multiplied by 2.
1809 * The amount of space is size of a 16K volume trailer, a 16K File
1810 * End mark, its EOF marker, a 16K EODump marker, its EOF marker,
1811 * and up to two EOF markers done on close (3 16K blocks + 4 EOF
1814 tc_EndMargin
= (3 * 16384 + 4 * globalTapeConfig
.fileMarkSize
) * 2;
1815 tc_KEndMargin
= tc_EndMargin
/ 1024;
1819 unmountTape(taskId
, tapeInfoPtr
);
1827 makeVolumeHeader(struct volumeHeader
*vhptr
, struct dumpRock
*dparamsPtr
,
1830 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
1831 struct tc_dumpDesc
*curDump
;
1834 curDump
= &nodePtr
->dumps
[dparamsPtr
->curVolume
];
1836 memset(vhptr
, 0, sizeof(*vhptr
));
1837 strcpy(vhptr
->volumeName
, curDump
->name
);
1838 vhptr
->volumeID
= curDump
->vid
;
1839 vhptr
->cloneDate
= curDump
->cloneDate
;
1840 vhptr
->server
= curDump
->hostAddr
;
1841 vhptr
->part
= curDump
->partition
;
1842 vhptr
->from
= curDump
->date
;
1843 vhptr
->frag
= fragmentNumber
;
1845 vhptr
->magic
= TC_VOLBEGINMAGIC
;
1846 vhptr
->dumpID
= dparamsPtr
->databaseDumpId
; /* real dump id */
1847 vhptr
->level
= nodePtr
->level
;
1848 vhptr
->parentID
= nodePtr
->parent
;
1850 vhptr
->versionflags
= CUR_TAPE_VERSION
;
1851 strcpy(vhptr
->dumpSetName
, nodePtr
->dumpSetName
);
1852 strcpy(vhptr
->preamble
, "H++NAME#");
1853 strcpy(vhptr
->postamble
, "T--NAME#");
1859 volumeHeader_hton(struct volumeHeader
*hostPtr
, struct volumeHeader
*netPtr
)
1861 struct volumeHeader volHdr
;
1863 memset(&volHdr
, 0, sizeof(volHdr
));
1865 strcpy(volHdr
.preamble
, hostPtr
->preamble
);
1866 strcpy(volHdr
.postamble
, hostPtr
->postamble
);
1867 strcpy(volHdr
.volumeName
, hostPtr
->volumeName
);
1868 strcpy(volHdr
.dumpSetName
, hostPtr
->dumpSetName
);
1869 volHdr
.volumeID
= htonl(hostPtr
->volumeID
);
1870 volHdr
.server
= htonl(hostPtr
->server
);
1871 volHdr
.part
= htonl(hostPtr
->part
);
1872 volHdr
.from
= htonl(hostPtr
->from
);
1873 volHdr
.frag
= htonl(hostPtr
->frag
);
1874 volHdr
.magic
= htonl(hostPtr
->magic
);
1875 volHdr
.contd
= htonl(hostPtr
->contd
);
1876 volHdr
.dumpID
= htonl(hostPtr
->dumpID
);
1877 volHdr
.level
= htonl(hostPtr
->level
);
1878 volHdr
.parentID
= htonl(hostPtr
->parentID
);
1879 volHdr
.endTime
= htonl(hostPtr
->endTime
);
1880 volHdr
.versionflags
= htonl(hostPtr
->versionflags
);
1881 volHdr
.cloneDate
= htonl(hostPtr
->cloneDate
);
1883 memcpy(netPtr
, &volHdr
, sizeof(struct volumeHeader
));
1887 /* database related routines */
1890 createDump(struct dumpRock
*dparamsPtr
)
1892 struct dumpNode
*nodePtr
= dparamsPtr
->node
;
1893 struct budb_dumpEntry
*dumpPtr
;
1896 dumpPtr
= &dparamsPtr
->dump
;
1897 memset(dumpPtr
, 0, sizeof(*dumpPtr
));
1899 /* id filled in by database */
1900 dumpPtr
->parent
= nodePtr
->parent
;
1901 dumpPtr
->level
= nodePtr
->level
;
1905 if (xbsaType
== XBSA_SERVER_TYPE_ADSM
) {
1906 strcpy(dumpPtr
->tapes
.tapeServer
, butxInfo
.serverName
);
1907 dumpPtr
->flags
= BUDB_DUMP_ADSM
;
1909 if (!(butxInfo
.serverType
& XBSA_SERVER_FLAG_MULTIPLE
)) {
1910 /* The current server (API) doesn't provide the function required
1911 * to specify a server at startup time. For that reason, we can't
1912 * be sure that the server name supplied by the user in the user-
1913 * defined configuration file is correct. We set a flag here so
1914 * we know at restore time that the servername info in the backup
1915 * database may be incorrect. We will not allow a server switch
1916 * at that time, even if the server at restore time supports
1919 dumpPtr
->flags
|= BUDB_DUMP_XBSA_NSS
;
1923 strcpy(dumpPtr
->volumeSetName
, nodePtr
->volumeSetName
);
1924 strcpy(dumpPtr
->dumpPath
, nodePtr
->dumpName
);
1925 strcpy(dumpPtr
->name
, nodePtr
->dumpSetName
);
1926 dumpPtr
->created
= 0; /* let database assign it */
1927 dumpPtr
->incTime
= 0; /* not really used */
1928 dumpPtr
->nVolumes
= 0;
1929 dumpPtr
->initialDumpID
= 0;
1931 dumpPtr
->tapes
.id
= groupId
;
1932 dumpPtr
->tapes
.b
= 1;
1933 dumpPtr
->tapes
.maxTapes
= 0;
1934 strcpy(dumpPtr
->tapes
.format
, nodePtr
->tapeSetDesc
.format
);
1936 /* principal filled in by database */
1938 /* now call the database to create the entry */
1939 code
= bcdb_CreateDump(dumpPtr
);
1941 dparamsPtr
->databaseDumpId
= dumpPtr
->id
;
1948 * Initialize to a specific server. The first time, we remember the
1949 * server as the original server and go back to it each time we pass 0
1953 InitToServer(afs_int32 taskId
, struct butx_transactionInfo
* butxInfoP
,
1956 static char origserver
[BSA_MAX_DESC
];
1957 static int init
= 0;
1958 afs_int32 rc
, code
= 0;
1961 strcpy(origserver
, "");
1966 server
= origserver
; /* return to original server */
1967 if (strcmp(server
, "") == 0)
1968 return 0; /* No server, do nothing */
1969 if (strcmp(butxInfoP
->serverName
, server
) == 0)
1970 return 0; /* same server, do nothing */
1971 if (strcmp(origserver
, "") == 0)
1972 strcpy(origserver
, server
); /* remember original server */
1974 if (strcmp(butxInfoP
->serverName
, "") != 0) {
1975 /* If already connected to a server, disconnect from it.
1976 * Check to see if our server does not support switching.
1978 if (!(butxInfo
.serverType
& XBSA_SERVER_FLAG_MULTIPLE
)) {
1979 ErrorLog(0, taskId
, TC_BADTASK
, 0,
1980 "This version of XBSA libraries does not support switching "
1981 "from server %s to server %s\n", butxInfoP
->serverName
,
1983 return (TC_BADTASK
);
1986 rc
= xbsa_Finalize(&butxInfo
);
1987 if (rc
!= XBSA_SUCCESS
) {
1988 ErrorLog(0, taskId
, rc
, 0,
1989 "InitToServer: Unable to terminate the connection to server %s\n",
1990 butxInfoP
->serverName
);
1995 /* initialize to the new server */
1996 rc
= xbsa_Initialize(&butxInfo
, xbsaObjectOwner
, appObjectOwner
,
1997 xbsaSecToken
, server
);
1998 if (rc
!= XBSA_SUCCESS
) {
1999 ErrorLog(0, taskId
, rc
, 0,
2000 "InitToServer: Unable to initialize the XBSA library to server %s\n",
2014 DeleteDump(void *param
)
2016 struct deleteDumpIf
*ptr
= (struct deleteDumpIf
*)param
;
2019 afs_int32 rc
, code
= 0;
2021 afs_int32 index
, next
, dbTime
;
2023 struct budb_dumpEntry dumpEntry
;
2024 char tapeName
[BU_MAXTAPELEN
];
2025 char dumpIdStr
[XBSA_MAX_OSNAME
];
2026 char volumeNameStr
[XBSA_MAX_PATHNAME
];
2029 int allnotfound
= 1, onenotfound
= 0;
2030 extern struct udbHandleS udbHandle
;
2031 extern struct deviceSyncNode
*deviceLatch
;
2033 dumpid
= ptr
->dumpID
;
2034 taskId
= ptr
->taskId
; /* Get task Id */
2036 afs_pthread_setname_self("deletedump");
2037 setStatus(taskId
, DRIVE_WAIT
);
2038 EnterDeviceQueue(deviceLatch
);
2039 clearStatus(taskId
, DRIVE_WAIT
);
2042 TapeLog(2, taskId
, 0, 0, "Delete Dump %u\n", dumpid
);
2044 vl
.budb_volumeList_len
= 0;
2045 vl
.budb_volumeList_val
= 0;
2048 /* Get the dump info for the dump we are deleting */
2049 rc
= bcdb_FindDumpByID(dumpid
, &dumpEntry
);
2051 ErrorLog(0, taskId
, rc
, 0,
2052 "Unable to locate dump ID %u in database\n", dumpid
);
2053 setStatus(taskId
, TASK_ERROR
);
2057 /* we must make sure that we are configured with the correct type of
2058 * XBSA server for this dump delete! Only those dumped to an ADSM server.
2060 if ((xbsaType
== XBSA_SERVER_TYPE_ADSM
)
2061 && !((dumpEntry
.flags
& (BUDB_DUMP_ADSM
| BUDB_DUMP_BUTA
)))) {
2062 ErrorLog(0, taskId
, TC_BADTASK
, 0,
2063 "The dump %u requested for deletion is incompatible with this instance of butc\n",
2065 setStatus(taskId
, TASK_ERROR
);
2066 ERROR_EXIT(TC_BADTASK
);
2069 /* Make sure we are connected to the correct server. If not, switch to it if appropriate */
2070 if ((strlen((char *)dumpEntry
.tapes
.tapeServer
) != 0)
2071 && (strcmp((char *)dumpEntry
.tapes
.tapeServer
, butxInfo
.serverName
) !=
2074 /* Check to see if the tapeServer name is trustworthy */
2075 if ((dumpEntry
.flags
& (BUDB_DUMP_XBSA_NSS
| BUDB_DUMP_BUTA
))
2076 && !forcemultiple
) {
2077 /* The dump was made with a version of the XBSA interface
2078 * that didn't allow switching of servers, we can't be sure
2079 * that the servername in the backup database is correct. So,
2080 * we will check the servername and log it if they don't match;
2081 * but we will try to do the delete without switching servers.
2084 "The dump %d requested for deletion is on server %s "
2085 "but butc is connected to server %s "
2086 "(Attempting to delete the dump anyway)\n", dumpid
,
2087 (char *)dumpEntry
.tapes
.tapeServer
, butxInfo
.serverName
);
2090 "The dump %u requested for deletion is on server %s "
2091 "but butc is connected to server %s "
2092 "(switching servers)\n", dumpid
,
2093 (char *)dumpEntry
.tapes
.tapeServer
, butxInfo
.serverName
);
2095 rc
= InitToServer(taskId
, &butxInfo
,
2096 (char *)dumpEntry
.tapes
.tapeServer
);
2097 if (rc
!= XBSA_SUCCESS
) {
2098 setStatus(taskId
, TASK_ERROR
);
2104 /* Start a new Transaction */
2105 rc
= xbsa_BeginTrans(&butxInfo
);
2106 if (rc
!= XBSA_SUCCESS
) {
2107 ErrorLog(0, taskId
, rc
, 0, "Unable to create a new transaction\n");
2108 setStatus(taskId
, TASK_ERROR
);
2113 /* Query the backup database for list of volumes to delete */
2114 for (index
= next
= 0; index
!= -1; index
= next
) {
2115 rc
= ubik_Call_SingleServer(BUDB_GetVolumes
, udbHandle
.uh_client
,
2116 UF_SINGLESERVER
, BUDB_MAJORVERSION
,
2117 BUDB_OP_DUMPID
, tapeName
, dumpid
, 0,
2118 index
, &next
, &dbTime
, &vl
);
2120 if (rc
== BUDB_ENDOFLIST
)
2122 ErrorLog(0, taskId
, rc
, 0, "Can't find volume info for dump %d\n",
2124 setStatus(taskId
, TASK_ERROR
);
2128 /* Delete all volumes on the list */
2129 for (i
= 0; i
< vl
.budb_volumeList_len
; i
++) {
2130 if (dumpEntry
.flags
& BUDB_DUMP_BUTA
) {
2131 /* dump was from buta, use old buta style names */
2132 snprintf(dumpIdStr
, sizeof(dumpIdStr
), "/%d", dumpid
);
2133 snprintf(volumeNameStr
, sizeof(volumeNameStr
), "/%s",
2134 (char *)vl
.budb_volumeList_val
[i
].name
);
2135 } else { /* BUDB_DUMP_ADSM */
2136 /* dump was from butc to ADSM, use butc names */
2137 snprintf(dumpIdStr
, sizeof(dumpIdStr
), "%s", butcdumpIdStr
);
2138 snprintf(volumeNameStr
, sizeof(volumeNameStr
), "/%d/%s",
2139 dumpid
, (char *)vl
.budb_volumeList_val
[i
].name
);
2142 rc
= xbsa_DeleteObject(&butxInfo
, dumpIdStr
, volumeNameStr
);
2143 if (rc
!= XBSA_SUCCESS
) {
2144 ErrorLog(0, taskId
, rc
, 0,
2145 "Unable to delete the object %s of dump %s from the server\n",
2146 volumeNameStr
, dumpIdStr
);
2147 /* Don't exit if volume was not found */
2148 if (rc
!= BUTX_DELETENOVOL
) {
2156 "Deleted volume %s (%u) in dumpID %u from the backup server\n",
2157 vl
.budb_volumeList_val
[i
].name
,
2158 vl
.budb_volumeList_val
[i
].id
, dumpid
);
2162 /* free the memory allocated by RPC for this list */
2163 if (vl
.budb_volumeList_val
)
2164 free(vl
.budb_volumeList_val
);
2165 vl
.budb_volumeList_len
= 0;
2166 vl
.budb_volumeList_val
= 0;
2171 rc
= xbsa_EndTrans(&butxInfo
);
2172 if (rc
!= XBSA_SUCCESS
) {
2173 ErrorLog(0, taskId
, rc
, 0,
2174 "Unable to terminate the current transaction\n");
2175 setStatus(taskId
, TASK_ERROR
);
2180 /* Switch back to the original server */
2181 rc
= InitToServer(taskId
, &butxInfo
, NULL
);
2183 if (vl
.budb_volumeList_val
)
2184 free(vl
.budb_volumeList_val
);
2186 setStatus(taskId
, TASK_DONE
);
2187 FreeNode(taskId
); /* free the dump node */
2188 LeaveDeviceQueue(deviceLatch
);
2190 /* If we don't find any dumps on the server, rather than returning
2191 * a success, return a failure.
2193 if (!code
&& onenotfound
&& allnotfound
) {
2194 code
= BUTX_DELETENOVOL
;
2195 setStatus(taskId
, TASK_ERROR
);
2197 return (void *)(uintptr_t)(code
);