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
RCSID("$Header: /afs/sipb.mit.edu/project/openafs/debian/cvs/openafs/src/butc/dump.c,v 1.1.1.8 2003/07/30 17:11:31 hartmans Exp $");
15
#include <sys/types.h>
21
#include <netinet/in.h>
22
#include <sys/socket.h>
31
#include <afs/tcdata.h>
32
#include <afs/bubasics.h>
33
#include <afs/budb_client.h>
34
#include <afs/vldbint.h>
35
#include <afs/ktime.h>
36
#include <afs/vlserver.h>
37
#include <afs/volser.h>
38
#include <afs/volint.h>
39
#include <afs/cellconfig.h>
41
#include "error_macros.h"
42
#include "butc_xbsa.h"
46
/* GLOBAL CONFIGURATION PARAMETERS */
47
extern int dump_namecheck;
48
extern int queryoperator;
50
extern int forcemultiple;
52
extern struct ubik_client *cstruct;
53
dlqlinkT savedEntries;
54
dlqlinkT entries_to_flush;
56
afs_int32 flushSavedEntries(), finishDump(), finishTape(), useTape(), addVolume();
58
extern struct rx_connection *UV_Bind();
60
extern char *globalCellName;
62
extern afs_int32 xbsaType;
63
extern afs_int32 groupId;
64
extern afs_int32 BufferSize;
65
extern afs_int32 statusSize;
66
extern FILE *centralLogIO;
69
char *butcdumpIdStr = "/backup_afs_volume_dumps";
70
extern struct butx_transactionInfo butxInfo;
71
extern char *xbsaObjectOwner;
72
extern char *appObjectOwner;
73
extern char *xbsaSecToken;
74
extern char *xbsalGName;
75
extern char *globalButcLog;
78
afs_int32 dataSize; /* Size of data to read on each rx_Read() call */
79
afs_int32 tapeblocks; /* Number of 16K tape datablocks in buffer (!CONF_XBSA) */
83
* Done 1) dump id generation
84
* Done xx) volume fragment number accounting !! I think.
85
* 2) check abort - check after subroutine calls
86
* Done 3) trailer anomaly
87
* 4) trailer damage indicator after partial dumps ( affects scandump )
88
* Done 5) Ensure mount failure logged
89
* 6) Ensure bucoord status calls work
93
* keep token timeout. If no user reponse (idle time > some period)
94
* and tokens about to time out, terminate dump. This provides at
95
* least something usable.
98
#define DUMPNAME(dumpname, name, dbDumpId) \
100
sprintf(dumpname, "%s", name); \
102
sprintf(dumpname, "%s (DumpId %u)", name, dbDumpId);
104
#if defined(AFS_NT40_ENV) || (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN60_ENV)) || defined(AFS_SUN4_ENV)
109
memcpy(tm, localtime(t), sizeof(struct tm));
117
int curVolume; /* index in dumpNode of volume */
118
int curVolumeStatus; /* more explicit dump state */
119
afs_uint32 curVolStartPos; /* Starting position of the current volume */
120
afs_uint32 databaseDumpId; /* real dump id, for db */
121
afs_uint32 initialDumpId; /* the initial dump, for appended dumps */
122
afs_int32 volumesDumped; /* # volumes successfully dumped */
123
afs_int32 volumesFailed; /* # volumes that failed to dump */
124
afs_int32 volumesNotDumped; /* # volumes that were not dumped (didn't fail) */
126
/* tape management */
127
char tapeName[TC_MAXTAPENAMELEN];
128
struct butm_tapeInfo *tapeInfoPtr;
129
struct butm_tapeLabel tapeLabel;
130
int wroteLabel; /* If the tape label is written */
132
/* database information */
133
struct budb_dumpEntry lastDump; /* the last dump of this volset */
134
struct budb_dumpEntry dump; /* current dump */
135
struct budb_tapeEntry tape; /* current tape, not used -VA*/
137
/* links to existing info */
138
struct dumpNode *node;
141
/* configuration variables */
142
#define HITEOT(code) ((code == BUTM_IO) || (code == BUTM_EOT) || (code == BUTM_IOCTL))
143
extern int autoQuery;
146
afs_int32 tc_EndMargin;
147
afs_int32 tc_KEndMargin;
150
/* compute the absolute expiration date */
152
calcExpirationDate(expType, expDate, createTime)
155
afs_int32 createTime;
157
struct ktime_date kd;
158
afs_int32 Add_RelDate_to_Time();
163
/* expiration date is relative to the creation time of the dump.
164
* This is the only case that requires any work
166
Int32To_ktimeRelDate(expDate, &kd);
167
return(Add_RelDate_to_Time(&kd, createTime));
180
afs_int32 curr_bserver = 0;
181
struct rx_connection *curr_fromconn = (struct rx_connection *)0;
183
struct rx_connection *Bind(server)
187
if (curr_bserver == server) /* Keep connection if have it */
188
return (curr_fromconn);
190
rx_DestroyConnection (curr_fromconn); /* Otherwise get rid of it */
191
curr_fromconn = (struct rx_connection *)0;
196
curr_fromconn = UV_Bind (server, AFSCONF_VOLUMEPORT); /* Establish new connection */
197
if (curr_fromconn) curr_bserver = server;
200
return (curr_fromconn);
204
* 1) save the chunksize or otherwise ensure tape space remaining is
205
* check frequently enough
206
* 2) This is called once. For partial dumps, need to
207
* ensure that the tape device is left in the correct state for
211
#define BIGCHUNK 102400
214
dumpVolume(curDump, dparamsPtr)
215
struct tc_dumpDesc *curDump;
216
struct dumpRock *dparamsPtr;
218
struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
219
struct dumpNode *nodePtr = dparamsPtr->node;
220
afs_int32 taskId = nodePtr->taskID;
223
afs_int32 volumeFlags;
224
afs_int32 kRemaining;
225
afs_int32 rc, code = 0;
227
afs_uint32 volBytesRead;
228
afs_uint32 chunkSize;
229
afs_int32 bytesread; /* rx reads */
230
int endofvolume=0; /* Have we read all volume data */
233
struct volumeHeader hostVolumeHeader;
235
struct rx_call *fromcall = (struct rx_call *)0;
236
struct rx_connection *fromconn;
237
afs_int32 updatedate, fromtid = 0;
238
volEntries volumeInfo;
239
afs_int32 bytesWritten;
240
afs_uint32 statuscount=statusSize, tsize=0;
242
dparamsPtr->curVolumeStatus = DUMP_NOTHING;
244
fromconn = Bind(htonl(curDump->hostAddr)); /* get connection to the server */
246
/* Determine when the volume was last cloned and updated */
247
volumeInfo.volEntries_val = (volintInfo *)0;
248
volumeInfo.volEntries_len = 0;
249
rc = AFSVolListOneVolume(fromconn, curDump->partition, curDump->vid, &volumeInfo);
250
if (rc) ERROR_EXIT(rc);
251
updatedate = volumeInfo.volEntries_val[0].updateDate;
252
curDump->cloneDate = ((curDump->vtype == RWVOL) ?
253
time(0) : volumeInfo.volEntries_val[0].creationDate);
255
if (curDump->date >= curDump->cloneDate)
256
ERROR_EXIT(0); /* not recloned since last dump */
257
if (curDump->date > updatedate) {
258
dparamsPtr->curVolumeStatus = DUMP_NODUMP; /* not modified since last dump */
262
/* Start the volserver transaction and dump */
263
rc = AFSVolTransCreate (fromconn, curDump->vid, curDump->partition, ITBusy, &fromtid);
264
if (rc) ERROR_EXIT(rc);
265
fromcall = rx_NewCall(fromconn);
267
rc = StartAFSVolDump (fromcall, fromtid, curDump->date);
268
if (rc) ERROR_EXIT(rc);
270
dparamsPtr->curVolumeStatus = DUMP_PARTIAL;
271
dparamsPtr->curVolStartPos = tapeInfoPtr->position;
273
/* buffer is place in bufferBlock to write volume data.
274
* butm_writeFileData() assumes the previous BUTM_HDRSIZE bytes
275
* is available to write the tape block header.
277
buffer = bufferBlock + BUTM_HDRSIZE;
279
/* Dump one volume fragment at a time until we dump the full volume.
280
* A volume with more than 1 fragment means the volume will 'span'
283
for (fragmentNumber=1; !endofvolume; fragmentNumber++) { /*frag*/
284
rc = butm_WriteFileBegin(tapeInfoPtr);
286
ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write FileBegin on tape\n");
289
indump = 1; /* first write to tape */
291
/* Create and Write the volume header */
292
makeVolumeHeader(&hostVolumeHeader, dparamsPtr, fragmentNumber);
293
hostVolumeHeader.contd = ((fragmentNumber == 1) ? 0 : TC_VOLCONTD);
294
volumeHeader_hton(&hostVolumeHeader, buffer);
296
rc = butm_WriteFileData(tapeInfoPtr, buffer, 1, sizeof(hostVolumeHeader));
298
ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write VolumeHeader on tape\n");
302
bytesWritten = BUTM_BLOCKSIZE; /* Wrote one tapeblock */
303
tsize += bytesWritten;
305
/* Start reading volume data, rx_Read(), and dumping to the tape
306
* until we've dumped the entire volume (endofvolume == 1). We can
307
* exit this loop early if we find we are close to the end of the
308
* tape; in which case we dump the next fragment on the next tape.
313
while (!endofvolume && !fragmentvolume) { /*w*/
316
/* Check for abort in the middle of writing data */
317
if (volBytesRead >= chunkSize) {
318
chunkSize += BIGCHUNK;
319
if ( checkAbortByTaskId(taskId) )
320
ABORT_EXIT(TC_ABORTEDBYREQUEST);
322
/* set bytes dumped for backup */
324
nodePtr->statusNodePtr->nKBytes = tapeInfoPtr->kBytes;
328
/* Determine how much data to read in upcoming RX_Read() call */
330
/* Check if we are close to the EOT. There should at least be some
331
* data on the tape before it is switched. HACK: we have to split a
332
* volume across tapes because the volume trailer says the dump
333
* continues on the next tape (and not the filemark). This could
334
* result in a volume starting on one tape (no volume data dumped) and
335
* continued on the next tape. It'll work, just requires restore to
336
* switch tapes. This allows many small volumes (<16K) to be dumped.
338
kRemaining = butm_remainingKSpace(tapeInfoPtr);
339
if ( (kRemaining < tc_KEndMargin) &&
340
(volBytesRead || (tapeInfoPtr->position > (isafile?3:2))) ) {
345
/* Guess at how much data to read. So we don't write off end of tape */
346
if (kRemaining < (tapeblocks * 16)) {
347
if (kRemaining < 0) {
348
toread = BUTM_BLKSIZE;
350
toread = ((kRemaining/16) + 1) * BUTM_BLKSIZE;
351
if (toread > dataSize) toread = dataSize;
355
/* Read some volume data. */
356
if (fragmentvolume) {
359
bytesread = rx_Read(fromcall, buffer, toread);
360
volBytesRead += bytesread;
361
if (bytesread != toread) {
362
/* Make sure were at end of volume and not a communication error */
363
rc = rx_Error(fromcall);
364
if (rc) ERROR_EXIT(rc);
369
if (fragmentvolume || endofvolume) {
370
/* Create a volume trailer appending it to this data block */
371
makeVolumeHeader(&hostVolumeHeader, dparamsPtr, fragmentNumber);
372
hostVolumeHeader.contd = (endofvolume ? 0 : TC_VOLCONTD);
373
hostVolumeHeader.magic = TC_VOLENDMAGIC;
374
hostVolumeHeader.endTime = (endofvolume ? time(0) : 0);
375
volumeHeader_hton(&hostVolumeHeader, &buffer[bytesread]);
376
bytesread += sizeof(hostVolumeHeader);
379
/* Write the datablock out */
380
/* full data buffer - write it to tape */
381
rc = butm_WriteFileData(tapeInfoPtr, buffer, tapeblocks, bytesread);
383
ErrorLog(1, taskId, rc, tapeInfoPtr->error,
384
"Can't write VolumeData on tape\n");
387
bytesWritten = tapeblocks * BUTM_BLOCKSIZE;
388
tsize += bytesWritten;
390
/* Display a status line every statusSize or at end of volume */
392
((tsize >= statuscount) || endofvolume || fragmentvolume) ) {
395
localtime_r(&t, &tm);
396
printf("%02d:%02d:%02d: Task %u: %u KB: %s: %u B\n",
397
tm.tm_hour, tm.tm_min, tm.tm_sec, taskId,
398
tapeInfoPtr->kBytes, hostVolumeHeader.volumeName, tsize);
399
statuscount = tsize + statusSize;
403
/* End the dump before recording it in BUDB as successfully dumped */
404
rc = butm_WriteFileEnd(tapeInfoPtr);
407
ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write FileEnd on tape\n");
411
/* Record in BUDB the volume fragment as succcessfully dumped */
412
volumeFlags = (( fragmentNumber == 1 ) ? BUDB_VOL_FIRSTFRAG : 0);
413
if (endofvolume) volumeFlags |= BUDB_VOL_LASTFRAG;
414
rc = addVolume(0, dparamsPtr->databaseDumpId, dparamsPtr->tapeName,
415
nodePtr->dumps[dparamsPtr->curVolume].name,
416
nodePtr->dumps[dparamsPtr->curVolume].vid,
417
nodePtr->dumps[dparamsPtr->curVolume].cloneDate,
418
dparamsPtr->curVolStartPos,
419
volBytesRead, (fragmentNumber-1), volumeFlags);
420
if (rc) ABORT_EXIT(rc);
422
/* If haven't finished dumping the volume, end this
423
* tape and get the next tape.
426
/* Write an EOT marker.
427
* Log the error but ignore it since the dump is effectively done.
428
* Scantape will detect continued volume and not read the EOT.
430
rc = butm_WriteEOT(tapeInfoPtr);
431
if (rc) TapeLog(1, taskId, rc, tapeInfoPtr->error,
432
"Warning: Can't write End-Of-Dump on tape\n");
434
/* Unmount the tape */
435
unmountTape(taskId, tapeInfoPtr);
437
/* Tell the database the tape is complete (and ok) */
438
rc = finishTape(&dparamsPtr->tape, dparamsPtr->tapeInfoPtr->kBytes +
439
(dparamsPtr->tapeInfoPtr->nBytes ? 1 : 0));
440
if (rc) ABORT_EXIT(rc);
442
/* get the next tape. Prompt, mount, and add it into the database */
443
dparamsPtr->tapeSeq++;
444
rc = getDumpTape(dparamsPtr, 1, 0); /* interactive - no append */
445
if (rc) ABORT_EXIT(rc);
447
dparamsPtr->curVolStartPos = tapeInfoPtr->position;
451
dparamsPtr->curVolumeStatus = DUMP_SUCCESS;
455
* If we hit the end, see if this is the first volume on the tape or not.
456
* Also, mark the tape as finished if the tape contains other dumps.
458
if (!code) code = rc;
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, dparamsPtr->tapeInfoPtr->kBytes +
469
(dparamsPtr->tapeInfoPtr->nBytes ? 1 : 0));
470
if (rc) ABORT_EXIT(rc);
475
* This is used when an error occurs part way into a volume dump. Clean
476
* the tape state by writing an FileEnd mark. Forgo this action if we hit
480
rc = butm_WriteFileEnd(tapeInfoPtr);
483
ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write FileEnd on tape\n");
488
rc = rx_EndCall (fromcall, 0);
489
if (!code) code = rc;
494
rc = AFSVolEndTrans (fromconn, fromtid, &rcode);
495
if (!code) code = (rc ? rc : rcode);
501
dparamsPtr->curVolumeStatus = DUMP_FAILED;
506
xbsaDumpVolume(curDump, dparamsPtr)
507
struct tc_dumpDesc *curDump;
508
struct dumpRock *dparamsPtr;
511
struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
512
struct dumpNode *nodePtr = dparamsPtr->node;
513
char *buffer = bufferBlock;
514
afs_int32 taskId = nodePtr->taskID;
515
afs_int32 rc, code = 0;
517
afs_uint32 volBytesRead;
518
afs_uint32 chunkSize;
519
afs_int32 bytesread; /* rx reads */
520
int endofvolume=0; /* Have we read all volume data */
521
int begindump=0, indump=0; /* if dump transaction started; if dumping data */
522
struct volumeHeader hostVolumeHeader;
524
struct rx_call *fromcall = (struct rx_call *)0;
525
struct rx_connection *fromconn;
526
afs_int32 updatedate, fromtid = 0;
527
volEntries volumeInfo;
528
afs_int32 bytesWritten;
529
afs_uint32 statuscount=statusSize, tsize=0, esize;
532
char dumpIdStr[XBSA_MAX_OSNAME];
533
char volumeNameStr[XBSA_MAX_PATHNAME];
534
static char *dumpDescription = "AFS volume dump";
535
static char *objectDescription = "XBSA - butc";
537
dparamsPtr->curVolumeStatus = DUMP_NOTHING;
539
fromconn = Bind(htonl(curDump->hostAddr)); /* get connection to the server */
541
/* Determine when the volume was last cloned and updated */
542
volumeInfo.volEntries_val = (volintInfo *)0;
543
volumeInfo.volEntries_len = 0;
544
rc = AFSVolListOneVolume(fromconn, curDump->partition, curDump->vid, &volumeInfo);
545
if (rc) ERROR_EXIT(rc);
546
updatedate = volumeInfo.volEntries_val[0].updateDate;
547
curDump->cloneDate = ((curDump->vtype == RWVOL) ?
548
time(0) : volumeInfo.volEntries_val[0].creationDate);
550
/* Get the volume size (in KB) and increase by 25%. Then set as a hyper */
551
esize = volumeInfo.volEntries_val[0].size;
552
esize += (esize/4)+1;
554
if (curDump->date >= curDump->cloneDate)
555
ERROR_EXIT(0); /* not recloned since last dump */
556
if (curDump->date > updatedate) {
557
dparamsPtr->curVolumeStatus = DUMP_NODUMP; /* not modified since last dump */
561
/* Start a new XBSA Transaction */
562
rc = xbsa_BeginTrans(&butxInfo);
563
if (rc != XBSA_SUCCESS) {
564
ErrorLog(1, taskId, rc, 0, "Unable to create a new transaction\n");
567
begindump = 1; /* Will need to do an xbsa_EndTrans */
569
/* Start the volserver transaction and dump. Once started, the
570
* volume status is "partial dump". Also, the transaction with
571
* the volserver is idle until the first read. An idle transaction
572
* will time out in 600 seconds. After the first rx_Read,
573
* the transaction is not idle. See GCTrans().
575
rc = AFSVolTransCreate (fromconn, curDump->vid, curDump->partition, ITBusy, &fromtid);
576
if (rc) ERROR_EXIT(rc);
577
fromcall = rx_NewCall(fromconn);
579
rc = StartAFSVolDump (fromcall, fromtid, curDump->date);
580
if (rc) ERROR_EXIT(rc);
582
dparamsPtr->curVolumeStatus = DUMP_PARTIAL;
583
dparamsPtr->curVolStartPos = tapeInfoPtr->position;
585
/* Tell XBSA what the name and size of volume to write */
586
strcpy(dumpIdStr, butcdumpIdStr); /* "backup_afs_volume_dumps" */
587
sprintf(volumeNameStr, "/%d", dparamsPtr->databaseDumpId);
588
strcat(volumeNameStr, "/");
589
strcat(volumeNameStr, curDump->name); /* <dumpid>/<volname> */
590
hset32(estSize, esize);
591
hshlft(estSize, 10); /* Multiply by 1024 so its in KB */
593
rc = xbsa_WriteObjectBegin(&butxInfo, dumpIdStr, volumeNameStr,
594
xbsalGName, estSize, dumpDescription,
596
if (rc != XBSA_SUCCESS) {
597
ErrorLog(1, taskId, rc, 0,
598
"Unable to begin writing of the fileset data to the server\n");
601
indump = 1; /* Will need to do an xbsa_WriteObjectEnd */
603
/* Create and Write the volume header */
604
makeVolumeHeader(&hostVolumeHeader, dparamsPtr, 1);
605
hostVolumeHeader.contd = 0;
606
volumeHeader_hton(&hostVolumeHeader, buffer);
608
rc = xbsa_WriteObjectData(&butxInfo, buffer, sizeof(struct volumeHeader), &bytesWritten);
609
if (rc != XBSA_SUCCESS) {
610
ErrorLog(1, taskId, rc, 0, "Unable to write VolumeHeader data to the server\n");
613
/* There is a bug in the ADSM library where the bytesWritten is
614
* not filled in, so we set it as correct anyway.
616
bytesWritten = sizeof(struct volumeHeader);
617
if (bytesWritten != sizeof(struct volumeHeader)) {
618
ErrorLog(1, taskId, rc, 0,
619
"The size of VolumeHeader written (%d) does not equal its actual size (%d)\n",
620
bytesWritten, sizeof(struct volumeHeader));
621
ERROR_EXIT(TC_INTERNALERROR);
624
incSize(tapeInfoPtr, sizeof(struct volumeHeader)); /* Increment amount we've written */
625
tsize += bytesWritten;
627
/* Start reading volume data, rx_Read(), and dumping to the tape
628
* until we've dumped the entire volume (endofvolume == 1).
632
while (!endofvolume) { /*w*/
635
/* Check for abort in the middle of writing data */
636
if (volBytesRead >= chunkSize) {
637
chunkSize += BIGCHUNK;
638
if ( checkAbortByTaskId(taskId) )
639
ABORT_EXIT(TC_ABORTEDBYREQUEST);
641
/* set bytes dumped for backup */
643
nodePtr->statusNodePtr->nKBytes = tapeInfoPtr->kBytes;
647
/* Determine how much data to read in upcoming RX_Read() call */
650
/* Read some volume data. */
651
bytesread = rx_Read(fromcall, buffer, toread);
652
volBytesRead += bytesread;
653
if (bytesread != toread) {
656
/* Make sure were at end of volume and not a communication error */
657
rc = rx_Error(fromcall);
658
if (rc) ERROR_EXIT(rc);
662
/* Create a volume trailer appending it to this data block (if not XBSA) */
663
makeVolumeHeader(&hostVolumeHeader, dparamsPtr, 1);
664
hostVolumeHeader.contd = 0;
665
hostVolumeHeader.magic = TC_VOLENDMAGIC;
666
hostVolumeHeader.endTime = time(0);
667
volumeHeader_hton(&hostVolumeHeader, &buffer[bytesread]);
668
bytesread += sizeof(hostVolumeHeader);
670
/* End the dump and transaction with the volserver. We end it now, before
671
* we make the XBSA call because if XBSA blocks, we could time out on the
672
* volserver (After last read, the transaction with the volserver is idle).
674
rc = rx_EndCall (fromcall, 0);
676
if (rc) ERROR_EXIT(rc);
678
rc = AFSVolEndTrans (fromconn, fromtid, &rcode);
680
if (rc) ERROR_EXIT(rc);
683
/* Write the datablock out */
684
rc = xbsa_WriteObjectData(&butxInfo, buffer, bytesread, &bytesWritten);
685
if (rc != XBSA_SUCCESS) {
686
ErrorLog(1, taskId, rc, 0, "Unable to write data to the server\n");
689
/* There is a bug in the ADSM library where the bytesWritten is
690
* not filled in, so we set it as correct anyway.
692
bytesWritten = bytesread;
693
if (bytesWritten != bytesread) {
694
ErrorLog(1, taskId, rc, 0,
695
"The size of data written (%d) does not equal size read (%d)\n",
696
bytesWritten, bytesread);
697
ERROR_EXIT(TC_INTERNALERROR);
700
incSize(tapeInfoPtr, bytesread); /* Increment amount we've written */
701
tsize += bytesWritten;
703
/* Display a status line every statusSize or at end of volume */
704
if ( statusSize && ((tsize >= statuscount) || endofvolume) ) {
707
localtime_r(&t, &tm);
708
printf("%02d:%02d:%02d: Task %u: %u KB: %s: %u B\n",
709
tm.tm_hour, tm.tm_min, tm.tm_sec, taskId,
710
tapeInfoPtr->kBytes, hostVolumeHeader.volumeName, tsize);
711
statuscount = tsize + statusSize;
715
/* End the XBSA transaction before recording it in BUDB as successfully dumped */
716
rc = xbsa_WriteObjectEnd(&butxInfo);
718
if (rc != XBSA_SUCCESS) {
719
ErrorLog(1, taskId, rc, 0,
720
"Unable to terminate writing of the volume data to the server");
723
rc = xbsa_EndTrans(&butxInfo);
725
tapeInfoPtr->position++;
726
if (rc != XBSA_SUCCESS) {
727
ErrorLog(1, taskId, rc, 0, "Unable to terminate the current transaction");
731
/* Record in BUDB the volume fragment as succcessfully dumped */
732
rc = addVolume(0, dparamsPtr->databaseDumpId, dparamsPtr->tapeName,
733
nodePtr->dumps[dparamsPtr->curVolume].name,
734
nodePtr->dumps[dparamsPtr->curVolume].vid,
735
nodePtr->dumps[dparamsPtr->curVolume].cloneDate,
736
dparamsPtr->curVolStartPos,
737
volBytesRead, 0/*frag0*/,
738
(BUDB_VOL_FIRSTFRAG | BUDB_VOL_LASTFRAG));
739
if (rc) ABORT_EXIT(rc);
741
dparamsPtr->curVolumeStatus = DUMP_SUCCESS;
744
/* Cleanup after an error occurs part way into a volume dump */
746
rc = rx_EndCall (fromcall, 0);
747
if (!code) code = rc;
752
rc = AFSVolEndTrans (fromconn, fromtid, &rcode);
753
if (!code) code = (rc ? rc : rcode);
756
/* If this dump failed, what happens to successive retries
757
* of the volume? How do they get recorded in the XBSA database
758
* (overwritten)? If not, we don't record this in the BUDB database
759
* so it will not be removed when we delete the dump. What to do?
760
* Also if the volume was never recorded in the DB (partial dump).
764
rc = xbsa_WriteObjectEnd(&butxInfo);
766
if (rc != XBSA_SUCCESS) {
767
ErrorLog(1, taskId, rc, 0,
768
"Unable to terminate writing of the volume data to the server");
770
tapeInfoPtr->position++;
774
/* End the XBSA Transaction */
775
rc = xbsa_EndTrans(&butxInfo);
777
if (rc != XBSA_SUCCESS) {
778
ErrorLog(1, taskId, rc, 0, "Unable to terminate the current transaction");
785
dparamsPtr->curVolumeStatus = DUMP_FAILED;
791
#define HOSTADDR(sockaddr) (sockaddr)->sin_addr.S_un.S_addr
793
#define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr
797
* Go through the list of volumes to dump, dumping each one. The action
798
* taken when a volume dump fails, depends on the passNumber. At minimum,
799
* the failed volume is remembered.
801
* flushSavedEntries - inconsistent treatment for errors. What should
802
* be done for user aborts?
806
dumpPass(dparamsPtr, passNumber)
807
struct dumpRock *dparamsPtr;
810
struct dumpNode *nodePtr = dparamsPtr->node;
811
struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
812
afs_int32 taskId = nodePtr->taskID;
813
struct tc_dumpDesc *curDump;
815
afs_int32 code = 0, tcode, dvcode;
818
struct vldbentry vldbEntry;
819
struct sockaddr_in server;
822
TapeLog(2, taskId, 0, 0, "Starting pass %d\n", passNumber);
824
/* while there are more volumes to dump */
825
for (dparamsPtr->curVolume = 0;
826
dparamsPtr->curVolume < nodePtr->arraySize;
827
dparamsPtr->curVolume++)
829
curDump = &nodePtr->dumps[dparamsPtr->curVolume];
830
if (curDump->hostAddr == 0) continue;
832
/* set name of current volume being dumped */
834
strcpy(nodePtr->statusNodePtr->volumeName, curDump->name);
837
/* Determine location of the volume.
838
* In case the volume moved has moved.
842
tcode = bc_GetEntryByID(cstruct, curDump->vid, curDump->vtype, &vldbEntry);
845
ErrorLog(0, taskId, tcode, 0,
846
"Volume %s (%u) failed - Can't find volume in VLDB\n",
847
curDump->name, curDump->vid);
848
curDump->hostAddr = 0;
849
dparamsPtr->volumesFailed++;
853
switch (curDump->vtype)
856
if ( !(vldbEntry.flags & BACK_EXISTS) )
858
ErrorLog(0, taskId, 0, 0,
859
"Volume %s (%u) failed - Backup volume no longer exists\n",
860
curDump->name, curDump->vid);
861
curDump->hostAddr = 0;
862
dparamsPtr->volumesFailed++;
865
/* Fall into RWVOL case */
868
for (e=0; e<vldbEntry.nServers; e++) /* Find the RW volume */
870
if (vldbEntry.serverFlags[e] & ITSRWVOL) break;
875
/* Try to use the server and partition we found the volume on
876
* Otherwise, use the first RO volume.
878
for (e=0; e<vldbEntry.nServers; e++) /* Find the RO volume */
880
if ( (curDump->hostAddr == vldbEntry.serverNumber[e] ) &&
881
(curDump->partition == vldbEntry.serverPartition[e]) )
885
if (e >= vldbEntry.nServers)
886
{ /* Didn't find RO volume */
887
for (e=0; e<vldbEntry.nServers; e++) /* Find the first RO volume */
889
if (vldbEntry.serverFlags[e] & ITSROVOL) break;
895
ErrorLog(0, taskId, 0, 0,
896
"Volume %s (%u) failed - Unknown volume type\n",
897
curDump->name, curDump->vid);
898
curDump->hostAddr = 0;
903
if (e >=vldbEntry.nServers)
905
ErrorLog(0, taskId, 0, 0,
906
"Volume %s (%u) failed - Can't find volume entry in VLDB\n",
907
curDump->name, curDump->vid);
908
curDump->hostAddr = 0;
909
dparamsPtr->volumesFailed++;
913
/* Remember the server and partition the volume exists on */
914
memset(&server, 0, sizeof(server));
915
server.sin_addr.s_addr = vldbEntry.serverNumber[e];
917
server.sin_family = AF_INET;
918
#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
919
server.sin_len = sizeof(struct sockaddr_in);
921
curDump->hostAddr = HOSTADDR(&server);
922
curDump->partition = vldbEntry.serverPartition[e];
924
/* Determine date from which to do an incremental dump
928
tcode = bcdb_FindClone(nodePtr->parent, curDump->name, &curDump->date);
929
if (tcode) curDump->date = 0;
933
curDump->date = 0; /* do a full dump */
937
if ( checkAbortByTaskId(taskId) )
938
ERROR_EXIT(TC_ABORTEDBYREQUEST);
940
/* Establish connection to volume - UV_ routine expects
941
* host address in network order
944
dvcode = xbsaDumpVolume(curDump, dparamsPtr);
946
dvcode = dumpVolume(curDump, dparamsPtr);
948
action = dparamsPtr->curVolumeStatus;
950
/* Flush volume and tape entries to the database */
951
tcode = flushSavedEntries(action);
952
if (tcode) ERROR_EXIT(tcode);
957
TapeLog(1, taskId, 0, 0, "Volume %s (%u) successfully dumped\n",
958
curDump->name, curDump->vid);
960
ErrorLog(1, taskId, dvcode, 0,
961
"Warning: Termination processing error on volume %s (%u)\n",
962
curDump->name, curDump->vid);
964
curDump->hostAddr = 0;
965
dparamsPtr->volumesDumped++;
970
if (action == DUMP_PARTIAL)
972
ErrorLog(1, taskId, dvcode, 0,
973
"Volume %s (%u) failed - partially dumped\n",
974
curDump->name, curDump->vid);
978
ErrorLog(0, taskId, dvcode, 0,
979
"Volume %s (%u) failed\n", curDump->name, curDump->vid);
983
ErrorLog(0, taskId, dvcode, 0,
984
"Volume %s (%u) not dumped - has not been re-cloned since last dump\n",
985
curDump->name, curDump->vid);
988
if (passNumber == maxpass)
993
ch = retryPrompt(curDump->name, curDump->vid, taskId);
997
case 'r': /* retry */
998
dparamsPtr->curVolume--; /* redump this volume */
1001
case 'o': /* omit */
1002
ErrorLog(1, taskId, 0, 0, "Volume %s (%u) omitted\n",
1003
curDump->name, curDump->vid);
1004
dparamsPtr->volumesFailed++;
1006
case 'a': /* abort */
1007
TapeLog(1, taskId, 0, 0, "Dump aborted\n");
1008
ERROR_EXIT(TC_ABORTEDBYREQUEST);
1011
ERROR_EXIT(TC_INTERNALERROR);
1018
TapeLog(1, taskId, dvcode, 0,
1019
"Volume %s (%u) hit end-of-tape inferred - will retry on next tape\n",
1020
curDump->name, curDump->vid);
1022
/* Get the next tape */
1023
unmountTape(taskId, tapeInfoPtr);
1025
dparamsPtr->tapeSeq++;
1026
tcode = getDumpTape(dparamsPtr, 1, 0); /* interactive - no appends */
1027
if (tcode) ERROR_EXIT(tcode);
1029
dparamsPtr->curVolume--; /* redump this volume */
1033
case DUMP_NORETRYEOT:
1034
ErrorLog(1, taskId, 0, 0, "Volume %s (%u) failed - volume larger than tape\n",
1035
curDump->name, curDump->vid);
1037
/* rewrite the label on the tape - rewind - no need to switch tapes */
1038
tcode = butm_Create(tapeInfoPtr, &dparamsPtr->tapeLabel, 1);
1040
ErrorLog(0, taskId, tcode, tapeInfoPtr->error, "Can't relabel tape\n");
1042
unmountTape(taskId, tapeInfoPtr);
1043
tcode = getDumpTape(dparamsPtr, 1, 0); /* interactive - no appends */
1044
if (tcode) ERROR_EXIT(tcode);
1046
else { /* Record the tape in database */
1047
tapepos = tapeInfoPtr->position;
1048
tcode = useTape(&dparamsPtr->tape,
1049
dparamsPtr->databaseDumpId,
1050
dparamsPtr->tapeName,
1051
(dparamsPtr->tapeSeq + dparamsPtr->dump.tapes.b),
1052
dparamsPtr->tapeLabel.useCount,
1053
dparamsPtr->tapeLabel.creationTime,
1054
dparamsPtr->tapeLabel.expirationDate,
1058
curDump->hostAddr = 0;
1059
dparamsPtr->volumesFailed++;
1063
TapeLog(1, taskId, dvcode, 0,
1064
"Volume %s (%u) not dumped - has not been modified since last dump\n",
1065
curDump->name, curDump->vid);
1067
curDump->hostAddr = 0;
1068
dparamsPtr->volumesNotDumped++;
1072
ErrorLog(1, taskId, dvcode, 0, "Volume %s (%u) failed\n",
1073
curDump->name, curDump->vid);
1080
/* check if we terminated while processing a volume */
1081
if (dparamsPtr->curVolume < nodePtr->arraySize)
1083
TapeLog(2, taskId, 0, 0, "Terminated while processing Volume %s (%u)\n",
1084
curDump->name, curDump->vid);
1087
/* print a summary of this pass */
1088
TapeLog(2, taskId, 0, 0, "End of pass %d: Volumes remaining = %d\n", passNumber,
1089
nodePtr->arraySize - (dparamsPtr->volumesDumped + dparamsPtr->volumesFailed +
1090
dparamsPtr->volumesNotDumped));
1095
struct dumpNode *nodePtr;
1097
struct dumpRock dparams;
1098
struct butm_tapeInfo tapeInfo;
1104
/* for volume setup */
1105
struct tc_dumpDesc *dumpDescPtr;
1107
int failedvolumes = 0;
1108
int dumpedvolumes = 0;
1109
int nodumpvolumes = 0;
1112
char finishedMsg1[50];
1113
char finishedMsg2[50];
1116
afs_int32 allocbufferSize;
1118
extern struct deviceSyncNode *deviceLatch;
1119
extern struct tapeConfig globalTapeConfig;
1120
extern afs_int32 createDump();
1122
taskId = nodePtr->taskID; /* Get task Id */
1123
setStatus(taskId, DRIVE_WAIT);
1124
EnterDeviceQueue(deviceLatch);
1125
clearStatus(taskId, DRIVE_WAIT);
1128
TapeLog(2, taskId, 0, 0, "Dump %s\n", nodePtr->dumpSetName);
1130
/* setup the dump parameters */
1131
memset(&dparams, 0, sizeof(dparams));
1132
dparams.node = nodePtr;
1133
dparams.tapeInfoPtr = &tapeInfo;
1134
dlqInit(&savedEntries);
1137
/* Instantiate the tape module */
1138
tapeInfo.structVersion = BUTM_MAJORVERSION;
1139
code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1141
ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize the tape module\n");
1146
/* check if abort requested while waiting on device latch */
1147
if ( checkAbortByTaskId(taskId) )
1148
ERROR_EXIT(TC_ABORTEDBYREQUEST);
1150
/* Are there volumes to dump */
1151
if (nodePtr->arraySize == 0)
1153
TLog(taskId, "Dump (%s), no volumes to dump\n", nodePtr->dumpSetName);
1157
/* Allocate a buffer for the dumps. Leave room for header and vol-trailer.
1158
* dataSize is amount of data to read in each rx_Read() call.
1161
/* XBSA dumps have not header */
1162
dataSize = BufferSize;
1163
allocbufferSize = dataSize + sizeof(struct volumeHeader);
1165
tapeblocks = BufferSize / BUTM_BLOCKSIZE; /* # of 16K tapeblocks */
1166
dataSize = (tapeblocks * BUTM_BLKSIZE);
1167
allocbufferSize = BUTM_HDRSIZE + dataSize + sizeof(struct volumeHeader);
1169
bufferBlock = (char *)0;
1170
bufferBlock = malloc(allocbufferSize);
1172
ErrorLog(0, taskId, TC_NOMEMORY, 0, "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
sprintf(strlevel, "%d", nodePtr->level);
1181
code = bcdb_FindLatestDump(nodePtr->volumeSetName, strlevel, &dparams.lastDump);
1183
if (code != BUDB_NODUMPNAME) {
1184
ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
1187
memset(&dparams.lastDump, 0, sizeof(dparams.lastDump));
1190
code = createDump(&dparams); /* enter dump into database */
1193
ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
1197
TLog(taskId, "Dump %s (DumpID %u)\n", nodePtr->dumpSetName, dparams.databaseDumpId);
1200
/* mount the tape and write its label */
1201
code = getDumpTape(&dparams, autoQuery, nodePtr->doAppend);
1203
/* Create a dummy tape to satisfy backup databae */
1204
code = getXBSATape(&dparams);
1205
tapeInfo.position = 1;
1208
/* If didn't write the label, remove dump from the database */
1209
if ( !dparams.wroteLabel ) {
1210
i = bcdb_deleteDump(dparams.databaseDumpId, 0, 0, 0);
1211
if ( i && (i != BUDB_NOENT) )
1212
ErrorLog(1, taskId, i, 0, "Warning: Can't delete dump %u from database\n",
1213
dparams.databaseDumpId);
1215
dparams.databaseDumpId = 0;
1217
ERROR_EXIT(code); /* exit with code from getTape */
1220
startTime = time(0);
1221
for (pass = 1; pass <= maxpass; pass++)
1223
lastPass = (pass == maxpass);
1224
code = dumpPass(&dparams, pass);
1225
if (code) ERROR_EXIT(code);
1227
/* if no failed volumes, we're done */
1228
if ((dparams.volumesDumped + dparams.volumesFailed + dparams.volumesNotDumped) ==
1229
nodePtr->arraySize) break;
1233
* Log the error but ignore it since the dump is effectively done.
1234
* Scantape may assume another volume and ask for next tape.
1237
code = butm_WriteEOT(&tapeInfo);
1238
if (code) TapeLog(taskId, code, tapeInfo.error,
1239
"Warning: Can't write end-of-dump on tape\n");
1242
code = finishTape(&dparams.tape, dparams.tapeInfoPtr->kBytes +
1243
(dparams.tapeInfoPtr->nBytes ? 1 : 0));
1244
if (code) ERROR_EXIT(code);
1246
code = finishDump(&dparams.dump);
1247
if (code) ERROR_EXIT(code);
1249
action = dparams.curVolumeStatus;
1250
code = flushSavedEntries(action);
1251
if (code) ERROR_EXIT(code);
1256
if (bufferBlock) free(bufferBlock);
1259
unmountTape(taskId, &tapeInfo);
1263
dumpedvolumes = dparams.volumesDumped;
1264
nodumpvolumes = dparams.volumesNotDumped;
1265
failedvolumes = nodePtr->arraySize - (dumpedvolumes + nodumpvolumes);
1267
/* pass back the number of volumes we failed to dump */
1269
nodePtr->statusNodePtr->volsFailed = failedvolumes;
1272
lastPass = 1; /* In case we aborted */
1274
DUMPNAME(finishedMsg1, nodePtr->dumpSetName, dparams.databaseDumpId);
1275
sprintf(finishedMsg2, "%d volumes dumped", dumpedvolumes);
1278
sprintf(msg, ", %d failed", failedvolumes);
1279
strcat(finishedMsg2, msg);
1283
sprintf(msg, ", %d unchanged", nodumpvolumes);
1284
strcat(finishedMsg2, msg);
1287
if (code == TC_ABORTEDBYREQUEST)
1289
ErrorLog(0, taskId, 0, 0,
1290
"%s: Aborted by request. %s\n", finishedMsg1, finishedMsg2);
1291
clearStatus(taskId, ABORT_REQUEST);
1292
setStatus (taskId, ABORT_DONE);
1296
ErrorLog(0, taskId, code, 0,
1297
"%s: Finished with errors. %s\n", finishedMsg1, finishedMsg2);
1298
setStatus(taskId, TASK_ERROR);
1302
TLog(taskId, "%s: Finished. %s\n", finishedMsg1, finishedMsg2);
1306
/* Record how long the dump took */
1307
if (centralLogIO && startTime) {
1309
afs_int32 hrs, min, sec, tmp;
1311
struct tm tmstart, tmend;
1313
localtime_r(&startTime, &tmstart);
1314
localtime_r(&endTime, &tmend);
1315
timediff = (int)endTime - (int)startTime;
1316
hrs = timediff / 3600;
1317
tmp = timediff % 3600;
1321
sprintf(line, "%-5d %02d/%02d/%04d %02d:%02d:%02d "
1322
"%02d/%02d/%04d %02d:%02d:%02d "
1324
"%s %d of %d volumes dumped (%ld KB)\n",
1325
taskId, tmstart.tm_mon+1, tmstart.tm_mday, tmstart.tm_year+1900,
1326
tmstart.tm_hour, tmstart.tm_min, tmstart.tm_sec,
1327
tmend.tm_mon+1, tmend.tm_mday, tmend.tm_year+1900,
1328
tmend.tm_hour, tmend.tm_min, tmend.tm_sec,
1329
hrs, min, sec, nodePtr->volumeSetName,
1330
dumpedvolumes, dumpedvolumes+failedvolumes,
1331
dparams.tapeInfoPtr->kBytes+1);
1333
fwrite(line, strlen(line), 1, centralLogIO);
1334
fflush(centralLogIO);
1337
setStatus(taskId, TASK_DONE);
1339
FreeNode(taskId); /* free the dump node */
1340
LeaveDeviceQueue(deviceLatch);
1344
#define BELLTIME 60 /* 60 seconds before a bell rings */
1345
#define BELLCHAR 7 /* ascii for bell */
1348
* prompt the user to decide how to handle a failed volume dump. The
1349
* volume parameters describe the volume that failed
1351
* volumeName - name of volume
1352
* volumeId - volume id
1353
* taskId - for job contrl
1355
* character typed by user, one of r, o or a
1359
retryPrompt(volumeName, volumeId, taskId)
1368
setStatus(taskId, OPR_WAIT);
1369
printf("\nDump of volume %s (%u) failed\n\n", volumeName, volumeId);
1371
printf("Please select action to be taken for this volume\n");
1374
printf("r - retry, try dumping this volume again\n");
1375
printf("o - omit, this volume from this dump\n");
1376
printf("a - abort, the entire dump\n");
1386
#ifdef AFS_PTHREAD_ENV
1387
code = GetResponseKey(5, &ch); /* ch stores key pressed */
1389
code = LWP_GetResponseKey(5, &ch); /* ch stores key pressed */
1392
break; /* input is available */
1394
if ( checkAbortByTaskId(taskId) )
1396
clearStatus(taskId, OPR_WAIT);
1397
printf("This tape operation has been aborted by the coordinator\n");
1401
if (time(0) > start + BELLTIME) break;
1403
/* otherwise, we should beep again, check for abort and go back,
1404
* since the GetResponseKey() timed out.
1407
break; /* input is available */
1409
clearStatus(taskId, OPR_WAIT);
1410
if ( ch != 'r' && ch != 'o' && ch != 'a' )
1412
printf("Please select one of the 3 options, r, o or a\n");
1419
/* For testing: it prints the tape label */
1421
struct butm_tapeLabel *tl;
1423
printf("Tape Label\n");
1424
printf(" structVersion = %d\n", tl->structVersion);
1425
printf(" creationTime = %u\n", tl->creationTime);
1426
printf(" expirationDate = %u\n", tl->expirationDate);
1427
printf(" AFSName = %s\n", tl->AFSName);
1428
printf(" cell = %s\n", tl->cell);
1429
printf(" dumpid = %d\n", tl->dumpid);
1430
printf(" useCount = %d\n", tl->useCount);
1431
printf(" comment = %s\n", tl->comment);
1432
printf(" pName = %s\n", tl->pName);
1433
printf(" size = %u\n", tl->size);
1434
printf(" dumpPath = %s\n", tl->dumpPath);
1438
* Create a tape structure to be satisfy the backup database
1439
* even though we don't really use a tape with XBSA.
1441
getXBSATape(dparamsPtr)
1442
struct dumpRock *dparamsPtr;
1444
struct dumpNode *nodePtr = dparamsPtr->node;
1445
struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
1446
struct butm_tapeLabel *tapeLabelPtr = &dparamsPtr->tapeLabel;
1449
tc_MakeTapeName(dparamsPtr->tapeName, &nodePtr->tapeSetDesc, dparamsPtr->tapeSeq);
1451
GetNewLabel(tapeInfoPtr, ""/*pName*/, dparamsPtr->tapeName, tapeLabelPtr);
1452
strcpy(tapeLabelPtr->dumpPath, nodePtr->dumpName);
1453
tapeLabelPtr->dumpid = dparamsPtr->databaseDumpId;
1454
tapeLabelPtr->expirationDate = calcExpirationDate(nodePtr->tapeSetDesc.expType,
1455
nodePtr->tapeSetDesc.expDate,
1458
/* printTapeLabel(tapeLabelPtr); For testing */
1460
code = useTape(&dparamsPtr->tape,
1461
dparamsPtr->databaseDumpId,
1462
dparamsPtr->tapeName,
1463
(dparamsPtr->tapeSeq + dparamsPtr->dump.tapes.b),
1464
tapeLabelPtr->useCount,
1465
tapeLabelPtr->creationTime,
1466
tapeLabelPtr->expirationDate,
1467
0 /*tape position*/);
1472
* iterate until the desired tape (as specified by the dump structures)
1476
* 0 - assume the tape is there. Prompt if assumption false
1477
* 1 - prompt regardless
1480
getDumpTape(dparamsPtr, interactiveFlag, append)
1481
struct dumpRock *dparamsPtr;
1482
int interactiveFlag;
1485
struct dumpNode *nodePtr = dparamsPtr->node;
1486
struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
1487
struct butm_tapeLabel *newTapeLabelPtr = &dparamsPtr->tapeLabel;
1488
char AFSTapeName[TC_MAXTAPENAMELEN];
1489
afs_int32 taskId = nodePtr->taskID;
1490
struct butm_tapeLabel oldTapeLabel;
1491
struct budb_dumpEntry dumpEntry;
1492
struct budb_tapeEntry tapeEntry;
1493
struct budb_volumeEntry volEntry;
1494
Date oldTapeExpiration, expir;
1498
int askForTape, opcode;
1501
afs_int32 tapepos, lastpos;
1503
extern struct tapeConfig globalTapeConfig;
1504
extern struct udbHandleS udbHandle;
1505
extern afs_int32 BUDB_DeleteDump();
1507
askForTape = interactiveFlag;
1508
dparamsPtr->wroteLabel = 0;
1510
/* Keep prompting for a tape until we get it right */
1513
/* What the name of the tape would be if not appending to it */
1514
tc_MakeTapeName(AFSTapeName, &nodePtr->tapeSetDesc, dparamsPtr->tapeSeq);
1520
code = PromptForTape((doAppend ? APPENDOPCODE : WRITEOPCODE),
1521
AFSTapeName, dparamsPtr->databaseDumpId, taskId, tapecount);
1522
if (code) ERROR_EXIT(code);
1527
/* open the tape device */
1528
code = butm_Mount(tapeInfoPtr, AFSTapeName);
1531
TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
1535
/* Read the tape label */
1536
code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1); /* rewind */
1538
if (tapeInfoPtr->error) {
1539
ErrorLog(0, taskId, code, tapeInfoPtr->error,
1540
"Warning: Tape error while reading label (will proceed with dump)\n");
1542
memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
1545
/* Check if null tape. Prior 3.3, backup tapes have no dump id */
1546
if ( (strcmp(oldTapeLabel.AFSName,"") == 0) && (oldTapeLabel.dumpid == 0) )
1550
TLog(taskId, "Dump not found on tape. Proceeding with initial dump\n");
1554
else if (doAppend) /* appending */
1556
/* Check that we don't have a database dump tape */
1557
if ( databaseTape(oldTapeLabel.AFSName) )
1559
char gotName[BU_MAXTAPELEN+32];
1561
/* label does not match */
1562
LABELNAME(gotName, &oldTapeLabel);
1563
TLog(taskId, "Can't append to database tape %s\n", gotName);
1567
/* Verify that the tape is of version 4 (AFS 3.3) or greater */
1568
if (oldTapeLabel.structVersion < TAPE_VERSION_4)
1570
TLog(taskId, "Can't append: requires tape version %d or greater\n",
1575
/* Verify that the last tape of the dump set is in the drive.
1576
* volEntry will be zeroed if last dump has no volume entries.
1578
code = bcdb_FindLastTape(oldTapeLabel.dumpid, &dumpEntry, &tapeEntry, &volEntry);
1580
ErrorLog(0, taskId, code, 0,
1581
"Can't append: Can't find last volume of dumpId %u in database\n",
1582
oldTapeLabel.dumpid);
1583
printf("Please scan the dump in or choose another tape\n");
1586
lastpos = (volEntry.position ? volEntry.position : tapeEntry.labelpos);
1588
if (strcmp(TNAME(&oldTapeLabel),tapeEntry.name))
1590
char expName[BU_MAXTAPELEN+32], gotName[BU_MAXTAPELEN+32];
1592
TAPENAME(expName, tapeEntry.name, oldTapeLabel.dumpid);
1593
LABELNAME(gotName, &oldTapeLabel);
1596
"Can't append: Last tape in dump-set is %s, label seen %s\n",
1601
/* After reading the tape label, we now know what it is */
1602
strcpy (AFSTapeName, oldTapeLabel.AFSName); /* the real name */
1603
strcpy (tapeInfoPtr->name, oldTapeLabel.AFSName); /* the real name */
1605
/* Position after last volume on the tape */
1606
code = butm_SeekEODump(tapeInfoPtr, lastpos);
1609
ErrorLog(0, taskId, code, tapeInfoPtr->error,
1610
"Can't append: Can't position to end of dump on tape %s\n",
1615
/* Track size of tape - set after seek since seek changes the value */
1616
tapeInfoPtr->kBytes = tapeEntry.useKBytes;
1618
else /* not appending */
1621
afs_uint32 dmp, parent;
1622
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) )
1630
if ( strcmp(oldTapeLabel.AFSName,"") && /* not null tape */
1631
strcmp(oldTapeLabel.AFSName,AFSTapeName) ) /* not expected name */
1633
TLog(taskId, "Tape label expected %s, label seen %s\n",
1634
AFSTapeName, oldTapeLabel.AFSName);
1638
/* Check that we don't have a database dump tape */
1639
if ( databaseTape(oldTapeLabel.AFSName) )
1641
/* label does not match */
1642
TLog(taskId, "Tape label expected %s, can't dump to database tape %s\n",
1643
AFSTapeName, oldTapeLabel.AFSName);
1648
/* Verify the tape has not expired - only check if not appending */
1649
if ( !tapeExpired(&oldTapeLabel) ) {
1650
TLog(taskId, "This tape has not expired\n");
1654
/* Given a tape dump with good data, verify we don't overwrite recent dumps
1655
* and also verify that the volume will be restorable - if not print warnings
1657
if (oldTapeLabel.dumpid)
1659
/* Do not overwrite a tape that belongs to the dump's dumpset */
1660
tapeid = (dparamsPtr->initialDumpId ? dparamsPtr->initialDumpId :
1661
dparamsPtr->databaseDumpId);
1662
if (oldTapeLabel.dumpid == tapeid)
1664
ErrorLog(0, taskId, 0, 0,
1665
"Can't overwrite tape containing the dump in progress\n");
1669
/* Since the dumpset on this tape will be deleted from database, check if
1670
* any of the dump's parent-dumps are on this tape.
1672
for (dmp=nodePtr->parent; dmp; dmp=de.parent)
1674
code = bcdb_FindDumpByID(dmp, &de);
1676
ErrorLog(0, taskId, 0, 0,
1677
"Warning: Can't find parent dump %u in backup database\n",
1682
tapeid = (de.initialDumpID ? de.initialDumpID : de.id);
1683
if (oldTapeLabel.dumpid == tapeid) {
1684
ErrorLog(0, taskId, 0, 0,
1685
"Can't overwrite the parent dump %s (DumpID %u)\n",
1691
/* Since the dumpset on this tape will be deleted from database, check if
1692
* any of the dumps in this dumpset are most-recent-dumps.
1694
for (dmp=oldTapeLabel.dumpid; dmp; dmp=de.appendedDumpID) {
1695
if (dmp == dparamsPtr->lastDump.id) {
1696
memcpy(&de, &dparamsPtr->lastDump, sizeof(de));
1697
memcpy(&de2, &dparamsPtr->lastDump, sizeof(de2));
1700
code = bcdb_FindDumpByID(dmp, &de);
1702
sprintf(strlevel, "%d", de.level);
1703
code = bcdb_FindLatestDump(de.volumeSetName, strlevel, &de2);
1707
/* If dump on the tape is the latest dump at this level */
1708
if (de.id == de2.id) {
1709
if (strcmp(DUMP_TAPE_NAME,de2.name) == 0) {
1710
ErrorLog(0, taskId, 0, 0,
1711
"Warning: Overwriting most recent dump %s (DumpID %u)\n",
1715
ErrorLog(0, taskId, 0, 0,
1716
"Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
1717
de.volumeSetName, de.name, de.id);
1721
} /* if (oldTapeLabel.dumpid) */
1722
} /* else not appending */
1725
* Now have the right tape. Create a new label for the tape
1726
* Appended labels have the dump's dumpId - labels at beginnings of
1727
* tape have the initial dump's dumpId.
1728
* Appended labels do not increment the useCount.
1729
* Labels at beginnings of tape use the most future expiration of the dump set.
1731
GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, AFSTapeName, newTapeLabelPtr);
1732
strcpy(newTapeLabelPtr->dumpPath, nodePtr->dumpName);
1733
newTapeLabelPtr->expirationDate =
1734
calcExpirationDate(nodePtr->tapeSetDesc.expType, 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);
1752
char gotName[BU_MAXTAPELEN+32];
1754
LABELNAME(gotName, newTapeLabelPtr);
1755
TapeLog(0, taskId, code, tapeInfoPtr->error, "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. */
1766
char gotName[BU_MAXTAPELEN+32];
1768
nodePtr->tapeSetDesc.b = extractTapeSeq(AFSTapeName);
1769
dparamsPtr->dump.tapes.b = nodePtr->tapeSetDesc.b;
1770
dparamsPtr->initialDumpId = oldTapeLabel.dumpid;
1771
strcpy(nodePtr->tapeSetDesc.format, dumpEntry.tapes.format);
1773
code = bcdb_MakeDumpAppended(dparamsPtr->databaseDumpId,
1774
dparamsPtr->initialDumpId, nodePtr->tapeSetDesc.b);
1776
ErrorLog(2, taskId, code, 0,
1777
"Warning: Can't append dump %u to dump %u in database\n",
1778
dparamsPtr->databaseDumpId, dparamsPtr->initialDumpId);
1780
LABELNAME(gotName, &oldTapeLabel);
1781
TLog(taskId, "Appending dump %s (DumpID %u) to tape %s\n",
1782
nodePtr->dumpSetName, dparamsPtr->databaseDumpId, gotName);
1785
/* If not appending, delete overwritten dump from the database */
1788
if ( (oldTapeLabel.structVersion >= TAPE_VERSION_3) && oldTapeLabel.dumpid )
1790
code = bcdb_deleteDump(oldTapeLabel.dumpid, 0, 0, 0);
1791
if ( code && (code != BUDB_NOENT) )
1792
ErrorLog(0, taskId, code, 0,
1793
"Warning: Can't delete old dump %u from database\n",
1794
oldTapeLabel.dumpid);
1798
code = useTape(&dparamsPtr->tape,
1799
dparamsPtr->databaseDumpId,
1800
dparamsPtr->tapeName,
1801
(dparamsPtr->tapeSeq + dparamsPtr->dump.tapes.b),
1802
newTapeLabelPtr->useCount,
1803
newTapeLabelPtr->creationTime,
1804
newTapeLabelPtr->expirationDate,
1808
* The margin of space to check for end of tape is set to the
1809
* amount of space used to write an end-of-tape multiplied by 2.
1810
* The amount of space is size of a 16K volume trailer, a 16K File
1811
* End mark, its EOF marker, a 16K EODump marker, its EOF marker,
1812
* and up to two EOF markers done on close (3 16K blocks + 4 EOF
1815
tc_EndMargin = (3 * 16384 + 4 * globalTapeConfig.fileMarkSize) * 2;
1816
tc_KEndMargin = tc_EndMargin / 1024;
1820
unmountTape(taskId, tapeInfoPtr);
1827
makeVolumeHeader(vhptr, dparamsPtr, fragmentNumber)
1828
struct volumeHeader *vhptr;
1829
struct dumpRock *dparamsPtr;
1832
struct dumpNode *nodePtr = dparamsPtr->node;
1833
struct tc_dumpDesc *curDump;
1836
curDump = &nodePtr->dumps[dparamsPtr->curVolume];
1838
memset(vhptr, 0, sizeof(*vhptr));
1839
strcpy(vhptr->volumeName, curDump->name);
1840
vhptr->volumeID = curDump->vid;
1841
vhptr->cloneDate = curDump->cloneDate;
1842
vhptr->server = curDump->hostAddr;
1843
vhptr->part = curDump->partition;
1844
vhptr->from = curDump->date;
1845
vhptr->frag = fragmentNumber;
1847
vhptr->magic = TC_VOLBEGINMAGIC;
1848
vhptr->dumpID = dparamsPtr->databaseDumpId; /* real dump id */
1849
vhptr->level = nodePtr->level;
1850
vhptr->parentID = nodePtr->parent;
1852
vhptr->versionflags = CUR_TAPE_VERSION;
1853
strcpy(vhptr->dumpSetName, nodePtr->dumpSetName);
1854
strcpy(vhptr->preamble,"H++NAME#");
1855
strcpy(vhptr->postamble,"T--NAME#");
1860
volumeHeader_hton(hostPtr, netPtr)
1861
struct volumeHeader *hostPtr, *netPtr;
1863
struct volumeHeader 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));
1886
/* database related routines */
1889
createDump(dparamsPtr)
1890
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);
1940
if (code == 0) dparamsPtr->databaseDumpId = dumpPtr->id;
1947
* Initialize to a specific server. The first time, we remember the
1948
* server as the original server and go back to it each time we pass 0
1951
afs_int32 InitToServer(afs_int32 taskId, struct butx_transactionInfo *butxInfoP, char *server)
1953
static char origserver[BSA_MAX_DESC];
1955
afs_int32 rc, code=0;
1958
strcpy(origserver,"");
1962
if (!server) server = origserver; /* return to original server */
1963
if (strcmp(server,"") == 0) return 0; /* No server, do nothing */
1964
if (strcmp(butxInfoP->serverName,server) == 0) return 0; /* same server, do nothing */
1965
if (strcmp(origserver,"") == 0) strcpy(origserver, server);/* remember original server */
1967
if (strcmp(butxInfoP->serverName,"") != 0) {
1968
/* If already connected to a server, disconnect from it.
1969
* Check to see if our server does not support switching.
1971
if (!(butxInfo.serverType & XBSA_SERVER_FLAG_MULTIPLE)) {
1972
ErrorLog(0, taskId, TC_BADTASK, 0,
1973
"This version of XBSA libraries does not support switching "
1974
"from server %s to server %s\n",
1975
butxInfoP->serverName, server);
1979
rc = xbsa_Finalize(&butxInfo);
1980
if (rc != XBSA_SUCCESS) {
1981
ErrorLog(0, taskId, rc, 0,
1982
"InitToServer: Unable to terminate the connection to server %s\n",
1983
butxInfoP->serverName);
1988
/* initialize to the new server */
1989
rc = xbsa_Initialize(&butxInfo, xbsaObjectOwner, appObjectOwner, xbsaSecToken, server);
1990
if (rc != XBSA_SUCCESS) {
1991
ErrorLog(0, taskId, rc, 0,
1992
"InitToServer: Unable to initialize the XBSA library to server %s\n",
2006
struct deleteDumpIf *ptr;
2009
afs_int32 rc, code=0;
2011
afs_int32 index, next, dbTime;
2013
struct budb_dumpEntry dumpEntry;
2014
char tapeName[BU_MAXTAPELEN];
2015
char dumpIdStr[XBSA_MAX_OSNAME];
2016
char volumeNameStr[XBSA_MAX_PATHNAME];
2019
int allnotfound=1, onenotfound=0;
2020
extern struct udbHandleS udbHandle;
2021
extern struct deviceSyncNode *deviceLatch;
2023
setStatus(taskId, DRIVE_WAIT);
2024
EnterDeviceQueue(deviceLatch);
2025
clearStatus(taskId, DRIVE_WAIT);
2027
dumpid = ptr->dumpID;
2028
taskId = ptr->taskId; /* Get task Id */
2031
TapeLog(2, taskId, 0, 0, "Delete Dump %u\n", dumpid);
2033
vl.budb_volumeList_len = 0;
2034
vl.budb_volumeList_val = 0;
2037
/* Get the dump info for the dump we are deleting */
2038
rc = bcdb_FindDumpByID(dumpid, &dumpEntry);
2040
ErrorLog(0, taskId, rc, 0, "Unable to locate dump ID %u in database\n", dumpid);
2041
setStatus(taskId, TASK_ERROR);
2045
/* we must make sure that we are configured with the correct type of
2046
* XBSA server for this dump delete! Only those dumped to an ADSM server.
2048
if ( (xbsaType == XBSA_SERVER_TYPE_ADSM) &&
2049
!((dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) ) {
2050
ErrorLog(0, taskId, TC_BADTASK, 0,
2051
"The dump %u requested for deletion is incompatible with this instance of butc\n",
2053
setStatus(taskId, TASK_ERROR);
2054
ERROR_EXIT(TC_BADTASK);
2057
/* Make sure we are connected to the correct server. If not, switch to it if appropriate */
2058
if ( (strlen((char *)dumpEntry.tapes.tapeServer) != 0) &&
2059
(strcmp((char *)dumpEntry.tapes.tapeServer,butxInfo.serverName) != 0)) {
2061
/* Check to see if the tapeServer name is trustworthy */
2062
if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA)) && !forcemultiple) {
2063
/* The dump was made with a version of the XBSA interface
2064
* that didn't allow switching of servers, we can't be sure
2065
* that the servername in the backup database is correct. So,
2066
* we will check the servername and log it if they don't match;
2067
* but we will try to do the delete without switching servers.
2069
TLog(taskId, "The dump %d requested for deletion is on server %s "
2070
"but butc is connected to server %s "
2071
"(Attempting to delete the dump anyway)\n",
2072
dumpid, (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
2074
TLog(taskId, "The dump %u requested for deletion is on server %s "
2075
"but butc is connected to server %s "
2076
"(switching servers)\n",
2077
dumpid, (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
2079
rc = InitToServer(taskId, &butxInfo, (char *)dumpEntry.tapes.tapeServer);
2080
if (rc != XBSA_SUCCESS) {
2081
setStatus(taskId, TASK_ERROR);
2087
/* Start a new Transaction */
2088
rc = xbsa_BeginTrans(&butxInfo);
2089
if (rc != XBSA_SUCCESS) {
2090
ErrorLog(0, taskId, rc, 0, "Unable to create a new transaction\n");
2091
setStatus(taskId, TASK_ERROR);
2096
/* Query the backup database for list of volumes to delete */
2097
for (index=next=0; index!=-1; index=next) {
2098
rc = ubik_Call_SingleServer(BUDB_GetVolumes, udbHandle.uh_client,
2099
UF_SINGLESERVER, BUDB_MAJORVERSION,
2106
if (rc == BUDB_ENDOFLIST) break;
2107
ErrorLog(0, taskId, rc, 0, "Can't find volume info for dump %d\n", dumpid);
2108
setStatus(taskId, TASK_ERROR);
2112
/* Delete all volumes on the list */
2113
for (i=0; i<vl.budb_volumeList_len; i++) {
2114
if (dumpEntry.flags & BUDB_DUMP_BUTA) {
2115
/* dump was from buta, use old buta style names */
2116
sprintf(dumpIdStr, "/%d", dumpid);
2117
strcpy(volumeNameStr, "/");
2118
strcat(volumeNameStr, (char *)vl.budb_volumeList_val[i].name);
2119
} else { /* BUDB_DUMP_ADSM */
2120
/* dump was from butc to ADSM, use butc names */
2121
strcpy(dumpIdStr, butcdumpIdStr);
2122
sprintf(volumeNameStr, "/%d", dumpid);
2123
strcat(volumeNameStr, "/");
2124
strcat(volumeNameStr, (char *)vl.budb_volumeList_val[i].name);
2127
rc = xbsa_DeleteObject(&butxInfo, dumpIdStr, volumeNameStr);
2128
if (rc != XBSA_SUCCESS) {
2129
ErrorLog(0, taskId, rc, 0,
2130
"Unable to delete the object %s of dump %s from the server\n",
2131
volumeNameStr, dumpIdStr);
2132
/* Don't exit if volume was not found */
2133
if (rc != BUTX_DELETENOVOL) {
2140
TLog(0, "Deleted volume %s (%u) in dumpID %u from the backup server\n",
2141
vl.budb_volumeList_val[i].name, vl.budb_volumeList_val[i].id, dumpid);
2145
/* free the memory allocated by RPC for this list */
2146
if (vl.budb_volumeList_val) free(vl.budb_volumeList_val);
2147
vl.budb_volumeList_len = 0;
2148
vl.budb_volumeList_val = 0;
2153
rc = xbsa_EndTrans(&butxInfo);
2154
if (rc != XBSA_SUCCESS) {
2155
ErrorLog(0, taskId, rc, 0, "Unable to terminate the current transaction\n");
2156
setStatus(taskId, TASK_ERROR);
2161
/* Switch back to the original server */
2162
rc = InitToServer(taskId, &butxInfo, (char *)0);
2164
if (vl.budb_volumeList_val) free(vl.budb_volumeList_val);
2166
setStatus(taskId, TASK_DONE);
2167
FreeNode(taskId); /* free the dump node */
2168
LeaveDeviceQueue(deviceLatch);
2170
/* If we don't find any dumps on the server, rather than returning
2171
* a success, return a failure.
2173
if (!code && onenotfound && allnotfound) {
2174
code = BUTX_DELETENOVOL;
2175
setStatus(taskId, TASK_ERROR);