~ubuntu-branches/ubuntu/warty/openafs/warty

« back to all changes in this revision

Viewing changes to src/butc/dump.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2004-01-10 16:37:33 UTC
  • Revision ID: james.westby@ubuntu.com-20040110163733-jvr0n1uahshlb1uu
Tags: upstream-1.2.11
ImportĀ upstreamĀ versionĀ 1.2.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2000, International Business Machines Corporation and others.
 
3
 * All Rights Reserved.
 
4
 * 
 
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
 
8
 */
 
9
 
 
10
#include <afsconfig.h>
 
11
#include <afs/param.h>
 
12
 
 
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 $");
 
14
 
 
15
#include <sys/types.h>
 
16
#ifdef AFS_NT40_ENV
 
17
#include <winsock2.h>
 
18
#else
 
19
#include <sys/time.h>
 
20
#include <sys/file.h>
 
21
#include <netinet/in.h>
 
22
#include <sys/socket.h>
 
23
#include <netdb.h>
 
24
#endif
 
25
#include <stdlib.h>
 
26
#include <rx/xdr.h>
 
27
#include <rx/rx.h>
 
28
#include <lwp.h>
 
29
#include <lock.h>
 
30
#include <errno.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>
 
40
 
 
41
#include "error_macros.h"
 
42
#include "butc_xbsa.h"
 
43
#include "afs/butx.h"
 
44
 
 
45
 
 
46
/* GLOBAL CONFIGURATION PARAMETERS */
 
47
extern int dump_namecheck;
 
48
extern int queryoperator;
 
49
extern int isafile;
 
50
extern int forcemultiple;
 
51
 
 
52
extern struct ubik_client *cstruct;
 
53
dlqlinkT savedEntries;
 
54
dlqlinkT entries_to_flush;
 
55
 
 
56
afs_int32 flushSavedEntries(), finishDump(), finishTape(), useTape(), addVolume();
 
57
 
 
58
extern struct rx_connection *UV_Bind();
 
59
 
 
60
extern char *globalCellName;
 
61
 
 
62
extern afs_int32 xbsaType;
 
63
extern afs_int32 groupId;
 
64
extern afs_int32 BufferSize;
 
65
extern afs_int32 statusSize;
 
66
extern FILE  *centralLogIO;
 
67
afs_int32 lastPass=0;
 
68
#ifdef xbsa
 
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;
 
76
#endif /*xbsa*/
 
77
 
 
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) */
 
80
 
 
81
/* TBD
 
82
 *
 
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
 
90
 *
 
91
 * notes
 
92
 * pass 3: 
 
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.
 
96
 */
 
97
 
 
98
#define DUMPNAME(dumpname, name, dbDumpId) \
 
99
   if (dbDumpId == 0) \
 
100
     sprintf(dumpname, "%s", name); \
 
101
   else \
 
102
     sprintf(dumpname, "%s (DumpId %u)", name, dbDumpId);
 
103
 
 
104
#if defined(AFS_NT40_ENV) || (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN60_ENV)) || defined(AFS_SUN4_ENV)
 
105
localtime_r(t, tm)
 
106
   time_t *t;
 
107
   struct tm *tm;
 
108
{
 
109
   memcpy(tm, localtime(t), sizeof(struct tm));
 
110
}
 
111
#endif
 
112
 
 
113
struct dumpRock
 
114
{
 
115
    /* status only */
 
116
    int         tapeSeq;
 
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) */
 
125
 
 
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 */
 
131
 
 
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*/
 
136
 
 
137
    /* links to existing info */
 
138
    struct dumpNode *node;
 
139
};
 
140
 
 
141
/* configuration variables */
 
142
#define HITEOT(code) ((code == BUTM_IO) || (code == BUTM_EOT) || (code == BUTM_IOCTL))
 
143
extern int autoQuery;
 
144
extern int maxpass;
 
145
 
 
146
afs_int32 tc_EndMargin;
 
147
afs_int32 tc_KEndMargin;
 
148
char  *bufferBlock;
 
149
 
 
150
/* compute the absolute expiration date */
 
151
afs_int32
 
152
calcExpirationDate(expType, expDate, createTime)
 
153
     afs_int32 expType;
 
154
     afs_int32 expDate;
 
155
     afs_int32 createTime;
 
156
{
 
157
    struct ktime_date kd;
 
158
    afs_int32  Add_RelDate_to_Time();
 
159
 
 
160
    switch ( expType )
 
161
    {
 
162
      case BC_REL_EXPDATE:
 
163
        /* expiration date is relative to the creation time of the dump.
 
164
         * This is the only case that requires any work
 
165
         */
 
166
        Int32To_ktimeRelDate(expDate, &kd);
 
167
        return(Add_RelDate_to_Time(&kd, createTime)); 
 
168
        break;
 
169
 
 
170
      case BC_ABS_EXPDATE:
 
171
        return(expDate);
 
172
        break;
 
173
 
 
174
      case BC_NO_EXPDATE:
 
175
      default:
 
176
        return(0);
 
177
    }
 
178
}
 
179
 
 
180
afs_int32                 curr_bserver = 0;
 
181
struct rx_connection  *curr_fromconn = (struct rx_connection *)0;
 
182
 
 
183
struct rx_connection *Bind(server)
 
184
  afs_int32 server;
 
185
{
 
186
  if (curr_fromconn) {
 
187
      if (curr_bserver == server)                             /* Keep connection if have it */
 
188
          return (curr_fromconn);
 
189
 
 
190
      rx_DestroyConnection (curr_fromconn);                   /* Otherwise get rid of it */
 
191
      curr_fromconn = (struct rx_connection *)0;
 
192
      curr_bserver  = 0;
 
193
  }
 
194
    
 
195
  if (server) {
 
196
      curr_fromconn = UV_Bind (server, AFSCONF_VOLUMEPORT);   /* Establish new connection */
 
197
      if (curr_fromconn) curr_bserver = server;
 
198
  }
 
199
 
 
200
  return (curr_fromconn);
 
201
}
 
202
 
 
203
/* notes
 
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
 
208
 *      further dumps.
 
209
 * 
 
210
 */
 
211
#define BIGCHUNK 102400
 
212
 
 
213
afs_int32
 
214
dumpVolume(curDump, dparamsPtr)
 
215
    struct tc_dumpDesc *curDump;
 
216
    struct dumpRock *dparamsPtr;
 
217
{
 
218
    struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
 
219
    struct dumpNode      *nodePtr     = dparamsPtr->node;
 
220
    afs_int32  taskId                     = nodePtr->taskID;
 
221
    char    *buffer;
 
222
    int     fragmentNumber;
 
223
    afs_int32   volumeFlags;
 
224
    afs_int32   kRemaining;
 
225
    afs_int32   rc, code = 0;
 
226
    afs_int32   toread;
 
227
    afs_uint32 volBytesRead;
 
228
    afs_uint32 chunkSize;
 
229
    afs_int32   bytesread;             /* rx reads */
 
230
    int     endofvolume=0;         /* Have we read all volume data */
 
231
    int     indump=0;
 
232
    int     fragmentvolume;
 
233
    struct volumeHeader  hostVolumeHeader;
 
234
 
 
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;
 
241
 
 
242
    dparamsPtr->curVolumeStatus = DUMP_NOTHING;
 
243
 
 
244
    fromconn = Bind(htonl(curDump->hostAddr));  /* get connection to the server */
 
245
 
 
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);
 
254
 
 
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 */
 
259
        ERROR_EXIT(0);
 
260
    }
 
261
 
 
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);
 
266
 
 
267
    rc = StartAFSVolDump (fromcall, fromtid, curDump->date);
 
268
    if (rc) ERROR_EXIT(rc);
 
269
 
 
270
    dparamsPtr->curVolumeStatus = DUMP_PARTIAL;
 
271
    dparamsPtr->curVolStartPos  = tapeInfoPtr->position;
 
272
 
 
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.
 
276
     */
 
277
    buffer = bufferBlock + BUTM_HDRSIZE;
 
278
 
 
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' 
 
281
     * 2 or more tapes.
 
282
     */
 
283
    for (fragmentNumber=1; !endofvolume; fragmentNumber++) { /*frag*/
 
284
        rc = butm_WriteFileBegin(tapeInfoPtr);
 
285
        if (rc) {
 
286
           ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write FileBegin on tape\n");
 
287
           ERROR_EXIT(rc);
 
288
        }
 
289
        indump = 1;     /* first write to tape */
 
290
 
 
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);
 
295
 
 
296
        rc = butm_WriteFileData(tapeInfoPtr, buffer, 1, sizeof(hostVolumeHeader));
 
297
        if (rc) {
 
298
           ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write VolumeHeader on tape\n");
 
299
           ERROR_EXIT(rc);
 
300
        }
 
301
 
 
302
        bytesWritten = BUTM_BLOCKSIZE; /* Wrote one tapeblock */
 
303
        tsize += bytesWritten;
 
304
 
 
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.
 
309
         */
 
310
        volBytesRead = 0;
 
311
        chunkSize    = 0;
 
312
        fragmentvolume = 0;
 
313
        while (!endofvolume && !fragmentvolume) { /*w*/
 
314
            bytesread = 0;
 
315
 
 
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);
 
321
 
 
322
                /* set bytes dumped for backup */
 
323
                lock_Status();
 
324
                nodePtr->statusNodePtr->nKBytes = tapeInfoPtr->kBytes;
 
325
                unlock_Status();
 
326
            }
 
327
 
 
328
            /* Determine how much data to read in upcoming RX_Read() call */
 
329
            toread = dataSize;
 
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.
 
337
             */
 
338
            kRemaining = butm_remainingKSpace(tapeInfoPtr);
 
339
            if ( (kRemaining < tc_KEndMargin) &&
 
340
                 (volBytesRead || (tapeInfoPtr->position > (isafile?3:2))) ) {
 
341
               fragmentvolume = 1;
 
342
            }
 
343
 
 
344
 
 
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;
 
349
               } else {
 
350
                  toread = ((kRemaining/16) + 1) * BUTM_BLKSIZE;
 
351
                  if (toread > dataSize) toread = dataSize;
 
352
               }
 
353
            }
 
354
 
 
355
            /* Read some volume data. */
 
356
            if (fragmentvolume) {
 
357
               bytesread = 0;
 
358
            } else {
 
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);
 
365
                  endofvolume = 1;
 
366
               }
 
367
            }
 
368
 
 
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);
 
377
            }
 
378
 
 
379
            /* Write the datablock out */
 
380
            /* full data buffer - write it to tape */
 
381
            rc = butm_WriteFileData(tapeInfoPtr, buffer, tapeblocks, bytesread);
 
382
            if (rc) {
 
383
               ErrorLog(1, taskId, rc, tapeInfoPtr->error, 
 
384
                        "Can't write VolumeData on tape\n");
 
385
               ERROR_EXIT(rc);
 
386
            }
 
387
            bytesWritten = tapeblocks * BUTM_BLOCKSIZE;
 
388
            tsize += bytesWritten;
 
389
 
 
390
            /* Display a status line every statusSize or at end of volume */
 
391
            if ( statusSize && 
 
392
                 ((tsize >= statuscount) || endofvolume || fragmentvolume) ) {
 
393
               time_t t = time(0);
 
394
               struct tm tm;
 
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;
 
400
            }
 
401
        } /*w*/
 
402
 
 
403
        /* End the dump before recording it in BUDB as successfully dumped */
 
404
        rc = butm_WriteFileEnd(tapeInfoPtr);
 
405
        indump = 0;
 
406
        if (rc) {
 
407
           ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write FileEnd on tape\n");
 
408
           ERROR_EXIT(rc);
 
409
        }
 
410
 
 
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);
 
421
 
 
422
        /* If haven't finished dumping the volume, end this
 
423
         * tape and get the next tape.
 
424
         */
 
425
        if (!endofvolume) {
 
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.
 
429
            */
 
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");
 
433
 
 
434
           /* Unmount the tape */
 
435
           unmountTape(taskId, tapeInfoPtr);
 
436
 
 
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);
 
441
 
 
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);
 
446
 
 
447
           dparamsPtr->curVolStartPos  = tapeInfoPtr->position;
 
448
        }
 
449
    } /*frag*/
 
450
 
 
451
    dparamsPtr->curVolumeStatus = DUMP_SUCCESS;
 
452
 
 
453
error_exit:
 
454
    /* 
 
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.
 
457
     */
 
458
    if (!code) code = rc;
 
459
    if (HITEOT(code)) {
 
460
        ErrorLog(2, taskId, code, tapeInfoPtr->error, 
 
461
                 "Warning: Dump (%s) hit end-of-tape inferred\n", 
 
462
                 nodePtr->dumpSetName);
 
463
 
 
464
        if (tapeInfoPtr->position == 2) {
 
465
            dparamsPtr->curVolumeStatus = DUMP_NORETRYEOT;
 
466
        } else {
 
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);
 
471
        }
 
472
    }
 
473
 
 
474
    /* 
 
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
 
477
     * the end of tape.
 
478
     */
 
479
    else if (indump) {
 
480
       rc = butm_WriteFileEnd(tapeInfoPtr);
 
481
       indump = 0;
 
482
       if (rc) {
 
483
          ErrorLog(1, taskId, rc, tapeInfoPtr->error, "Can't write FileEnd on tape\n");
 
484
       }
 
485
    }
 
486
 
 
487
    if (fromcall) {
 
488
        rc = rx_EndCall (fromcall, 0);
 
489
        if (!code) code = rc;
 
490
    }
 
491
 
 
492
    if (fromtid) {
 
493
        afs_int32 rcode;
 
494
        rc = AFSVolEndTrans (fromconn, fromtid, &rcode);
 
495
        if (!code) code = (rc ? rc : rcode);
 
496
    }
 
497
 
 
498
    return(code);
 
499
 
 
500
abort_exit:
 
501
    dparamsPtr->curVolumeStatus = DUMP_FAILED;
 
502
    ERROR_EXIT(code);
 
503
}
 
504
 
 
505
afs_int32
 
506
xbsaDumpVolume(curDump, dparamsPtr)
 
507
    struct tc_dumpDesc *curDump;
 
508
    struct dumpRock *dparamsPtr;
 
509
{
 
510
#ifdef xbsa
 
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;
 
516
    afs_int32  toread;
 
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;
 
523
 
 
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;
 
530
    afs_hyper_t          estSize;
 
531
 
 
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";
 
536
 
 
537
    dparamsPtr->curVolumeStatus = DUMP_NOTHING;
 
538
 
 
539
    fromconn = Bind(htonl(curDump->hostAddr));  /* get connection to the server */
 
540
 
 
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);
 
549
 
 
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;
 
553
 
 
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 */
 
558
        ERROR_EXIT(0);
 
559
    }
 
560
 
 
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");
 
565
       ERROR_EXIT(rc);
 
566
    }
 
567
    begindump = 1; /* Will need to do an xbsa_EndTrans */
 
568
 
 
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().
 
574
     */
 
575
    rc = AFSVolTransCreate (fromconn, curDump->vid, curDump->partition, ITBusy, &fromtid);
 
576
    if (rc) ERROR_EXIT(rc);
 
577
    fromcall = rx_NewCall(fromconn);
 
578
    
 
579
    rc = StartAFSVolDump (fromcall, fromtid, curDump->date);
 
580
    if (rc) ERROR_EXIT(rc);
 
581
 
 
582
    dparamsPtr->curVolumeStatus = DUMP_PARTIAL;
 
583
    dparamsPtr->curVolStartPos  = tapeInfoPtr->position;
 
584
 
 
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 */
 
592
 
 
593
    rc = xbsa_WriteObjectBegin(&butxInfo, dumpIdStr, volumeNameStr,
 
594
                               xbsalGName, estSize, dumpDescription,
 
595
                               objectDescription);
 
596
    if (rc != XBSA_SUCCESS) {
 
597
       ErrorLog(1, taskId, rc, 0, 
 
598
                "Unable to begin writing of the fileset data to the server\n");
 
599
       ERROR_EXIT(rc);
 
600
    }
 
601
    indump = 1;   /* Will need to do an xbsa_WriteObjectEnd */
 
602
 
 
603
    /* Create and Write the volume header */
 
604
    makeVolumeHeader(&hostVolumeHeader, dparamsPtr, 1);
 
605
    hostVolumeHeader.contd = 0;
 
606
    volumeHeader_hton(&hostVolumeHeader, buffer);
 
607
 
 
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");
 
611
       ERROR_EXIT(rc);
 
612
    }
 
613
    /* There is a bug in the ADSM library where the bytesWritten is
 
614
     * not filled in, so we set it as correct anyway.
 
615
     */
 
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);
 
622
    }
 
623
 
 
624
    incSize(tapeInfoPtr, sizeof(struct volumeHeader)); /* Increment amount we've written */
 
625
    tsize += bytesWritten;
 
626
 
 
627
    /* Start reading volume data, rx_Read(), and dumping to the tape
 
628
     * until we've dumped the entire volume (endofvolume == 1).
 
629
     */
 
630
    volBytesRead = 0;
 
631
    chunkSize    = 0;
 
632
    while (!endofvolume) { /*w*/
 
633
       bytesread = 0;
 
634
 
 
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);
 
640
 
 
641
          /* set bytes dumped for backup */
 
642
          lock_Status();
 
643
          nodePtr->statusNodePtr->nKBytes = tapeInfoPtr->kBytes;
 
644
          unlock_Status();
 
645
       }
 
646
 
 
647
       /* Determine how much data to read in upcoming RX_Read() call */
 
648
       toread = dataSize;
 
649
 
 
650
       /* Read some volume data. */
 
651
       bytesread = rx_Read(fromcall, buffer, toread);
 
652
       volBytesRead += bytesread;
 
653
       if (bytesread != toread) {
 
654
          afs_int32 rcode;
 
655
 
 
656
          /* Make sure were at end of volume and not a communication error */
 
657
          rc = rx_Error(fromcall);
 
658
          if (rc) ERROR_EXIT(rc);
 
659
 
 
660
          endofvolume = 1;
 
661
 
 
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);
 
669
 
 
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).
 
673
           */
 
674
          rc = rx_EndCall (fromcall, 0);
 
675
          fromcall = 0;
 
676
          if (rc) ERROR_EXIT(rc);
 
677
 
 
678
          rc = AFSVolEndTrans (fromconn, fromtid, &rcode);
 
679
          fromtid = 0;
 
680
          if (rc) ERROR_EXIT(rc);
 
681
       }
 
682
 
 
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");
 
687
          ERROR_EXIT(rc);
 
688
       }
 
689
       /* There is a bug in the ADSM library where the bytesWritten is
 
690
        * not filled in, so we set it as correct anyway.
 
691
        */
 
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);
 
698
       }
 
699
 
 
700
       incSize(tapeInfoPtr, bytesread);       /* Increment amount we've written */
 
701
       tsize += bytesWritten;
 
702
 
 
703
       /* Display a status line every statusSize or at end of volume */
 
704
       if ( statusSize && ((tsize >= statuscount) || endofvolume) ) {
 
705
          time_t t = time(0);
 
706
          struct tm tm;
 
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;
 
712
       }
 
713
    } /*w*/
 
714
 
 
715
    /* End the XBSA transaction before recording it in BUDB as successfully dumped */
 
716
    rc = xbsa_WriteObjectEnd(&butxInfo);
 
717
    indump = 0;
 
718
    if (rc != XBSA_SUCCESS) {
 
719
       ErrorLog(1, taskId, rc, 0,
 
720
                "Unable to terminate writing of the volume data to the server");
 
721
       ERROR_EXIT(rc);
 
722
    }
 
723
    rc = xbsa_EndTrans(&butxInfo);
 
724
    begindump = 0;
 
725
    tapeInfoPtr->position++;
 
726
    if (rc != XBSA_SUCCESS) {
 
727
       ErrorLog(1, taskId, rc, 0, "Unable to terminate the current transaction");
 
728
       ERROR_EXIT(rc);
 
729
    }
 
730
 
 
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);
 
740
 
 
741
    dparamsPtr->curVolumeStatus = DUMP_SUCCESS;
 
742
 
 
743
error_exit:
 
744
    /* Cleanup after an error occurs part way into a volume dump */
 
745
    if (fromcall) {
 
746
       rc = rx_EndCall (fromcall, 0);
 
747
       if (!code) code = rc;
 
748
    }
 
749
 
 
750
    if (fromtid) {
 
751
       afs_int32 rcode;
 
752
       rc = AFSVolEndTrans (fromconn, fromtid, &rcode);
 
753
       if (!code) code = (rc ? rc : rcode);
 
754
    }
 
755
    
 
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).
 
761
     */
 
762
    if (indump) {
 
763
       /* End the Write */
 
764
       rc = xbsa_WriteObjectEnd(&butxInfo);
 
765
       indump = 0;
 
766
       if (rc != XBSA_SUCCESS) {
 
767
          ErrorLog(1, taskId, rc, 0,
 
768
                   "Unable to terminate writing of the volume data to the server");
 
769
       }
 
770
       tapeInfoPtr->position++;
 
771
    }
 
772
 
 
773
    if (begindump) {
 
774
       /* End the XBSA Transaction */
 
775
       rc = xbsa_EndTrans(&butxInfo);
 
776
       begindump = 0;
 
777
       if (rc != XBSA_SUCCESS) {
 
778
          ErrorLog(1, taskId, rc, 0, "Unable to terminate the current transaction");
 
779
       }
 
780
    }
 
781
 
 
782
    return(code);
 
783
 
 
784
abort_exit:
 
785
    dparamsPtr->curVolumeStatus = DUMP_FAILED;
 
786
    ERROR_EXIT(code);
 
787
#endif
 
788
}
 
789
 
 
790
#ifdef AFS_DEC_ENV
 
791
#define HOSTADDR(sockaddr) (sockaddr)->sin_addr.S_un.S_addr
 
792
#else
 
793
#define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr
 
794
#endif
 
795
 
 
796
/* dumpPass
 
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.
 
800
 * notes:
 
801
 *      flushSavedEntries - inconsistent treatment for errors. What should
 
802
 *              be done for user aborts?
 
803
 */
 
804
 
 
805
afs_int32
 
806
dumpPass(dparamsPtr, passNumber)
 
807
    struct dumpRock *dparamsPtr;
 
808
    int passNumber;
 
809
{
 
810
    struct dumpNode      *nodePtr     = dparamsPtr->node;
 
811
    struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr;
 
812
    afs_int32                taskId       = nodePtr->taskID;
 
813
    struct tc_dumpDesc *curDump;
 
814
    int  action, e;
 
815
    afs_int32 code = 0, tcode, dvcode;
 
816
    char ch;
 
817
    char retryPrompt();
 
818
    struct vldbentry vldbEntry;
 
819
    struct sockaddr_in server;
 
820
    afs_int32  tapepos;
 
821
 
 
822
    TapeLog(2, taskId, 0, 0, "Starting pass %d\n", passNumber);
 
823
 
 
824
    /* while there are more volumes to dump */
 
825
    for (dparamsPtr->curVolume = 0; 
 
826
         dparamsPtr->curVolume < nodePtr->arraySize; 
 
827
         dparamsPtr->curVolume++)
 
828
    { /*w*/
 
829
        curDump = &nodePtr->dumps[dparamsPtr->curVolume];
 
830
        if (curDump->hostAddr == 0) continue;
 
831
 
 
832
        /* set name of current volume being dumped */
 
833
        lock_Status();
 
834
        strcpy(nodePtr->statusNodePtr->volumeName, curDump->name); 
 
835
        unlock_Status();
 
836
 
 
837
        /* Determine location of the volume.
 
838
         * In case the volume moved has moved.
 
839
         */
 
840
        if (passNumber > 1)
 
841
        { /*pass*/
 
842
            tcode = bc_GetEntryByID(cstruct, curDump->vid, curDump->vtype, &vldbEntry);
 
843
            if (tcode)
 
844
            {
 
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++;
 
850
                continue;
 
851
            }
 
852
 
 
853
            switch (curDump->vtype)
 
854
            {
 
855
                case BACKVOL:
 
856
                    if ( !(vldbEntry.flags & BACK_EXISTS) )
 
857
                    {
 
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++;
 
863
                        continue;
 
864
                    }
 
865
                    /* Fall into RWVOL case */
 
866
 
 
867
                  case RWVOL:
 
868
                      for (e=0; e<vldbEntry.nServers; e++) /* Find the RW volume */
 
869
                      {
 
870
                          if (vldbEntry.serverFlags[e] & ITSRWVOL) break;
 
871
                      }
 
872
                      break;
 
873
                    
 
874
                  case ROVOL:           
 
875
                      /* Try to use the server and partition we found the volume on
 
876
                       * Otherwise, use the first RO volume.
 
877
                       */
 
878
                      for (e=0; e<vldbEntry.nServers; e++) /* Find the RO volume */
 
879
                      {
 
880
                          if ( (curDump->hostAddr  == vldbEntry.serverNumber[e]   ) &&
 
881
                               (curDump->partition == vldbEntry.serverPartition[e]) )
 
882
                              break;
 
883
                      }
 
884
 
 
885
                      if (e >= vldbEntry.nServers)
 
886
                      {                                           /* Didn't find RO volume */
 
887
                          for (e=0; e<vldbEntry.nServers; e++)    /* Find the first RO volume */
 
888
                          {
 
889
                              if (vldbEntry.serverFlags[e] & ITSROVOL) break;
 
890
                          }
 
891
                      }
 
892
                      break;
 
893
 
 
894
                  default:
 
895
                      ErrorLog(0, taskId, 0, 0,
 
896
                               "Volume %s (%u) failed - Unknown volume type\n",
 
897
                               curDump->name, curDump->vid);
 
898
                      curDump->hostAddr = 0;
 
899
                      continue;
 
900
                      break;
 
901
                }
 
902
 
 
903
            if (e >=vldbEntry.nServers)
 
904
            {
 
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++;
 
910
                continue;
 
911
            }
 
912
 
 
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];
 
916
            server.sin_port        = 0;
 
917
            server.sin_family      = AF_INET;
 
918
#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
 
919
            server.sin_len         = sizeof(struct sockaddr_in);
 
920
#endif
 
921
            curDump->hostAddr      = HOSTADDR(&server);
 
922
            curDump->partition     = vldbEntry.serverPartition[e];
 
923
 
 
924
            /* Determine date from which to do an incremental dump
 
925
             */
 
926
            if (nodePtr->parent)
 
927
            {
 
928
                tcode = bcdb_FindClone(nodePtr->parent, curDump->name, &curDump->date);
 
929
                if (tcode) curDump->date = 0;
 
930
            }
 
931
            else
 
932
            {
 
933
                curDump->date = 0;    /* do a full dump */
 
934
            }
 
935
        } /*pass*/
 
936
 
 
937
        if ( checkAbortByTaskId(taskId) ) 
 
938
            ERROR_EXIT(TC_ABORTEDBYREQUEST);
 
939
            
 
940
        /* Establish connection to volume - UV_ routine expects 
 
941
         * host address in network order 
 
942
         */
 
943
        if (CONF_XBSA) {
 
944
           dvcode = xbsaDumpVolume(curDump, dparamsPtr);
 
945
        } else {
 
946
           dvcode = dumpVolume(curDump, dparamsPtr);
 
947
        }
 
948
        action = dparamsPtr->curVolumeStatus;
 
949
 
 
950
        /* Flush volume and tape entries to the database */
 
951
        tcode = flushSavedEntries(action);
 
952
        if (tcode) ERROR_EXIT(tcode);
 
953
 
 
954
        switch (action)
 
955
        {
 
956
           case DUMP_SUCCESS:
 
957
                TapeLog(1, taskId, 0, 0, "Volume %s (%u) successfully dumped\n",
 
958
                        curDump->name, curDump->vid);
 
959
                if (dvcode)
 
960
                    ErrorLog(1, taskId, dvcode, 0,
 
961
                             "Warning: Termination processing error on volume %s (%u)\n",
 
962
                             curDump->name, curDump->vid);
 
963
 
 
964
                curDump->hostAddr = 0;
 
965
                dparamsPtr->volumesDumped++;
 
966
                break;
 
967
                
 
968
           case DUMP_PARTIAL:
 
969
           case DUMP_NOTHING:
 
970
                if (action == DUMP_PARTIAL)
 
971
                {
 
972
                    ErrorLog(1, taskId, dvcode, 0, 
 
973
                             "Volume %s (%u) failed - partially dumped\n",
 
974
                             curDump->name, curDump->vid);
 
975
                }
 
976
                else if (dvcode)
 
977
                {
 
978
                    ErrorLog(0, taskId, dvcode, 0,
 
979
                       "Volume %s (%u) failed\n", curDump->name, curDump->vid);
 
980
                }
 
981
                else
 
982
                {
 
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);
 
986
                }
 
987
 
 
988
                if (passNumber == maxpass)
 
989
                {
 
990
                    if (!queryoperator)
 
991
                        ch = 'o';
 
992
                    else
 
993
                        ch = retryPrompt(curDump->name, curDump->vid, taskId);
 
994
 
 
995
                    switch ( ch )
 
996
                    {
 
997
                       case 'r':                                    /* retry */
 
998
                           dparamsPtr->curVolume--;      /* redump this volume */
 
999
                           continue;
 
1000
                           break;
 
1001
                        case 'o':                                    /* omit */
 
1002
                           ErrorLog(1, taskId, 0, 0, "Volume %s (%u) omitted\n",
 
1003
                                    curDump->name, curDump->vid);
 
1004
                           dparamsPtr->volumesFailed++;
 
1005
                           break;
 
1006
                        case 'a':                                    /* abort */
 
1007
                           TapeLog(1, taskId, 0, 0, "Dump aborted\n");
 
1008
                           ERROR_EXIT(TC_ABORTEDBYREQUEST);
 
1009
                           break;
 
1010
                        default:
 
1011
                           ERROR_EXIT(TC_INTERNALERROR);
 
1012
                           break;
 
1013
                    }
 
1014
                }
 
1015
                break;
 
1016
                
 
1017
           case DUMP_RETRY:
 
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);
 
1021
 
 
1022
                /* Get the next tape */
 
1023
                unmountTape(taskId, tapeInfoPtr);
 
1024
 
 
1025
                dparamsPtr->tapeSeq++;
 
1026
                tcode = getDumpTape(dparamsPtr, 1, 0);   /* interactive - no appends */
 
1027
                if (tcode) ERROR_EXIT(tcode);
 
1028
 
 
1029
                dparamsPtr->curVolume--;                 /* redump this volume */
 
1030
                continue;
 
1031
                break;
 
1032
 
 
1033
           case DUMP_NORETRYEOT:
 
1034
                ErrorLog(1, taskId, 0, 0, "Volume %s (%u) failed - volume larger than tape\n",
 
1035
                         curDump->name, curDump->vid);
 
1036
 
 
1037
                /* rewrite the label on the tape - rewind - no need to switch tapes */
 
1038
                tcode = butm_Create(tapeInfoPtr, &dparamsPtr->tapeLabel, 1);
 
1039
                if (tcode) {
 
1040
                    ErrorLog(0, taskId, tcode, tapeInfoPtr->error, "Can't relabel tape\n");
 
1041
                    
 
1042
                    unmountTape(taskId, tapeInfoPtr);
 
1043
                    tcode = getDumpTape(dparamsPtr, 1, 0);   /* interactive - no appends */
 
1044
                    if (tcode) ERROR_EXIT(tcode);
 
1045
                }
 
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,
 
1055
                                    tapepos);
 
1056
                }
 
1057
 
 
1058
                curDump->hostAddr = 0;
 
1059
                dparamsPtr->volumesFailed++;
 
1060
                break;
 
1061
 
 
1062
           case DUMP_NODUMP:
 
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);
 
1066
 
 
1067
                curDump->hostAddr = 0;
 
1068
                dparamsPtr->volumesNotDumped++;
 
1069
                break;
 
1070
 
 
1071
           default:
 
1072
                ErrorLog(1, taskId, dvcode, 0, "Volume %s (%u) failed\n",
 
1073
                         curDump->name, curDump->vid);
 
1074
                ERROR_EXIT(dvcode);
 
1075
                break;
 
1076
        }
 
1077
    } /*w*/
 
1078
 
 
1079
error_exit:
 
1080
    /* check if we terminated while processing a volume */
 
1081
    if (dparamsPtr->curVolume < nodePtr->arraySize)
 
1082
    {
 
1083
        TapeLog(2, taskId, 0, 0, "Terminated while processing Volume %s (%u)\n", 
 
1084
                curDump->name, curDump->vid);
 
1085
    }
 
1086
 
 
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));
 
1091
    return(code);
 
1092
}
 
1093
 
 
1094
Dumper(nodePtr)
 
1095
    struct dumpNode *nodePtr;
 
1096
{
 
1097
    struct dumpRock      dparams;
 
1098
    struct butm_tapeInfo tapeInfo;
 
1099
    int pass;
 
1100
    int action;
 
1101
    afs_int32 taskId;
 
1102
    afs_int32 code = 0;
 
1103
 
 
1104
    /* for volume setup */
 
1105
    struct tc_dumpDesc  *dumpDescPtr;
 
1106
    int    i;
 
1107
    int    failedvolumes = 0;
 
1108
    int    dumpedvolumes = 0;
 
1109
    int    nodumpvolumes = 0;
 
1110
    char   strlevel[5];
 
1111
    char   msg[20];
 
1112
    char   finishedMsg1[50];
 
1113
    char   finishedMsg2[50];
 
1114
    time_t startTime=0;
 
1115
    time_t endTime=0;
 
1116
    afs_int32  allocbufferSize;
 
1117
 
 
1118
    extern struct deviceSyncNode *deviceLatch;
 
1119
    extern struct tapeConfig     globalTapeConfig;
 
1120
    extern afs_int32 createDump();
 
1121
 
 
1122
    taskId = nodePtr->taskID;                              /* Get task Id */
 
1123
    setStatus(taskId, DRIVE_WAIT);
 
1124
    EnterDeviceQueue(deviceLatch);
 
1125
    clearStatus(taskId, DRIVE_WAIT);
 
1126
 
 
1127
    printf("\n\n");
 
1128
    TapeLog(2, taskId, 0, 0, "Dump %s\n", nodePtr->dumpSetName);
 
1129
 
 
1130
    /* setup the dump parameters */
 
1131
    memset(&dparams, 0, sizeof(dparams));
 
1132
    dparams.node = nodePtr;
 
1133
    dparams.tapeInfoPtr = &tapeInfo;
 
1134
    dlqInit(&savedEntries);
 
1135
 
 
1136
    if (!CONF_XBSA) {
 
1137
       /* Instantiate the tape module */
 
1138
       tapeInfo.structVersion = BUTM_MAJORVERSION;
 
1139
       code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
 
1140
       if (code) {
 
1141
          ErrorLog(0, taskId, code, tapeInfo.error, "Can't initialize the tape module\n");
 
1142
          ERROR_EXIT(code);
 
1143
       }
 
1144
    }
 
1145
 
 
1146
    /* check if abort requested while waiting on device latch */
 
1147
    if ( checkAbortByTaskId(taskId) ) 
 
1148
        ERROR_EXIT(TC_ABORTEDBYREQUEST);
 
1149
 
 
1150
    /* Are there volumes to dump */
 
1151
    if (nodePtr->arraySize == 0)
 
1152
    {
 
1153
        TLog(taskId, "Dump (%s), no volumes to dump\n", nodePtr->dumpSetName);
 
1154
        ERROR_EXIT(0);
 
1155
    }
 
1156
 
 
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.
 
1159
     */
 
1160
    if (CONF_XBSA) {
 
1161
       /* XBSA dumps have not header */
 
1162
       dataSize = BufferSize;
 
1163
       allocbufferSize = dataSize + sizeof(struct volumeHeader);
 
1164
    } else {
 
1165
       tapeblocks = BufferSize / BUTM_BLOCKSIZE;  /* # of 16K tapeblocks */
 
1166
       dataSize = (tapeblocks * BUTM_BLKSIZE);
 
1167
       allocbufferSize = BUTM_HDRSIZE + dataSize + sizeof(struct volumeHeader);
 
1168
    }
 
1169
    bufferBlock = (char *)0;
 
1170
    bufferBlock = malloc(allocbufferSize);
 
1171
    if (!bufferBlock) {
 
1172
        ErrorLog(0, taskId, TC_NOMEMORY, 0, "Can't allocate BUFFERSIZE for dumps\n");
 
1173
        ERROR_EXIT(TC_NOMEMORY);
 
1174
    }
 
1175
 
 
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.
 
1179
     */
 
1180
    sprintf(strlevel, "%d", nodePtr->level);
 
1181
    code = bcdb_FindLatestDump(nodePtr->volumeSetName, strlevel, &dparams.lastDump);
 
1182
    if (code) {
 
1183
       if (code != BUDB_NODUMPNAME) {
 
1184
          ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
 
1185
          ERROR_EXIT(code);
 
1186
       }
 
1187
       memset(&dparams.lastDump, 0, sizeof(dparams.lastDump));
 
1188
    }
 
1189
 
 
1190
    code = createDump(&dparams);                        /* enter dump into database */
 
1191
    if (code) 
 
1192
    {
 
1193
        ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
 
1194
        ERROR_EXIT(code);
 
1195
    }
 
1196
 
 
1197
    TLog(taskId, "Dump %s (DumpID %u)\n", nodePtr->dumpSetName, dparams.databaseDumpId);
 
1198
 
 
1199
    if (!CONF_XBSA) {
 
1200
       /* mount the tape and write its label */
 
1201
       code = getDumpTape(&dparams, autoQuery, nodePtr->doAppend);
 
1202
    } else {
 
1203
       /* Create a dummy tape to satisfy backup databae */
 
1204
       code = getXBSATape(&dparams);
 
1205
       tapeInfo.position = 1;
 
1206
    }
 
1207
    if (code) {
 
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);
 
1214
          else 
 
1215
             dparams.databaseDumpId = 0;
 
1216
       }
 
1217
       ERROR_EXIT(code);                        /* exit with code from getTape */
 
1218
    }
 
1219
        
 
1220
    startTime = time(0);
 
1221
    for (pass = 1; pass <= maxpass; pass++)
 
1222
    {
 
1223
        lastPass = (pass == maxpass);
 
1224
        code = dumpPass(&dparams, pass);
 
1225
        if (code) ERROR_EXIT(code);
 
1226
 
 
1227
        /* if no failed volumes, we're done */
 
1228
        if ((dparams.volumesDumped + dparams.volumesFailed + dparams.volumesNotDumped) == 
 
1229
            nodePtr->arraySize) break;
 
1230
    }
 
1231
 
 
1232
    /* 
 
1233
     * Log the error but ignore it since the dump is effectively done.
 
1234
     * Scantape may assume another volume and ask for next tape.
 
1235
     */
 
1236
    if (!CONF_XBSA) {
 
1237
       code = butm_WriteEOT(&tapeInfo);
 
1238
       if (code) TapeLog(taskId, code, tapeInfo.error, 
 
1239
                         "Warning: Can't write end-of-dump on tape\n");
 
1240
    }
 
1241
 
 
1242
    code = finishTape(&dparams.tape, dparams.tapeInfoPtr->kBytes + 
 
1243
                                    (dparams.tapeInfoPtr->nBytes ? 1 : 0));
 
1244
    if (code) ERROR_EXIT(code);
 
1245
 
 
1246
    code = finishDump(&dparams.dump);
 
1247
    if (code) ERROR_EXIT(code);
 
1248
 
 
1249
    action = dparams.curVolumeStatus;
 
1250
    code = flushSavedEntries(action);
 
1251
    if (code) ERROR_EXIT(code);
 
1252
 
 
1253
  error_exit:
 
1254
    endTime = time(0);
 
1255
    Bind(0);
 
1256
    if (bufferBlock) free(bufferBlock);
 
1257
 
 
1258
    if (!CONF_XBSA) {
 
1259
       unmountTape(taskId, &tapeInfo);
 
1260
    }
 
1261
    waitDbWatcher();
 
1262
 
 
1263
    dumpedvolumes = dparams.volumesDumped;
 
1264
    nodumpvolumes = dparams.volumesNotDumped;
 
1265
    failedvolumes = nodePtr->arraySize - (dumpedvolumes + nodumpvolumes);
 
1266
 
 
1267
    /* pass back the number of volumes we failed to dump */
 
1268
    lock_Status();
 
1269
    nodePtr->statusNodePtr->volsFailed = failedvolumes;
 
1270
    unlock_Status();
 
1271
 
 
1272
    lastPass = 1; /* In case we aborted */
 
1273
 
 
1274
    DUMPNAME(finishedMsg1, nodePtr->dumpSetName, dparams.databaseDumpId);
 
1275
    sprintf(finishedMsg2, "%d volumes dumped", dumpedvolumes);
 
1276
    if (failedvolumes)
 
1277
    {
 
1278
        sprintf(msg, ", %d failed", failedvolumes);
 
1279
        strcat(finishedMsg2, msg);
 
1280
    }
 
1281
    if (nodumpvolumes)
 
1282
    {
 
1283
        sprintf(msg, ", %d unchanged", nodumpvolumes);
 
1284
        strcat(finishedMsg2, msg);
 
1285
    }
 
1286
 
 
1287
    if (code == TC_ABORTEDBYREQUEST)
 
1288
    {
 
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);
 
1293
    }
 
1294
    else if (code)
 
1295
    {
 
1296
        ErrorLog(0, taskId, code, 0, 
 
1297
                 "%s: Finished with errors. %s\n", finishedMsg1, finishedMsg2);
 
1298
        setStatus(taskId, TASK_ERROR);
 
1299
    }
 
1300
    else
 
1301
    {
 
1302
        TLog(taskId, "%s: Finished. %s\n", finishedMsg1, finishedMsg2);
 
1303
    }
 
1304
    lastPass = 0;
 
1305
 
 
1306
    /* Record how long the dump took */
 
1307
    if (centralLogIO && startTime) {
 
1308
       long timediff;
 
1309
       afs_int32 hrs, min, sec, tmp;
 
1310
       char line[1024];
 
1311
       struct tm tmstart, tmend;
 
1312
 
 
1313
       localtime_r(&startTime, &tmstart);
 
1314
       localtime_r(&endTime, &tmend);
 
1315
       timediff = (int)endTime - (int)startTime;
 
1316
       hrs = timediff / 3600;
 
1317
       tmp = timediff % 3600;
 
1318
       min = tmp / 60;
 
1319
       sec = tmp % 60;
 
1320
 
 
1321
       sprintf(line, "%-5d  %02d/%02d/%04d %02d:%02d:%02d  "
 
1322
                           "%02d/%02d/%04d %02d:%02d:%02d  "
 
1323
                           "%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);
 
1332
 
 
1333
       fwrite(line, strlen(line), 1, centralLogIO);
 
1334
       fflush(centralLogIO);
 
1335
    }
 
1336
 
 
1337
    setStatus(taskId, TASK_DONE);
 
1338
 
 
1339
    FreeNode(taskId);                     /* free the dump node */
 
1340
    LeaveDeviceQueue(deviceLatch);
 
1341
    return(code);
 
1342
}
 
1343
 
 
1344
#define BELLTIME 60     /* 60 seconds before a bell rings */
 
1345
#define BELLCHAR 7      /* ascii for bell */
 
1346
 
 
1347
/* retryPrompt
 
1348
 *      prompt the user to decide how to handle a failed volume dump. The
 
1349
 *      volume parameters describe the volume that failed
 
1350
 * entry:
 
1351
 *      volumeName - name of volume
 
1352
 *      volumeId - volume id 
 
1353
 *      taskId - for job contrl
 
1354
 * fn return:
 
1355
 *      character typed by user, one of r, o or a
 
1356
 */
 
1357
 
 
1358
char
 
1359
retryPrompt(volumeName, volumeId, taskId)
 
1360
     char *volumeName;
 
1361
     afs_int32 volumeId;
 
1362
     afs_uint32 taskId;
 
1363
{
 
1364
    afs_int32 start;
 
1365
    char ch;
 
1366
    afs_int32 code = 0;
 
1367
 
 
1368
    setStatus(taskId, OPR_WAIT);
 
1369
    printf("\nDump of volume %s (%u) failed\n\n", volumeName, volumeId);
 
1370
 
 
1371
    printf("Please select action to be taken for this volume\n");
 
1372
 
 
1373
again:    
 
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");
 
1377
 
 
1378
    while (1) {
 
1379
        FFlushInput(stdin);
 
1380
        putchar(BELLCHAR);
 
1381
        fflush(stdout);
 
1382
 
 
1383
        start = time(0);
 
1384
        while(1) 
 
1385
        {
 
1386
#ifdef AFS_PTHREAD_ENV
 
1387
            code = GetResponseKey(5, &ch); /* ch stores key pressed */
 
1388
#else
 
1389
            code = LWP_GetResponseKey(5, &ch); /* ch stores key pressed */
 
1390
#endif
 
1391
            if (code == 1) 
 
1392
                break;                  /* input is available */
 
1393
 
 
1394
            if ( checkAbortByTaskId(taskId) )
 
1395
            {
 
1396
                clearStatus(taskId, OPR_WAIT);
 
1397
                printf("This tape operation has been aborted by the coordinator\n");
 
1398
                return 'a';
 
1399
            }
 
1400
 
 
1401
            if (time(0) > start + BELLTIME) break;
 
1402
        }
 
1403
        /* otherwise, we should beep again, check for abort and go back,
 
1404
         * since the GetResponseKey() timed out.
 
1405
         */
 
1406
        if (code == 1) 
 
1407
            break;                      /* input is available */
 
1408
    }
 
1409
    clearStatus(taskId, OPR_WAIT);
 
1410
    if ( ch != 'r' && ch != 'o' && ch != 'a' )
 
1411
    {
 
1412
        printf("Please select one of the 3 options, r, o or a\n");
 
1413
        goto again;
 
1414
    }
 
1415
 
 
1416
    return ch;
 
1417
}
 
1418
 
 
1419
/* For testing: it prints the tape label */
 
1420
printTapeLabel(tl)
 
1421
   struct butm_tapeLabel *tl;
 
1422
{
 
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);
 
1435
}
 
1436
 
 
1437
/* getXBSATape
 
1438
 *      Create a tape structure to be satisfy the backup database
 
1439
 *      even though we don't really use a tape with XBSA.
 
1440
 */
 
1441
getXBSATape(dparamsPtr)
 
1442
    struct dumpRock *dparamsPtr;
 
1443
{
 
1444
    struct dumpNode       *nodePtr      =  dparamsPtr->node;
 
1445
    struct butm_tapeInfo  *tapeInfoPtr  =  dparamsPtr->tapeInfoPtr;
 
1446
    struct butm_tapeLabel *tapeLabelPtr = &dparamsPtr->tapeLabel;
 
1447
    afs_int32 code = 0;
 
1448
 
 
1449
    tc_MakeTapeName(dparamsPtr->tapeName, &nodePtr->tapeSetDesc, dparamsPtr->tapeSeq);
 
1450
 
 
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,
 
1456
                                                      time(0));
 
1457
 
 
1458
    /* printTapeLabel(tapeLabelPtr); For testing */
 
1459
 
 
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*/);
 
1468
    return(code);
 
1469
}
 
1470
 
 
1471
/* getDumpTape
 
1472
 *      iterate until the desired tape (as specified by the dump structures)
 
1473
 *      is mounted.
 
1474
 * entry:
 
1475
 *      interactiveFlag
 
1476
 *              0 - assume the tape is there. Prompt if assumption false
 
1477
 *              1 - prompt regardless
 
1478
 */
 
1479
 
 
1480
getDumpTape(dparamsPtr, interactiveFlag, append)
 
1481
     struct dumpRock *dparamsPtr;
 
1482
     int interactiveFlag;
 
1483
     afs_int32 append;
 
1484
{
 
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;
 
1495
    afs_int32 curTime;
 
1496
    afs_int32 doAppend;
 
1497
    afs_int32 code = 0;
 
1498
    int   askForTape, opcode;
 
1499
    int   tapecount = 1;
 
1500
    char  strlevel[5];
 
1501
    afs_int32 tapepos, lastpos;
 
1502
 
 
1503
    extern struct tapeConfig globalTapeConfig;
 
1504
    extern struct udbHandleS udbHandle;
 
1505
    extern afs_int32 BUDB_DeleteDump();
 
1506
 
 
1507
    askForTape = interactiveFlag;
 
1508
    dparamsPtr->wroteLabel = 0;
 
1509
 
 
1510
    /* Keep prompting for a tape until we get it right */
 
1511
    while (1)
 
1512
    {
 
1513
        /* What the name of the tape would be if not appending to it */
 
1514
        tc_MakeTapeName(AFSTapeName, &nodePtr->tapeSetDesc, dparamsPtr->tapeSeq);
 
1515
 
 
1516
        doAppend = append;
 
1517
 
 
1518
        if (askForTape)
 
1519
        {
 
1520
            code = PromptForTape((doAppend ? APPENDOPCODE : WRITEOPCODE), 
 
1521
                                 AFSTapeName, dparamsPtr->databaseDumpId, taskId, tapecount);
 
1522
            if (code) ERROR_EXIT(code);
 
1523
        }
 
1524
        askForTape = 1;
 
1525
        tapecount++;
 
1526
 
 
1527
        /* open the tape device */
 
1528
        code = butm_Mount(tapeInfoPtr, AFSTapeName);
 
1529
        if (code)
 
1530
        {
 
1531
            TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
 
1532
            goto getNewTape;
 
1533
        }
 
1534
 
 
1535
        /* Read the tape label */
 
1536
        code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);   /* rewind */
 
1537
        if (code) {
 
1538
           if (tapeInfoPtr->error) {
 
1539
              ErrorLog(0, taskId, code, tapeInfoPtr->error, 
 
1540
                       "Warning: Tape error while reading label (will proceed with dump)\n");
 
1541
           }
 
1542
           memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
 
1543
        }
 
1544
 
 
1545
        /* Check if null tape. Prior 3.3, backup tapes have no dump id */
 
1546
        if ( (strcmp(oldTapeLabel.AFSName,"") == 0) && (oldTapeLabel.dumpid == 0) )
 
1547
        {
 
1548
            if (doAppend)
 
1549
            {
 
1550
                TLog(taskId, "Dump not found on tape. Proceeding with initial dump\n");
 
1551
                doAppend = 0;
 
1552
            }
 
1553
        }
 
1554
        else if (doAppend)                          /* appending */
 
1555
        {
 
1556
            /* Check that we don't have a database dump tape */
 
1557
            if ( databaseTape(oldTapeLabel.AFSName) )
 
1558
            {
 
1559
                char gotName[BU_MAXTAPELEN+32];
 
1560
 
 
1561
                /* label does not match */
 
1562
                LABELNAME(gotName, &oldTapeLabel);
 
1563
                TLog(taskId, "Can't append to database tape %s\n", gotName);
 
1564
                goto getNewTape;
 
1565
            }
 
1566
 
 
1567
            /* Verify that the tape is of version 4 (AFS 3.3) or greater */
 
1568
            if (oldTapeLabel.structVersion < TAPE_VERSION_4)
 
1569
            {
 
1570
                TLog(taskId, "Can't append: requires tape version %d or greater\n", 
 
1571
                     TAPE_VERSION_4);
 
1572
                goto getNewTape;
 
1573
            }
 
1574
 
 
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.
 
1577
             */
 
1578
            code = bcdb_FindLastTape(oldTapeLabel.dumpid, &dumpEntry, &tapeEntry, &volEntry);
 
1579
            if (code) {
 
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");
 
1584
               goto getNewTape;
 
1585
            }
 
1586
            lastpos = (volEntry.position ? volEntry.position : tapeEntry.labelpos);
 
1587
 
 
1588
            if (strcmp(TNAME(&oldTapeLabel),tapeEntry.name))
 
1589
            {
 
1590
                char expName[BU_MAXTAPELEN+32], gotName[BU_MAXTAPELEN+32];
 
1591
 
 
1592
                TAPENAME(expName, tapeEntry.name, oldTapeLabel.dumpid);
 
1593
                LABELNAME(gotName, &oldTapeLabel);
 
1594
 
 
1595
                TLog(taskId, 
 
1596
                     "Can't append: Last tape in dump-set is %s, label seen %s\n",
 
1597
                     expName, gotName);
 
1598
                goto getNewTape;
 
1599
            }
 
1600
 
 
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 */
 
1604
 
 
1605
            /* Position after last volume on the tape */
 
1606
            code = butm_SeekEODump(tapeInfoPtr, lastpos);
 
1607
            if (code) 
 
1608
            {
 
1609
                ErrorLog(0, taskId, code, tapeInfoPtr->error, 
 
1610
                         "Can't append: Can't position to end of dump on tape %s\n", 
 
1611
                         tapeEntry.name);
 
1612
                goto getNewTape;
 
1613
            }
 
1614
 
 
1615
            /* Track size of tape - set after seek since seek changes the value */
 
1616
            tapeInfoPtr->kBytes = tapeEntry.useKBytes;
 
1617
        }
 
1618
        else                         /* not appending */
 
1619
        {
 
1620
            afs_uint32 tapeid;
 
1621
            afs_uint32 dmp, parent;
 
1622
            struct budb_dumpEntry de, de2;
 
1623
 
 
1624
 
 
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.
 
1627
             */
 
1628
            if ( dump_namecheck && (strcmp(oldTapeLabel.pName,"")==0) )
 
1629
            {
 
1630
                if ( strcmp(oldTapeLabel.AFSName,"") &&             /* not null tape */
 
1631
                     strcmp(oldTapeLabel.AFSName,AFSTapeName) )     /* not expected name */
 
1632
                {
 
1633
                    TLog(taskId, "Tape label expected %s, label seen %s\n", 
 
1634
                         AFSTapeName, oldTapeLabel.AFSName);
 
1635
                    goto getNewTape;
 
1636
                }
 
1637
 
 
1638
                /* Check that we don't have a database dump tape */
 
1639
                if ( databaseTape(oldTapeLabel.AFSName) )
 
1640
                {
 
1641
                    /* label does not match */
 
1642
                    TLog(taskId, "Tape label expected %s, can't dump to database tape %s\n", 
 
1643
                         AFSTapeName, oldTapeLabel.AFSName);
 
1644
                    goto getNewTape;
 
1645
                }
 
1646
            }
 
1647
 
 
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");
 
1651
                goto getNewTape;
 
1652
            }
 
1653
 
 
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
 
1656
             */
 
1657
            if (oldTapeLabel.dumpid)
 
1658
            {
 
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)
 
1663
                {
 
1664
                    ErrorLog(0, taskId, 0, 0, 
 
1665
                             "Can't overwrite tape containing the dump in progress\n");
 
1666
                    goto getNewTape;
 
1667
                }
 
1668
            
 
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.
 
1671
                 */
 
1672
                for (dmp=nodePtr->parent; dmp; dmp=de.parent)
 
1673
                {
 
1674
                    code = bcdb_FindDumpByID(dmp, &de);
 
1675
                    if (code) {
 
1676
                        ErrorLog(0, taskId, 0, 0, 
 
1677
                                 "Warning: Can't find parent dump %u in backup database\n", 
 
1678
                                 dmp);
 
1679
                        break;
 
1680
                    }
 
1681
 
 
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",
 
1686
                                 de.name, de.id);
 
1687
                        goto getNewTape;
 
1688
                    }
 
1689
                }
 
1690
 
 
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.
 
1693
                 */
 
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));
 
1698
                    }
 
1699
                    else {
 
1700
                        code = bcdb_FindDumpByID(dmp, &de);
 
1701
                        if (code) break;
 
1702
                        sprintf(strlevel, "%d", de.level);
 
1703
                        code = bcdb_FindLatestDump(de.volumeSetName, strlevel, &de2);
 
1704
                        if (code) continue;
 
1705
                    }
 
1706
 
 
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",
 
1712
                                   de.name, de.id);
 
1713
                       }
 
1714
                       else {
 
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);
 
1718
                       }
 
1719
                    }
 
1720
                }
 
1721
            }       /* if (oldTapeLabel.dumpid) */
 
1722
        }           /* else not appending */
 
1723
        
 
1724
        /*
 
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.
 
1730
         */
 
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;
 
1737
 
 
1738
        if (!doAppend) {
 
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;
 
1745
            }
 
1746
        }
 
1747
 
 
1748
        /* write the label on the tape - rewind if not appending and vice-versa */
 
1749
        code = butm_Create(tapeInfoPtr, newTapeLabelPtr, !doAppend);
 
1750
        if (code)
 
1751
        {
 
1752
            char gotName[BU_MAXTAPELEN+32];
 
1753
 
 
1754
            LABELNAME(gotName, newTapeLabelPtr);
 
1755
            TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't label tape as %s\n", gotName);
 
1756
            goto getNewTape;
 
1757
        }
 
1758
        dparamsPtr->wroteLabel = 1;                   /* Remember we wrote the label */
 
1759
        tapepos = tapeInfoPtr->position-1;
 
1760
 
 
1761
        strcpy(dparamsPtr->tapeName, TNAME(newTapeLabelPtr));
 
1762
 
 
1763
        /* If appending, set dumpentry in the database as appended. */
 
1764
        if (doAppend)
 
1765
        {
 
1766
            char gotName[BU_MAXTAPELEN+32];
 
1767
 
 
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);
 
1772
 
 
1773
            code = bcdb_MakeDumpAppended(dparamsPtr->databaseDumpId, 
 
1774
                                         dparamsPtr->initialDumpId, nodePtr->tapeSetDesc.b);
 
1775
            if (code)
 
1776
                ErrorLog(2, taskId, code, 0,
 
1777
                         "Warning: Can't append dump %u to dump %u in database\n",
 
1778
                         dparamsPtr->databaseDumpId, dparamsPtr->initialDumpId);
 
1779
 
 
1780
            LABELNAME(gotName, &oldTapeLabel);
 
1781
            TLog(taskId, "Appending dump %s (DumpID %u) to tape %s\n",
 
1782
                 nodePtr->dumpSetName,  dparamsPtr->databaseDumpId, gotName);
 
1783
        }
 
1784
 
 
1785
        /* If not appending, delete overwritten dump from the database */
 
1786
        else
 
1787
        {
 
1788
            if ( (oldTapeLabel.structVersion >= TAPE_VERSION_3) && oldTapeLabel.dumpid )
 
1789
            {
 
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);
 
1795
            }
 
1796
        }
 
1797
 
 
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,
 
1805
                        tapepos);
 
1806
 
 
1807
        /*
 
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
 
1813
         * markers).
 
1814
         */
 
1815
        tc_EndMargin  = (3 * 16384 + 4 * globalTapeConfig.fileMarkSize) * 2;
 
1816
        tc_KEndMargin = tc_EndMargin / 1024;
 
1817
        break;
 
1818
 
 
1819
      getNewTape:
 
1820
        unmountTape(taskId, tapeInfoPtr);
 
1821
    }
 
1822
 
 
1823
error_exit:
 
1824
    return(code);
 
1825
}
 
1826
 
 
1827
makeVolumeHeader(vhptr, dparamsPtr, fragmentNumber)
 
1828
     struct volumeHeader *vhptr;
 
1829
     struct dumpRock *dparamsPtr;
 
1830
     int fragmentNumber;
 
1831
{
 
1832
    struct dumpNode *nodePtr = dparamsPtr->node;
 
1833
    struct tc_dumpDesc *curDump;
 
1834
    afs_int32 code = 0;
 
1835
 
 
1836
    curDump = &nodePtr->dumps[dparamsPtr->curVolume];
 
1837
 
 
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;
 
1846
    vhptr->contd = 0;
 
1847
    vhptr->magic = TC_VOLBEGINMAGIC;
 
1848
    vhptr->dumpID = dparamsPtr->databaseDumpId; /* real dump id */
 
1849
    vhptr->level = nodePtr->level;
 
1850
    vhptr->parentID = nodePtr->parent;
 
1851
    vhptr->endTime = 0;
 
1852
    vhptr->versionflags = CUR_TAPE_VERSION;
 
1853
    strcpy(vhptr->dumpSetName, nodePtr->dumpSetName);
 
1854
    strcpy(vhptr->preamble,"H++NAME#");
 
1855
    strcpy(vhptr->postamble,"T--NAME#");
 
1856
error_exit:
 
1857
    return (code);
 
1858
}
 
1859
 
 
1860
volumeHeader_hton(hostPtr, netPtr)
 
1861
     struct volumeHeader *hostPtr, *netPtr;
 
1862
{
 
1863
    struct volumeHeader volHdr;
 
1864
 
 
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);
 
1882
 
 
1883
    memcpy(netPtr, &volHdr, sizeof(struct volumeHeader));
 
1884
}
 
1885
 
 
1886
/* database related routines */
 
1887
 
 
1888
afs_int32
 
1889
createDump(dparamsPtr)
 
1890
     struct dumpRock *dparamsPtr;
 
1891
{
 
1892
    struct dumpNode *nodePtr = dparamsPtr->node;
 
1893
    struct budb_dumpEntry *dumpPtr;
 
1894
    afs_int32 code = 0;
 
1895
 
 
1896
    dumpPtr = &dparamsPtr->dump;
 
1897
    memset(dumpPtr, 0, sizeof(*dumpPtr));
 
1898
 
 
1899
    /* id filled in by database */
 
1900
    dumpPtr->parent = nodePtr->parent;
 
1901
    dumpPtr->level  = nodePtr->level;
 
1902
    dumpPtr->flags  = 0;
 
1903
#ifdef xbsa
 
1904
    if (CONF_XBSA) {
 
1905
       if (xbsaType == XBSA_SERVER_TYPE_ADSM) {
 
1906
          strcpy(dumpPtr->tapes.tapeServer, butxInfo.serverName);
 
1907
          dumpPtr->flags = BUDB_DUMP_ADSM;
 
1908
       }
 
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
 
1917
           * multiple servers.
 
1918
           */
 
1919
          dumpPtr->flags |= BUDB_DUMP_XBSA_NSS;
 
1920
       }
 
1921
    }
 
1922
#endif
 
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;
 
1930
 
 
1931
    dumpPtr->tapes.id       = groupId;
 
1932
    dumpPtr->tapes.b        = 1;
 
1933
    dumpPtr->tapes.maxTapes = 0;
 
1934
    strcpy(dumpPtr->tapes.format, nodePtr->tapeSetDesc.format);
 
1935
 
 
1936
    /* principal filled in by database */
 
1937
 
 
1938
    /* now call the database to create the entry */
 
1939
    code = bcdb_CreateDump(dumpPtr);
 
1940
    if (code == 0) dparamsPtr->databaseDumpId = dumpPtr->id;
 
1941
 
 
1942
    return(code);
 
1943
}
 
1944
 
 
1945
#ifdef xbsa
 
1946
/* InitToServer:
 
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
 
1949
 * as the server.
 
1950
 */
 
1951
afs_int32 InitToServer(afs_int32 taskId, struct butx_transactionInfo *butxInfoP, char *server)
 
1952
{
 
1953
   static char origserver[BSA_MAX_DESC];
 
1954
   static int  init=0;
 
1955
   afs_int32 rc, code=0;
 
1956
 
 
1957
   if (!init) {
 
1958
      strcpy(origserver,"");
 
1959
      init = 1;
 
1960
   }
 
1961
 
 
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 */
 
1966
 
 
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.
 
1970
       */
 
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);
 
1976
         return(TC_BADTASK);
 
1977
      }
 
1978
 
 
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);
 
1984
         ERROR_EXIT(rc);
 
1985
      }
 
1986
   }
 
1987
 
 
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",
 
1993
               server);
 
1994
      ERROR_EXIT(rc);
 
1995
   }
 
1996
 
 
1997
  error_exit:
 
1998
   return(code);
 
1999
}
 
2000
 
 
2001
 
 
2002
/* DeleteDump
 
2003
 *
 
2004
 */
 
2005
DeleteDump(ptr) 
 
2006
   struct deleteDumpIf *ptr;
 
2007
{
 
2008
    afs_int32 taskId;
 
2009
    afs_int32 rc, code=0;
 
2010
    afs_uint32 dumpid;
 
2011
    afs_int32 index, next, dbTime;
 
2012
    budb_volumeList vl;
 
2013
    struct budb_dumpEntry dumpEntry;
 
2014
    char tapeName[BU_MAXTAPELEN];
 
2015
    char dumpIdStr[XBSA_MAX_OSNAME];
 
2016
    char volumeNameStr[XBSA_MAX_PATHNAME];
 
2017
    afs_int32 i;
 
2018
    int intrans=0;
 
2019
    int allnotfound=1, onenotfound=0;
 
2020
    extern struct udbHandleS udbHandle;
 
2021
    extern struct deviceSyncNode *deviceLatch;
 
2022
 
 
2023
    setStatus(taskId, DRIVE_WAIT);
 
2024
    EnterDeviceQueue(deviceLatch);
 
2025
    clearStatus(taskId, DRIVE_WAIT);
 
2026
 
 
2027
    dumpid = ptr->dumpID;
 
2028
    taskId = ptr->taskId;                              /* Get task Id */
 
2029
 
 
2030
    printf("\n\n");
 
2031
    TapeLog(2, taskId, 0, 0, "Delete Dump %u\n", dumpid);
 
2032
 
 
2033
    vl.budb_volumeList_len = 0;
 
2034
    vl.budb_volumeList_val = 0;
 
2035
    tapeName[0] = '\0';
 
2036
 
 
2037
    /* Get the dump info for the dump we are deleting */
 
2038
    rc = bcdb_FindDumpByID(dumpid, &dumpEntry);
 
2039
    if (rc) {
 
2040
       ErrorLog(0, taskId, rc, 0, "Unable to locate dump ID %u in database\n", dumpid);
 
2041
       setStatus(taskId, TASK_ERROR);
 
2042
       ERROR_EXIT(rc);
 
2043
    }
 
2044
 
 
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.
 
2047
     */
 
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",
 
2052
                dumpid);
 
2053
       setStatus(taskId, TASK_ERROR);
 
2054
       ERROR_EXIT(TC_BADTASK);
 
2055
    }
 
2056
 
 
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)) {
 
2060
 
 
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.
 
2068
           */
 
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);
 
2073
       } else {
 
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);
 
2078
 
 
2079
          rc = InitToServer(taskId, &butxInfo, (char *)dumpEntry.tapes.tapeServer);
 
2080
          if (rc != XBSA_SUCCESS) {
 
2081
             setStatus(taskId, TASK_ERROR);
 
2082
             ERROR_EXIT(rc);
 
2083
          }
 
2084
       }
 
2085
    }
 
2086
 
 
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);
 
2092
       ERROR_EXIT(rc);
 
2093
    }
 
2094
    intrans = 1;
 
2095
 
 
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,
 
2100
                                   BUDB_OP_DUMPID,
 
2101
                                   tapeName, dumpid,
 
2102
                                   0,
 
2103
                                   index, &next,
 
2104
                                   &dbTime, &vl);
 
2105
       if (rc) {
 
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);
 
2109
          ERROR_EXIT(rc);
 
2110
       }             
 
2111
 
 
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);
 
2125
          }
 
2126
 
 
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) {
 
2134
               allnotfound = 0;
 
2135
               ERROR_EXIT(rc);
 
2136
             }
 
2137
             onenotfound = 1;
 
2138
          } else {
 
2139
             allnotfound = 0;
 
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);
 
2142
          }
 
2143
       }
 
2144
 
 
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;
 
2149
    }
 
2150
 
 
2151
  error_exit:
 
2152
    if (intrans) {
 
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);
 
2157
          ERROR_EXIT(rc);
 
2158
       }
 
2159
    }
 
2160
 
 
2161
    /* Switch back to the original server */
 
2162
    rc = InitToServer(taskId, &butxInfo, (char *)0);
 
2163
 
 
2164
    if (vl.budb_volumeList_val) free(vl.budb_volumeList_val);
 
2165
 
 
2166
    setStatus(taskId, TASK_DONE);
 
2167
    FreeNode(taskId);                     /* free the dump node */
 
2168
    LeaveDeviceQueue(deviceLatch);
 
2169
 
 
2170
    /* If we don't find any dumps on the server, rather than returning
 
2171
     * a success, return a failure.
 
2172
     */
 
2173
    if (!code && onenotfound && allnotfound) {
 
2174
       code = BUTX_DELETENOVOL;
 
2175
       setStatus(taskId, TASK_ERROR);
 
2176
    }
 
2177
    return(code);
 
2178
}
 
2179
#endif